Adding Features¶
Decision Tree¶
When adding new functionality, determine the right approach:
graph TD
A[New Feature] --> B{User-invocable<br/>via command?}
B -->|Yes| C{Needs<br/>rendering cmd?}
C -->|Yes| D[Create a Tool]
C -->|No| E{Needs<br/>persistent state?}
E -->|Yes| F[Create a Manager]
E -->|No| D
B -->|No| G{UI component?}
G -->|Yes| H{Complex panel?}
H -->|Yes| I[Create a Panel/Sidebar]
H -->|No| J[Add to UIManager]
G -->|No| K{Keyboard-triggered?}
K -->|Yes| L[Add to keyPressEvent]
K -->|No| M[Add to relevant Manager]
Option 1: Create a Tool¶
When: The feature is a user command that calls the rendering engine or processes data.
See Adding a New Tool for the step-by-step guide.
Checklist:
- [ ] Create
tools/<group>/<name>.pywithrun()function - [ ] Support dry-run (
cmd is None) - [ ] Add docstring with usage/example
- [ ] Add shortcut to
expand_shortcut()(optional) - [ ] Add autocomplete entry to
build_command_list()(optional) - [ ] Verify tests pass
Option 2: Create a Manager¶
When: The feature needs persistent state, background workers, or complex lifecycle management.
Examples: AtlasManager (API integration), ShareManager (WebSocket sessions), AgentManager (LLM agents).
Steps:
- Create
codemol/app/<name>_manager.py - Accept
AppContextin__init__ - Instantiate in
MolbotWindow.__init__()(after viewer/console creation) - Connect signals as needed
class NewManager:
def __init__(self, ctx: AppContext):
self._ctx = ctx
def do_something(self):
result = self._ctx.tools # access tool registry
self._ctx.console.log("Done")
Option 3: Create a Panel/Sidebar¶
When: The feature needs a dedicated UI area (list, table, controls).
Examples: structure_sidebar.py, measurement_panel.py, docking_panel.py.
Steps:
- Create
codemol/<name>_panel.pyas aQWidgetsubclass - Use
theme.pycolors for consistent dark styling - Add to the window layout (usually via a manager)
Option 4: Add a Keyboard Shortcut¶
When: The feature should be triggered by a key combination.
Add to MolbotWindow.keyPressEvent():
def keyPressEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
if event.key() == Qt.Key_N:
self.do_new_thing()
General Guidelines¶
Start with a tool
Most features start as tools. If you later need state management, extract a manager. Don't create managers preemptively.
Keep MolbotWindow thin
The window is a mediator, not a repository for logic. Put domain logic in managers or tools.
Don't bypass the command system
Even if a feature is triggered by a button or shortcut, route through handle_command() when possible. This ensures the action is logged, shared in collaborative sessions, and available to the AI agent.