Three-tier agent framework: Human ↔ Comms ↔ Daemon ↔ Orchestrator ↔ Workers
graph TB
Human["👤 Human\nTelegram · Email · Voice · Browser"]
subgraph CommsAgent["Comms Agent"]
ClaudeComms["Claude Code\n(persistent session + personality)"]
end
subgraph Daemon["Daemon"]
HTTP["HTTP API"]
DB["SQLite + Memory"]
Routing["Message & Channel Router"]
AgentMgr["Agent Lifecycle"]
Scheduler["Scheduler"]
end
subgraph Orchestrator["Orchestrator"]
ClaudeOrch["Claude Code\n(on-demand session)"]
end
Workers["Workers\nresearch · coding · testing"]
Peers["Peer Agents\nLAN direct · P2P relay"]
Human <-->|"channels"| Routing
CommsAgent <-->|"HTTP API"| HTTP
CommsAgent -->|"escalate"| HTTP
HTTP --- DB
HTTP --- Routing
HTTP --- AgentMgr
HTTP --- Scheduler
Routing -->|"inject"| CommsAgent
Routing -->|"inject"| Orchestrator
Orchestrator -->|"spawn"| AgentMgr
AgentMgr -->|"SDK"| Workers
Workers -->|"results"| Routing
CommsAgent <-->|"agent-comms"| Peers
Persistent tmux session "bmo". Full BMO personality from identity.md. Talks to human, delegates complex tasks to orchestrator. Never does multi-step implementation work.
Node.js HTTP server on localhost:3847. Owns SQLite DB (WAL). Routes messages, manages agent lifecycle, runs scheduler, handles channel delivery. Extension-based architecture.
On-demand tmux session "bmo-orch". Spawned via POST /api/orchestrator/escalate. Decomposes tasks, spawns workers, synthesizes results. Auto-kills after 15min idle.
Ephemeral Claude Code agents. Profiles: research (read-only), coding (implementation), testing (test runner). Spawned by orchestrator via SDK adapter. Results sent via message router.
graph TB
subgraph Server["HTTP Server (localhost:3847)"]
Router["Route Registry\n(registerRoute)"]
end
subgraph CoreAPI["Core API Routes"]
Health["/health, /status"]
AgentsAPI["/api/agents/*\n(spawn, list, kill)"]
OrchAPI["/api/orchestrator/*\n(escalate, status, shutdown)"]
MsgsAPI["/api/messages\n(inter-agent)"]
SendAPI["/api/send\n(channel delivery)"]
TodosAPI["/api/todos"]
CalendarAPI["/api/calendar"]
MemoryAPI["/api/memory/*\n(store, search)"]
TasksAPI["/api/tasks\n(scheduler control)"]
TimerAPI["/api/timer\n(self-timer alarms)"]
ConfigAPI["/api/config/reload"]
UsageAPI["/api/usage"]
ActivityAPI["/api/agents/:id/activity"]
end
subgraph ExtRoutes["Extension Routes (BMO)"]
TelegramWH["/telegram\n(webhook)"]
ShortcutRT["/shortcut"]
AgentP2P["/agent/p2p\n(A2A envelope)"]
AgentMsg["/agent/message"]
AgentSend["/agent/send"]
AgentStatus["/agent/status"]
ExtStatus["/agent/extended-status"]
CoworkAPI["/api/cowork/*\n(tabs, cdp, psk)"]
ContextAPI["/api/context"]
end
subgraph CoreModules["Core Modules"]
DB["SQLite\n(kithkit.db, WAL)"]
Logger["Logger\n(winston-style)"]
Config["Config Loader\n(YAML deep-merge)"]
Keychain["Keychain Reader\n(macOS security)"]
RouteReg["Route Registry"]
ExtReg["Extension Registry"]
end
subgraph AgentSys["Agent System"]
Lifecycle["lifecycle.ts\n(spawn/monitor/kill/queue)"]
SDKAdapter["sdk-adapter.ts\n(Claude SDK wrapper)"]
Profiles["profiles.ts\n(YAML frontmatter)"]
TmuxMgr["tmux.ts\n(session management)"]
MsgRouterMod["message-router.ts\n(dedup, inject, store)"]
end
subgraph MemSys["Memory System"]
KeywordSearch["Keyword Search\n(AND matching, relevance)"]
VectorSearch["Vector Search\n(MiniLM-L6-v2 ONNX)"]
HybridSearch["Hybrid Search\n(keyword + vector)"]
SQLiteVec["sqlite-vec\n(native extension)"]
end
Router --> CoreAPI
Router --> ExtRoutes
AgentsAPI --> Lifecycle
OrchAPI --> TmuxMgr
MsgsAPI --> MsgRouterMod
SendAPI --> ChanRouterMod["channel-router.ts"]
MemoryAPI --> KeywordSearch
MemoryAPI --> HybridSearch
Lifecycle --> SDKAdapter
Lifecycle --> Profiles
Lifecycle --> DB
MsgRouterMod --> TmuxMgr
MsgRouterMod --> DB
HybridSearch --> KeywordSearch
HybridSearch --> VectorSearch
VectorSearch --> SQLiteVec
Core routes handle agents, messages, todos, memory, scheduler. Extension routes (BMO) add Telegram webhook, agent-comms, cowork bridge, and more. Routes registered via registerRoute().
Workers: queued -> running -> completed/failed/timeout. Persistent agents: idle / busy. Max concurrent enforcement with FIFO queue. SDK adapter wraps Claude Code SDK for spawning.
Three search modes: keyword (AND matching, always available), vector (MiniLM-L6-v2 ONNX via sqlite-vec, requires enableVectorSearch()), hybrid (combines both scores).
Tables: agents, worker_jobs, memories, todos, todo_actions, calendar, messages, config, feature_state, task_results, migrations. WAL mode for concurrent reads.
Use the scrubber to step through the message flow one interaction at a time.
sequenceDiagram
participant H as Human (Dave)
participant TG as Telegram
participant D as Daemon
participant C as Comms Agent
participant O as Orchestrator
participant W as Worker
Note over H,W: Inbound: Human to Agent
H->>TG: Send message
TG->>D: POST /telegram (webhook)
D->>D: Access control check (5-tier)
D->>C: tmux send-keys (inject message)
C->>C: Process and respond
Note over H,W: Outbound: Agent to Human
C->>D: POST /api/send (message, channels: telegram)
D->>D: Channel router selects adapter
D->>TG: Telegram Bot API (sendMessage)
TG->>H: Deliver message
Note over H,W: Task Escalation Flow
C->>D: POST /api/orchestrator/escalate (task)
D->>D: Check if orchestrator alive
alt Orchestrator not running
D->>D: buildOrchestratorPrompt + memory injection
D->>O: spawnOrchestratorSession (tmux: bmo-orch)
end
D->>D: sendMessage(comms to orch, type task)
D->>O: tmux send-keys (inject task)
O->>O: Decompose task
Note over H,W: Worker Spawning
O->>D: POST /api/agents/spawn (profile, prompt)
D->>D: Load profile (.claude/agents/*.md)
D->>W: SDK spawn (Claude Code)
W->>W: Execute task
W->>D: POST /api/messages (type result)
D->>D: Store in SQLite and notify
D->>O: tmux send-keys (result notification)
Note over H,W: Result Delivery
O->>D: POST /api/messages (from orch, to comms, type result)
D->>C: tmux send-keys (inject result)
C->>D: POST /api/send (message, channels: telegram)
D->>TG: Telegram Bot API
TG->>H: Final result
sequenceDiagram
participant BMO as Agent A (localhost)
participant R2 as Peer Agent (LAN)
participant Relay as Relay (relay.bmobot.ai)
participant Remote as Remote Agent
Note over BMO,Remote: LAN: Direct Agent-to-Agent
BMO->>R2: POST /agent/message (Bearer token auth)
R2->>R2: Validate HMAC and process
R2->>BMO: POST /agent/message (response)
Note over BMO,Remote: Peer Heartbeat (interval)
BMO->>R2: POST /agent/status (agent, status)
R2->>BMO: 200 (agent, status, latencyMs)
Note over BMO,Remote: P2P: Via Network SDK
BMO->>Relay: WebSocket (register, heartbeat)
Remote->>Relay: Route envelope to BMO
Relay->>BMO: POST /agent/p2p (WireEnvelope)
BMO->>BMO: handleIncomingP2P()
graph LR
subgraph Core["Core Tasks (kithkit framework)"]
CW["context-watchdog\ninterval: 3m\nMonitors comms context usage"]
TR["todo-reminder\ninterval: 30m\nNudges on open todos"]
AA["approval-audit\ncron: biannual\nApproval review"]
BK["backup\ncron: Sun 03:00\nWeekly backup"]
OI["orchestrator-idle\ninterval: 2m\nKills idle orch (15min timeout)"]
MD["message-delivery\ninterval: 5s\nDelivers pending messages"]
CH["comms-heartbeat\ninterval: 60s\nChecks unacked workers/msgs"]
end
subgraph BMO["BMO Extension Tasks"]
EC["email-check\ninterval: 15m\nIMAP/Graph inbox scan"]
NT["nightly-todo\ncron: 22:00\nEnd-of-day todo review"]
HC["health-check\ncron: Mon 08:00\nWeekly system health"]
MC["memory-consolidation\ncron: 05:00\nDaily memory cleanup"]
MB["morning-briefing\ncron: 07:00\nDaily briefing"]
PH["peer-heartbeat\ninterval: 5m\nLAN peer status exchange"]
AD["a2a-digest\ncron: Mon 09:00\nWeekly A2A network digest"]
MS["memory-sync\ninterval: 30m\nCross-agent memory sync"]
LI["lindee-inbox-watch\ninterval: 15m\nEmail monitoring"]
SK["supabase-keep-alive\ncron: every 3 days\nPrevent free tier pause"]
BR["blog-reminder\ncron: Mon,Thu 14:00\nBlog writing nudge"]
WP["weekly-progress-report\ncron: Fri 16:00\nSend progress report"]
end
subgraph Engine["Scheduler Engine"]
Tick["Tick Loop (1s)"]
Cron["Cron Parser"]
Interval["Interval Tracker"]
Runner["Task Runner\n(in-process handlers\nor subprocess)"]
end
Tick --> Cron
Tick --> Interval
Cron --> Runner
Interval --> Runner
Runner --> Core
Runner --> BMO
graph TB
subgraph Extension["BMO Extension (extensions/index.ts)"]
onInit["onInit()"]
onShutdown["onShutdown()"]
end
subgraph Channels["Communication Channels"]
subgraph TGChan["Telegram"]
TGBot["Bot API\n(webhook: /telegram)"]
TGOwner["Owner Auth\n(chat ID allowlist)"]
TGAccess["5-tier Access Control"]
end
subgraph EmailChan["Email"]
Graph["Microsoft Graph"]
JMAP["Fastmail JMAP"]
Himalaya["Himalaya CLI (Gmail)"]
OutlookIMAP["Outlook IMAP"]
Triage["Email Triage\n(VIP, junk, newsletters,\nreceipts, auto-read)"]
end
subgraph VoiceChan["Voice"]
STT["Whisper-cpp (small.en)"]
TTS["Kokoro (am_adam)"]
Wake["OpenWakeWord\n(Hey BMO)"]
end
end
subgraph AgentNet["Agent Networking"]
subgraph LAN["LAN Comms"]
HB["Peer Heartbeat\n(5min interval)"]
HMAC["HMAC Auth\n(keychain secret)"]
R2Peer["Peer Agent\n(LAN discovery)"]
end
subgraph P2P["P2P Network"]
SDK["A2A SDK"]
RelayWS["Relay: relay.bmobot.ai"]
Endpoint["Endpoint: bmo.bmobot.ai/agent/p2p"]
end
end
subgraph Cowork["Cowork Bridge"]
WS["WebSocket Server\n(ws library, /cowork)"]
Auth["Token Auth\n(5s timeout)"]
KeyEx["ECDH Key Exchange\n(X25519 + PSK)"]
E2E["E2E Encryption\n(AES-256-GCM + seq numbers)"]
CDP["Chrome DevTools Protocol\n(tab control, JS eval)"]
end
onInit --> TGChan
onInit --> EmailChan
onInit --> VoiceChan
onInit --> LAN
onInit --> P2P
onInit --> Cowork