First half of brain#21: the applicability envelope — half_life (volatile| seasonal|durable), applies (local|homelab|universal), and claim_provenance (asserted|inferred). The strength half (confidence, contested) follows once the ingest-time contradiction detector exists to populate it. writeHallNote already passed unknown frontmatter keys through verbatim, so preservation was free — a test now pins it so a refactor of the merge loop cannot silently drop the fields. What was missing is validation, and it fails closed: - a value outside the enum is rejected. An unvalidated value is worse than an absent one, because a lint skips what it cannot parse and the note then reads as classified while nothing acts on it; - an envelope field without claim_provenance is rejected. A value a model inferred must never be indistinguishable from one Mathias asserted — otherwise a single classifier pass launders machine guesses into apparent human judgement across 1113 notes, which is precisely how a weak claim hardens into accepted fact; - provenance without any envelope field is rejected too: it says who set fields that are not there. Validation runs before MkdirAll, so a rejected write leaves nothing behind — not even an empty hall directory. The field is `applies`, not `scope`, as brain#19 proposed: `scope:` has been in use since brain#5 for glossary terms (homelab-core, project:<repo>), a disjoint value space on the same key. The shipped schema keeps the name. Notes with none of these fields are byte-identical to before. Bulk backfill across the corpus stays out of scope — the same failure mode as the extraction pass that produced 28 wrong wikilinks out of 67. Schema documented in brain/CLAUDE.md (via brain_edit_root, which produced the #97 audit record for the rewrite). Refs brain#21, brain#19 (superseded), brain#5, hyperguild#97.
hyperguild
An MCP server that acts as a disciplined AI supervisor for Claude Code sessions. Instead of letting Claude Code do whatever it wants, hyperguild enforces structured workflows (TDD red/green/refactor), logs every session, and accumulates learnings into a searchable brain.
This repo is also where brain-mcp lives — the MCP server at
brain-mcp.d-ma.be that brain_query, brain_write, brain_read, brain_edit
and capture are served from. It is not a separate deployable; see
Where brain-mcp lives.
Hypothesis
We believe routing skill tasks through local models, backed by brain context, produces measurably better outcomes than raw Claude Code alone — measurable by per-skill pass rate over rolling 30-day windows (available at
GET /pass-rate?skill=<name>&window=30don the brain pod).
This is the falsifiable claim the routing pod and pass-rate infrastructure exist to test. If per-skill pass rates don't improve over baseline (all-cloud) after 30 days of real usage, the fast-model routing path should be reconsidered.
Harness
hyperguild = Claude Code + MCP. This is a supervisor for Claude Code sessions specifically. For multi-agent orchestration (OpenCode + LiteLLM, executor/reviewer pipelines), see agentsquad — a separate harness for a different orchestration model. Skills (mathias/skills) are shared between both.
How it works
Your Claude Code session (in any project)
│
│ MCP over HTTP (Tailscale)
├──▶ routing :3210 (NodePort 30310 on koala) — review, debug, retrospective, trainer
└──▶ brain :3300 (NodePort 30330 on koala) — brain_query, brain_write, brain_ingest, session_log
│
└─ also serves the legacy REST endpoints (/query, /write, /ingest, …)
│
▼
brain/
├── sessions/ — JSONL log, one file per session_id
├── wiki/ — searchable knowledge (wing/hall layout)
│ ├── homelab/
│ ├── claude-sessions/
│ └── ...
└── knowledge/ — legacy flat notes (migration pending: hyperguild#22)
Where brain-mcp lives
brain-mcp is served from ingestion/internal/mcp in this repo, at
brain-mcp.d-ma.be. It is a component inside the ingestion service, not
a standalone deployable — one pod in the supervisor namespace serves the MCP
endpoint, the REST API, and the claudewatcher together.
| You are looking for | It is here |
|---|---|
The MCP tool surface (brain_query, brain_write, brain_read, brain_edit, capture, …) |
ingestion/internal/mcp |
The HTTP/REST API (/query, /write, /ingest) |
ingestion/internal/api |
| Session ingestion from Claude Code transcripts | ingestion/internal/claudewatcher |
| The brain content (notes, wings, halls) | mathias/brain — a separate repo |
| Deployment manifests | config/supervisor |
Why it is not its own repo
Asked and decided in #91
(part 2). internal/mcp imports 17 of ingestion's other internal packages and
has exactly one importer — it is the MCP facade over the service's own
internals, so "move it out" resolves to renaming ingestion, publishing 17
packages as a shared library, or maintaining a shim. The discoverability problem
that prompted the question is answered by naming it here instead.
Full reasoning, including the reversal trigger: brain
wiki/hyperguild/decisions/brain-mcp-stays-in-ingestion-fix-discoverability-by-name.
Phase 1 tools (available now)
| Tool | What it does |
|---|---|
session_log |
Appends a structured entry to the session JSONL log |
retrospective |
Reads the session log, identifies novel learnings, writes to brain |
review |
Structured code review via local model, brain-context injected |
debug |
Hypothesis-driven debugging via local model |
brain_query |
Full-text search over brain/wiki/ |
brain_write |
Writes a note to brain (with wing/hall routing) |
brain_answer |
BM25 + LLM synthesis — Q&A over brain corpus |
tier |
Returns the current connectivity tier (1=cloud, 2=LAN, 3=offline) |
Note:
tdd_red/green/refactorandspecwere retired in Plan 7 (2026-05-12). They are now SKILL.md files in mathias/skills.
Connect a project
Create .mcp.json in your project root:
{
"mcpServers": {
"routing": {
"type": "http",
"url": "http://koala:30310/mcp"
},
"brain": {
"type": "http",
"url": "http://koala:30330/mcp"
}
}
}
Two MCP servers are exposed, both reachable over Tailscale:
routingatkoala:30310— skill workers (review,debug,retrospective,trainer). Routes each call to fast local model or thinking model based on per-skill pass rate.brainatkoala:30330— knowledge access (brain_query,brain_write,brain_ingest,brain_ingest_raw,brain_answer,brain_classify) andsession_log.
No local binary or stdio shim is required — Claude Code talks to both via HTTP.
Open Claude Code in your project — run /mcp to confirm both servers are listed.
A typical session
1. Call review → brain context injected + local model review → findings
2. Call session_log → log each phase result
3. Call retrospective → extracts learnings → brain
4. Future sessions: call brain_query / brain_answer to retrieve relevant context
Tier detection
The routing pod probes connectivity at call time:
| Tier | Label | Condition |
|---|---|---|
| 1 | full-online | Can reach api.anthropic.com |
| 2 | lan-only | Can reach LiteLLM but not Anthropic |
| 3 | airplane | No external connectivity |
Model routing
The routing pod selects models per skill call based on historical pass rate:
| Pass rate | Decision |
|---|---|
| ≥ 0.90 (FLOOR) | Fast model (HYPERGUILD_FAST_MODEL) |
| ≤ 0.70 (CEIL) | Thinking model (HYPERGUILD_THINKING_MODEL) |
| between CEIL and FLOOR | Sample band — probabilistic routing |
| nil (no history yet) | Defaults to thinking model |
Bootstrap note: With no session history, all calls route to the thinking model. The fast-model path activates only after real pass-rate data accumulates at
/pass-rate. Seed with real usage — don't try to pre-populate.
Key env vars
| Variable | Default | Purpose |
|---|---|---|
INGEST_BRAIN_DIR |
../brain |
Brain directory for ingestion server |
INGEST_PORT |
3300 |
Ingestion server port |
INGEST_BASE_URL |
http://localhost:3300 |
Routing pod → brain |
LITELLM_BASE_URL |
— | LiteLLM proxy for Tier 2 model routing |
ROUTING_PORT |
3210 |
Routing pod's listen port |
ROUTING_MCP_TOKEN |
— | Optional bearer token; when empty, no auth enforced |
BRAIN_URL |
http://ingestion.supervisor:3300 |
Routing pod → brain (in-cluster) |
HYPERGUILD_FAST_MODEL |
koala/qwen35-9b-fast |
Fast model for high-pass-rate skill calls |
HYPERGUILD_THINKING_MODEL |
iguana/gemma4-26b |
Thinking model for low-pass-rate skill calls |
HYPERGUILD_ROUTE_LOCAL_FLOOR |
0.90 |
Fast model threshold |
HYPERGUILD_ROUTE_LOCAL_CEIL |
0.70 |
Thinking model threshold |
HYPERGUILD_PASS_RATE_TTL_SECONDS |
60 |
Per-skill pass-rate cache TTL |
Operator note: LiteLLM at
LITELLM_BASE_URLmust register bothHYPERGUILD_FAST_MODELandHYPERGUILD_THINKING_MODEL. If a model is missing, the fail-open retry also fails and the only signal isfinal_status: "fail"on_routingentries in the brain.
Open issues
See issues — key open items:
- #25 — skills platform overhaul (audit first, then lazy loading + brain feedback loop)
- #24 — reduce context burn from skill listing
- #22 — migrate legacy brain notes to wing/hall layout (one-shot script, low risk)
- #31 — connect routing-mcp to claude.ai as custom connector