Skip to content

Architecture

Jason L. West edited this page Feb 10, 2026 · 3 revisions

Architecture

Nebulus Atom follows a strict MVC (Model-View-Controller) architecture with SOLID principles, dependency injection, and composition over inheritance.

System Architecture

┌─────────────────────────────────────────────────┐
│                   CLI Entry Point                │
│                  (Typer / main.py)                │
├─────────────────────────────────────────────────┤
│                                                   │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────┐ │
│  │   Models     │  │  Controllers │  │  Views  │ │
│  │             │  │              │  │         │ │
│  │ - Task      │  │ - Agent      │  │ - Rich  │ │
│  │ - Plan      │  │   Controller │  │   TUI   │ │
│  │ - Skill     │  │ - Turn       │  │ - Prompt│ │
│  │ - Journal   │  │   Processor  │  │ - Panel │ │
│  └─────────────┘  └──────┬───────┘  └─────────┘ │
│                          │                        │
│  ┌───────────────────────┴────────────────────┐  │
│  │                  Services                    │  │
│  │                                              │  │
│  │  ┌──────────┐ ┌──────────┐ ┌─────────────┐ │  │
│  │  │ OpenAI   │ │ RAG      │ │ Skill       │ │  │
│  │  │ Service  │ │ Service  │ │ Library     │ │  │
│  │  ├──────────┤ ├──────────┤ ├─────────────┤ │  │
│  │  │ Tool     │ │ Cognition│ │ Checkpoint  │ │  │
│  │  │ Registry │ │ Service  │ │ Service     │ │  │
│  │  ├──────────┤ ├──────────┤ ├─────────────┤ │  │
│  │  │ MCP      │ │ AST      │ │ Telemetry   │ │  │
│  │  │ Client   │ │ Service  │ │ Service     │ │  │
│  │  └──────────┘ └──────────┘ └─────────────┘ │  │
│  └─────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────┘
                        │
                        ▼
              ┌──────────────────┐
              │  Local LLM Server │
              │  (OpenAI API)     │
              └──────────────────┘

Directory Structure

nebulus_atom/
├── main.py                    # Typer CLI entry point
├── models/                    # Data structures (dataclasses/Pydantic)
│   ├── task.py               # Task and Plan models
│   ├── skill.py              # Skill definitions
│   └── journal.py            # Session journal entries
├── views/                     # UI rendering (Rich library)
│   ├── cli_view.py           # Terminal output formatting
│   └── tui/                  # Textual TUI components
├── controllers/               # Orchestration logic
│   ├── agent_controller.py   # Main agent loop (~200 lines)
│   └── turn_processor.py     # LLM turn processing
└── services/                  # Business logic and integrations
    ├── openai_service.py     # LLM client (streaming)
    ├── tool_registry.py      # Tool definitions and dedup
    ├── response_parser.py    # JSON/tool call extraction
    ├── context_manager.py    # File pinning
    ├── checkpoint_service.py # Smart undo snapshots
    ├── skill_library.py      # Persistent skills
    ├── rag_service.py        # Semantic code search
    ├── cognition_service.py  # Advanced reasoning
    ├── mcp_client.py         # Model Context Protocol
    ├── ast_service.py        # Code analysis
    ├── telemetry_service.py  # Event logging
    └── doc_service.py        # Embedded docs

Design Principles

SOLID

  • Single Responsibility: Each class has one job (e.g., ToolRegistry only manages tools)
  • Open/Closed: Services are extensible without modification
  • Liskov Substitution: Abstract base classes define interfaces
  • Interface Segregation: Small, focused interfaces
  • Dependency Inversion: Dependencies injected via __init__

Key Patterns

  • Composition over Inheritance: Services are composed, not subclassed
  • Dependency Injection: All dependencies passed through constructors
  • Encapsulation: Private members use _prefix, properties for access
  • Data Models: @dataclass or Pydantic, no raw dicts at boundaries

Agent Loop

The core agent loop follows this cycle:

User Input
    ↓
AgentController.chat_loop()
    ↓
Build system prompt + pinned context
    ↓
TurnProcessor.process()
    ├── Stream LLM response
    ├── Parse tool calls
    ├── Execute tools (file ops, commands, etc.)
    └── Append results to history
    ↓
Display response to user
    ↓
Loop (or auto-continue in autonomous mode)

Tool System

Tools are defined as OpenAI-compatible function schemas:

Tool Purpose
read_file Read file contents
write_file Create or overwrite files
edit_file Targeted edits within files
list_directory List directory contents
search_files Search for patterns in files
glob_files Find files by glob pattern
run_command Execute shell commands
create_checkpoint Save undo snapshot
undo_last_change Restore from checkpoint
pin_file / unpin_file Manage context

Additional tools come from the Skill Library and MCP servers.

