Skip to content

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>.py with run() 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:

  1. Create codemol/app/<name>_manager.py
  2. Accept AppContext in __init__
  3. Instantiate in MolbotWindow.__init__() (after viewer/console creation)
  4. 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:

  1. Create codemol/<name>_panel.py as a QWidget subclass
  2. Use theme.py colors for consistent dark styling
  3. 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.