Docs/Resonant/Architecture

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

  1. User sends a message — via web UI, Discord, or Telegram
  2. Hooks enrich the message — current time, conversation context, presence state, emotional markers are injected
  3. Agent SDK receives the enriched prompt — along with CLAUDE.md, conversation history, and any active MCP servers
  4. Claude processes and responds — streaming tokens back through WebSocket
  5. Tool calls are visualised — the frontend shows what tools the agent is using in real-time
  6. Response is stored — in SQLite with the full conversation thread
  7. 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.