It's difficult to give advice, as it always depends on the programme itself and its purpose.
Personally, I would prefer variant 3. Old and proven programme style. In other words, the main load remains with the main programme as master. Regardless of this, the additional modules work, but only have intelligence for the job they are supposed to do. I would also not allow the additional modules to communicate with each other (apart from a few necessary exceptions perhaps). The main programme then polls the additional modules and retrieves the new data, updates the user interface, saves the data in a database, etc.
This may be a bit ‘oldschool’, but it makes troubleshooting and adding new add-on modules much easier later on. You remain more flexible in the long term.
Once the programme reaches a certain size, the whole construct may become confusing at some point, but this cannot be avoided. Good documentation in the source code is therefore really important.
In this way, I have created a programme that has grown more and more over the years and now contains 14 additional modules. In this case, however, they do not run simultaneously, but are switched on and off as required via the programme logic in the main.
In the course of developing the programme, however, I also reached the limits of the system. This concerns the layout, for example. If it is foreseeable that there will be many very different user interface views, then don't try to pack the code for this into a single designer script. Stay modular by programming a pane into which you then load the layout you need. Designer scripts are limited to a size of 64 kByte.
In the end, you are on your own. Don't take my tips as instructions or manuals, every programmer has it's own style of programming. That's why it's difficult to help you in making a decision.