Architecture
Resonant is a monorepo with three packages that form a full companion stack.
High-Level Overview
graph LR
subgraph Channels
WEB["Web UI<br/><i>SvelteKit</i>"]
DC["Discord"]
TG["Telegram"]
end
subgraph Backend["Express + WebSocket"]
ORCH["Orchestrator"]
HOOKS["Hooks"]
SESS["Sessions"]
end
subgraph Agent["Claude Agent SDK"]
CMD["CLAUDE.md"]
MCP["MCP Servers"]
TOOLS["Built-in Tools"]
end
WEB <--> Backend
DC --> Backend
TG --> Backend
Backend <--> Agent
style WEB fill:#3b0764,stroke:#4a4455,color:#e5e2e1
style DC fill:#1c1b1b,stroke:#4a4455,color:#e5e2e1
style TG fill:#1c1b1b,stroke:#4a4455,color:#e5e2e1
style ORCH fill:#0053db,stroke:#4a4455,color:#e5e2e1
style HOOKS fill:#0053db,stroke:#4a4455,color:#e5e2e1
style SESS fill:#0053db,stroke:#4a4455,color:#e5e2e1
style CMD fill:#8f4200,stroke:#4a4455,color:#e5e2e1
style MCP fill:#8f4200,stroke:#4a4455,color:#e5e2e1
style TOOLS fill:#8f4200,stroke:#4a4455,color:#e5e2e1
The companion runs as a Node.js server. Each interaction spawns a Claude Agent SDK query. Your companion’s personality lives in CLAUDE.md, its memory in a local SQLite database, and everything is configurable through resonant.yaml.
Package Structure
resonant/
├── packages/
│ ├── shared/ # Types + WebSocket protocol
│ ├── backend/ # Express + WS + Agent SDK + orchestrator
│ └── frontend/ # SvelteKit UI
├── tools/
│ └── sc.mjs # Agent CLI (the companion's built-in tools)
├── skills/ # Companion skills (SKILL.md format)
├── prompts/ # Wake prompts for autonomous sessions
└── scripts/
└── setup.mjs # Interactive setup wizard
packages/shared
Type definitions and the WebSocket protocol shared between frontend and backend. Message types, event definitions, and serialisation helpers.
packages/backend
The core of Resonant. Handles:
- Express server — HTTP API and static file serving
- WebSocket — real-time bidirectional communication with the frontend
- Agent SDK integration — spawns Claude Code queries, streams responses
- Session management — SQLite-backed conversation threads with daily rotation
- Orchestrator — autonomous scheduling, routines, pulse, triggers, timers, failsafe
- Hooks — context injection pipeline that enriches every message with time, conversation flow, emotional markers, and presence state
- Channel adapters — Discord, Telegram, push notifications
- Semantic search — local ONNX embeddings for meaning-based retrieval
packages/frontend
SvelteKit application that provides the web UI:
- Real-time streaming chat with interleaved tool visualisation
- Thread management (daily + named)
- Keyword search (Ctrl+K) and semantic search
- Canvas editor (markdown, code, text, HTML)
- Message reactions and reply-to
- Voice recording and playback
- Settings panel
- Themeable via CSS variables
Data Flow
Message Lifecycle
- User sends a message — via web UI, Discord, or Telegram
- Hooks enrich the message — current time, conversation context, presence state, emotional markers are injected
- Agent SDK receives the enriched prompt — along with
CLAUDE.md, conversation history, and any active MCP servers - Claude processes and responds — streaming tokens back through WebSocket
- Tool calls are visualised — the frontend shows what tools the agent is using in real-time
- Response is stored — in SQLite with the full conversation thread
- Memory processes — the daemon periodically reviews conversations for patterns and connections
Orchestrator Loop
The orchestrator runs independently of user interaction:
graph TD
SCHED["Scheduler<br/><i>cron</i>"] --> CHECK{"Routine due?"}
CHECK -->|Yes| WAKE["Spawn autonomous session<br/>with wake prompt"]
CHECK -->|No| WAIT["Wait"]
PULSE["Pulse<br/><i>periodic</i>"] --> EVAL{"Needs attention?"}
EVAL -->|Yes| ESC["Escalate to full session"]
EVAL -->|No| SILENT["Stay silent"]
TRIG["Triggers"] --> IMP["Impulse<br/><i>one-shot</i>"]
TRIG --> WATCH["Watcher<br/><i>recurring + cooldown</i>"]
TRIG --> FAIL["Failsafe<br/><i>tiered escalation</i>"]
style SCHED fill:#3b0764,stroke:#4a4455,color:#e5e2e1
style PULSE fill:#3b0764,stroke:#4a4455,color:#e5e2e1
style TRIG fill:#3b0764,stroke:#4a4455,color:#e5e2e1
style WAKE fill:#0053db,stroke:#4a4455,color:#e5e2e1
style ESC fill:#0053db,stroke:#4a4455,color:#e5e2e1
style IMP fill:#1c1b1b,stroke:#4a4455,color:#e5e2e1
style WATCH fill:#1c1b1b,stroke:#4a4455,color:#e5e2e1
style FAIL fill:#8f4200,stroke:#4a4455,color:#e5e2e1
The agent can create, modify, and delete orchestrator tasks from within a conversation using its built-in CLI tools. This is what makes Resonant’s autonomy “agent-directed” — the AI decides its own schedule.
Agent CLI Tools
The companion has a built-in CLI (tools/sc.mjs) that it uses to manage its environment. These commands are injected into the agent’s context and callable during any session:
sc routine create "evening journal" "0 22 * * *" --prompt "Reflect on the day"
sc pulse enable
sc pulse frequency 20
sc failsafe gentle 90
sc impulse create "greet" --condition presence_transition:offline:active
sc timer create "Meds" "context" "2026-03-26T14:00:00Z"
sc watch create "lunch" --condition routine_missing:meal:14 --cooldown 120
Also includes: reactions, voice messages, canvas, file sharing, and semantic search. See the full tools reference for all commands.
MCP Integration
Resonant supports connecting to any MCP server. Configure them in .mcp.json in your project root, and they’re available to the agent during every session.
This means you can connect Resonant Mind as a memory layer, add Cloud Discord for server management, or plug in any other MCP server your companion needs.