URL: https://mkdocs.justinsforge.com/memory/general/reference_brain_server/
forge-brain-server¶
Persistent daemon that holds warm Claude Agent SDK clients (one CLI process per model) and serves bot brain calls over localhost HTTP, replacing per-call cold claude -p. Built 2026-06-09; plan with probe numbers at brain-latency-rewire-2026-06-09.
Pieces¶
| Piece | Path |
|---|---|
| Daemon | scripts/forge_brain_server.py |
| Venv | ~/.forge-venvs/brain-server/ (claude-agent-sdk 0.2.95, aiohttp) |
| Unit | forge-brain-server.service (system, repo copy infra/systemd/) |
| Stage-1 drop-in | infra/systemd/forge-inbox-capture.service.d/brain-engine.conf |
| Callers | forge_telegram_inbox_brain.py (brain_engine, call_brain_server, _call_sonnet), forge_telegram_brain.py (_call_sonnet_once) |
HTTP surface (127.0.0.1:8771)¶
GET /health->{ok, uptime_s, models: {model: stats}}POST /brain{prompt, model, persona, timeout_s}->{ok, raw, latency_ms, num_turns, duration_api_ms, usage}
Why it is fast (and safe)¶
- Skips the ~2s Node cold boot per call (warm CLI process,
ClaudeSDKClient.query(session_id=uuid)keeps calls stateless). max_turns=1: the oldclaude -ppath ran with default CLI tool access, and 53 of 247 audited calls burned a median 37s doing agentic CLI-tool work before emitting JSON. Capped turns remove that tail. Probe: warm calls flat 3.5-4.6s vs subprocess p90 59.7s.- Bills the subscription: no API key exists on Console; the SDK spawns
~/.local/bin/claudeand rides its OAuth.cli_pathis pinned because the SDK ships a bundled CLI that SIGILLs on Console (no AVX2, see console binary constraint topic).
Kill switch (FORGE_BRAIN_ENGINE)¶
Read at call time by the brain scripts; values: subprocess (default), server:capture (comma persona list), server (all). Any server error falls back to the subprocess path automatically, so sudo systemctl stop forge-brain-server degrades latency, never availability.
Full flip after soak:
sudo sed -i 's/server:capture/server/' /etc/systemd/system/forge-inbox-capture.service.d/brain-engine.conf
sudo mkdir -p /etc/systemd/system/forge-lifeos-coordinator.service.d
sudo cp /etc/systemd/system/forge-inbox-capture.service.d/brain-engine.conf /etc/systemd/system/forge-lifeos-coordinator.service.d/
sudo systemctl daemon-reload && sudo systemctl restart forge-inbox-capture forge-lifeos-coordinator
Revert: delete the drop-ins, daemon-reload, restart pollers.
Quota rows¶
Server-engine calls record real token counts: engine: server, num_turns, tokens: {input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens} flattened into the JSONL row alongside the legacy char fields (aggregator unchanged).
Ops notes¶
- One
asyncio.Lockper model client: requests queue rather than interleave (receive_response drains to the next ResultMessage; concurrent in-flight queries on one transport would cross-read). - Client recycles after 200 queries or any error/timeout (reconnect ~1s).
- Selftest:
~/.forge-venvs/brain-server/bin/python scripts/forge_brain_server.py --selftest - Health:
python3 -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8771/health').read().decode())"
[Claude Code, brain-latency session 2026-06-09]