-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Jason L. West edited this page Feb 10, 2026
·
3 revisions
Nebulus Atom follows a strict MVC (Model-View-Controller) architecture with SOLID principles, dependency injection, and composition over inheritance.
┌─────────────────────────────────────────────────┐
│ 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) │
└──────────────────┘
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
-
Single Responsibility: Each class has one job (e.g.,
ToolRegistryonly 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__
- 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:
@dataclassor Pydantic, no raw dicts at boundaries
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)
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.
User → CLI → AgentController → TurnProcessor → OpenAI Service → LLM Server
↓
Tool Execution
↓
File System / Shell
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) │ │
│ └──────────────┘ └──────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
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
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.
- CLI Reference - Command documentation
- Features - Feature details
- Nebulus Swarm - Multi-agent architecture
- Swarm Overlord - Overlord components and phases
- Overlord CLI - CLI and Slack command reference