Architecture
July 6, 2026 · View on GitHub
sources/agents ──▶ Ingest ──▶ Brain Loop ──┬─▶ 🔔 Interrupt (with a plan)
(webhook/MCP/built-ins) (triage→associate→decide) ├─▶ 🤖 Dispatch (verify, then report)
▲ └─▶ 📚 Curate (memory)
│ │
Scene Engine + Memory ◀─────────────────┘ (recalled by future events)
▲
Feedback loop (user reactions / dispatch results)
One resident process (chief run) = one async event loop + scheduled jobs.
Everything is local: SQLite (~/.chief/state.db), markdown policy
(~/.chief/POLICY.md), JSONL audit log.
The path of one event
- Ingest (
ingest/) — webhookPOST /v1/events, MCPpropose, or a built-in poller (GitHub notifications, RSS). Normalization stamps an id, fillsdedup_key, infers a missing topic. Sources never judge. - Triage (
core/brain.py) — 24h dedup; same-topic near-duplicates within 10 min merge into the earlier event. - Associate (
memory/) — top-3 memory hits by embedding cosine (> 0.78) are injected into the decision context and boost relevance ×1.2. - Decide (
core/scorer.py) — three stages, cheapest first:- Stage 1, hard rules (µs): muted topics, dedup, zero-information templates → drop; quiet hours (minus night whitelist) → digest; user rules in POLICY.md → direct route.
- Stage 2, similarity classifier (ms): looks-like-things-you-dismissed (>0.88, no engaged record) → drop; looks-like-things-you-engaged → route by history, no LLM call.
- Stage 3, LLM judge: pluggable backend scores five dimensions
(urgency, relevance, actionability, novelty, confidence);
score = Σ(w_topic·comp) − scene_cost, routed against the scene's interrupt threshold. Judge output also flagsdispatchableprep work andmemorizefacts.
- Act — interrupts deliver at the highest level the scene allows
(
delivery/: terminal < desktop < telegram silent < ring). Dispatchable work runs FIRST (dispatch/), is verified (acceptance command or LLM second opinion, retry once, then ask the human), and the result rides along as the plan. 10-minute dispatch timeout — delivery never blocks. - Learn (
core/learner.py) — button presses and dispatch results update per-topic EMA weights, engaged/dismissed sets, and a bounded global threshold. Nightly at 03:00 the day's changes distill into one human-readable POLICY.md line; memory TTL expiry runs in the same job.
Scene engine (context/)
Pluggable ContextProviders (clock, calendar today; focus/lock/activity
designed-in) merge signals; pure inference rules map them to one of 7 scenes
with a confidence. Confidence < 0.6 degrades interrupt → digest — the
asymmetry principle: a false interrupt costs more trust than a missed one.
Trust ladder
New installs start in shadow mode: interrupts degrade to annotated digest
entries with ✓/✗ grading until 7 days pass or 50 samples accumulate. chief report renders the Tact Report at any time.
Accountability layer (v3.1)
Judgment is a claim too, so v3.1 makes it inspectable end to end:
- Trace + cost — every Decision records per-stage latency, tokens
(cache-aware), and USD cost at per-model list prices (
judge/pricing.py);chief trace <event_id>replays the whole chain. The Tact Report adds %-events-reaching-the-LLM, cache hit rate, and spend for its window. - Eval harness (
eval/) — a 200-case golden dataset. CAPABILITY evals measure the judge and may move; REGRESSION evals (the demo 24) are pinned at 100% in CI.chief eval [--backend X]writes bucketed markdown reports. - Prompt governance — prompts are versioned Jinja2 templates
(
judge/templates/<v>/); the version is stamped into every audit record, andchief eval --compare v1 v2produces the flipped-samples diff that any prompt change must carry (CONTRIBUTING.md). - Graceful degradation — if the judge backend fails (malformed output,
timeout, down), routing falls back to rules-only conservatism: whatever
passes stage 1 goes to digest — never interrupt while blind, never drop —
flagged
degraded=true, auto-recovering, visible inchief status. chief lite— the same Brain against an in-memory state for one-shot judgment-only callers (what the Claude Code / OpenClaw skills invoke); zero-config safety comes from the degradation path, not a second pipeline.
Module map
| dir | role |
|---|---|
cli/ | typer CLI, wizard, resident-process assembly |
core/ | schema, state, brain loop, 3-stage scorer, learner, digest, policy |
context/ | scene providers + inference + scene policy table |
judge/ | LLM backends (ollama/deepseek/anthropic/openai/fixtures) + all prompts |
ingest/ | webhook + /v1/feedback + console /api, MCP server, normalization, github/rss pollers |
ingest/connectors/ | connector registry + composio adapter (500+ apps) |
dispatch/ | executors (claude_code, whitelisted shell, openclaw) + verification |
memory/ | memory store, TTL/archive, association |
delivery/ | level abstraction + terminal/desktop/telegram channels |
demo/ | offline day-of-engineer replay (the 60-second wow) |
eval/ | golden dataset, capability/regression runner, prompt compare, preference-learning reward loop |
ui/ | local web console (one static HTML file, served on 127.0.0.1) |
skills/ | claude-code + openclaw SKILL.md packaging (propose-and-obey) |