Data Flow

User → CLI → AgentController → TurnProcessor → OpenAI Service → LLM Server
                                     ↓
                              Tool Execution
                                     ↓
                              File System / Shell

Swarm Architecture

Overlord Stack (Phases 1-3)

The Overlord meta-orchestrator is built in layers, each phase adding capabilities:

┌─────────────────────────────────────────────────────────────────┐
│                    Phase 3: Slack + Background                   │
│                                                                  │
│  ┌──────────────┐ ┌──────────────┐ ┌─────────────────────────┐ │
│  │ SlackCommand │ │  Proposal    │ │   OverlordDaemon        │ │
│  │ Router       │ │  Manager     │ │                         │ │
│  │              │ │              │ │ - Scheduler (croniter)  │ │
│  │ 9 commands   │ │ - Propose    │ │ - Signal handling       │ │
│  │ regex parse  │ │ - Approve    │ │ - Slack bot lifecycle   │ │
│  │ async bridge │ │ - Deny       │ │ - Cleanup loop          │ │
│  └──────┬───────┘ │ - Execute    │ └────────────┬────────────┘ │
│         │         │ - Expire     │              │              │
│         │         └──────┬───────┘              │              │
│  ┌──────┴───────┐ ┌──────┴───────┐ ┌───────────┴─────────┐   │
│  │ Detection    │ │ Notification │ │  Scheduled Tasks     │   │
│  │ Engine       │ │ Manager      │ │                      │   │
│  │              │ │              │ │  - scan (hourly)     │   │
│  │ - Stale      │ │ - Urgent     │ │  - test-all (nightly)│   │
│  │ - Ahead      │ │ - Buffered   │ │  - clean-branches    │   │
│  │ - Failing    │ │ - Digest     │ │    (weekly)          │   │
│  └──────────────┘ └──────────────┘ └──────────────────────┘   │
├─────────────────────────────────────────────────────────────────┤
│                    Phase 2: Dispatch + Autonomy                  │
│                                                                  │
│  ┌──────────────┐ ┌──────────────┐ ┌─────────────────────────┐ │
│  │ Autonomy     │ │ Dispatch     │ │  Model Router           │ │
│  │ Engine       │ │ Engine       │ │  (complexity → tier)    │ │
│  ├──────────────┤ ├──────────────┤ ├─────────────────────────┤ │
│  │ Task Parser  │ │ Release      │ │  E2E Integration        │ │
│  │ (NL → Plan)  │ │ Coordinator  │ │                         │ │
│  └──────────────┘ └──────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│                    Phase 1: Foundation                            │
│                                                                  │
│  ┌──────────────┐ ┌──────────────┐ ┌─────────────────────────┐ │
│  │ Registry     │ │ Scanner      │ │  Dependency Graph       │ │
│  │ (YAML config)│ │ (git/tests)  │ │  (DAG / Kahn's)        │ │
│  ├──────────────┤ ├──────────────┤ ├─────────────────────────┤ │
│  │ Action Scope │ │ Memory       │ │  CLI Commands           │ │
│  │ (blast radius│ │ (core shim)     │ │  (8 subcommands)       │ │
│  └──────────────┘ └──────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Phase 3 Data Flow

Slack @atom mention
    ↓
SlackBot (Socket Mode)
    ↓
SlackCommandRouter.handle()
    ├── status/scan/memory → asyncio.to_thread() → Phase 2 modules → response
    ├── merge/release → TaskParser → DispatchPlan → ProposalManager.propose()
    │                                                      ↓
    │                                                Slack thread post
    │                                                      ↓
    │                                              Thread reply (approve/deny)
    │                                                      ↓
    │                                              ProposalManager.handle_reply()
    │                                                      ↓
    │                                              DispatchEngine.execute()
    │                                                      ↓
    │                                              NotificationManager.accumulate()
    └── help → static response

OverlordDaemon (background)
    ├── _scheduler_loop() → croniter → _execute_scheduled_task()
    │       ├── scan → scan_ecosystem() → DetectionEngine.run_all()
    │       ├── test-all → scan_ecosystem() → report missing tests
    │       └── clean-stale-branches → scan_ecosystem() → report stale
    ├── _cleanup_loop() → ProposalManager.cleanup_expired()
    └── NotificationManager.send_digest() → daily summary

Async/Sync Bridge

Phase 2 modules are synchronous. Phase 3 Slack handlers are async. The bridge pattern:

# In SlackCommandRouter
result = await asyncio.to_thread(scan_ecosystem, self.config)

All Phase 2 calls (scan_ecosystem, TaskParser.parse, ReleaseCoordinator.execute, etc.) are wrapped in asyncio.to_thread() to avoid blocking the event loop.

Related Pages

Clone this wiki locally