# Architecture ## Tech Stack | Layer | Technology | |-------|------------| | Runtime | Bun (v1.0+) | | Language | TypeScript (strict mode) | | LLM Abstraction | Vercel AI SDK v6 | | Validation | Zod v4 | | CLI | Commander | | Colors | picocolors | | Formatting | oxfmt (single quotes) | | Linting | oxlint | ## Folder Structure ``` nanobot-ts/ ├── index.ts # Entry point ├── src/ │ ├── agent/ │ │ ├── loop.ts # AgentLoop: LLM ↔ tool execution loop │ │ ├── context.ts # ContextBuilder: system prompt assembly │ │ ├── memory.ts # MemoryConsolidator: token management │ │ ├── skills.ts # Skill loader from workspace │ │ ├── subagent.ts # SubagentManager: background tasks │ │ └── tools/ │ │ ├── base.ts # Tool interface + ToolRegistry │ │ ├── filesystem.ts # read_file, write_file, edit_file, list_dir │ │ ├── shell.ts # exec │ │ ├── web.ts # web_search, web_fetch │ │ ├── message.ts # message │ │ ├── spawn.ts # spawn │ │ └── cron.ts # cron │ ├── channels/ │ │ ├── base.ts # BaseChannel abstract class │ │ ├── mattermost.ts # Mattermost WebSocket + REST │ │ └── manager.ts # ChannelManager lifecycle │ ├── bus/ │ │ ├── types.ts # InboundMessage, OutboundMessage schemas │ │ └── queue.ts # AsyncQueue, MessageBus │ ├── provider/ │ │ ├── types.ts # LLMResponse, ToolCall, ChatOptions │ │ └── index.ts # LLMProvider (AI SDK wrapper) │ ├── session/ │ │ ├── types.ts # SessionMessage, SessionMeta schemas │ │ └── manager.ts # Session persistence (JSONL) │ ├── cron/ │ │ ├── types.ts # CronJob, CronSchedule schemas │ │ └── service.ts # CronService │ ├── heartbeat/ │ │ └── service.ts # HeartbeatService │ ├── config/ │ │ ├── types.ts # Zod config schemas │ │ └── loader.ts # loadConfig, env overrides │ └── cli/ │ └── commands.ts # gateway + agent commands ├── templates/ # Default workspace files │ ├── SOUL.md # Agent personality │ ├── USER.md # User preferences │ ├── TOOLS.md # Tool documentation │ ├── AGENTS.md # Agent behavior rules │ ├── HEARTBEAT.md # Periodic tasks │ └── memory/MEMORY.md # Long-term memory └── skills/ # Bundled skills ``` ## Data Flow ``` ┌─────────────────────────────────────────────────────────────────┐ │ Gateway Mode │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Mattermost ──► BaseChannel ──► MessageBus ──► AgentLoop │ │ ▲ │ │ │ │ │ ▼ ▼ │ │ │ OutboundQueue LLMProvider │ │ │ │ │ │ │ └───────────────────────────────┘ ▼ │ │ ToolRegistry │ │ │ │ │ ▼ │ │ Tool.execute() │ │ │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ Agent Mode │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ CLI stdin ──► processDirect() ──► AgentLoop ──► Response │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Key Components ### AgentLoop The core orchestrator. Consumes inbound messages, runs the LLM tool-calling loop, and publishes responses. 1. Receives `InboundMessage` from bus 2. Loads/creates session by key 3. Builds context (system prompt + history) 4. Calls LLM with tools 5. Executes tool calls, appends results 6. Repeats until no tool calls or max iterations 7. Saves session, publishes response ### MessageBus An async queue system for decoupling channels from the agent loop. - `publishInbound()` / `consumeInbound()`: messages from channels to agent - `publishOutbound()` / `consumeOutbound()`: responses from agent to channels ### LLMProvider Wraps Vercel AI SDK `generateText()` with: - Model string resolution (e.g., `openrouter/anthropic/claude-sonnet-4-5`) - Retry logic (3 attempts, exponential backoff) - Malformed JSON repair - Normalized `LLMResponse` type ### SessionManager Persists conversation history to JSONL files in `~/.nanobot/sessions/`. - Key format: `{channel}:{chatId}` (e.g., `mattermost:abc123`) - Supports history truncation for context window limits ### ToolRegistry Stores tools by name, provides OpenAI-compatible function definitions to the LLM. ### MemoryConsolidator When session history exceeds token limits, summarizes old messages and archives to `memory/MEMORY.md`. ## Configuration - File: `~/.nanobot/config.json` - Validation: Zod schemas in `src/config/types.ts` - Env overrides: `NANOBOT_MODEL`, `NANOBOT_WORKSPACE`, `NANOBOT_CONFIG` ## Session Key Convention | Channel | Key Format | Example | |---------|-----------|----------| | Mattermost | `mattermost:{channelId}` | `mattermost:abc123` | | Mattermost (thread) | `mattermost:{channelId}:{rootId}` | `mattermost:abc:def456` | | CLI | `cli:{chatId}` | `cli:interactive` | | System | `system:{source}` | `system:heartbeat` |