Turns the design doc into an ordered, dependency-correct build plan (phases 0-9) with an exit criterion per phase, and records the twelve architectural decisions it rests on as ADRs. Decisions: single Rust binary with routed compose services; Streamable HTTP only; per-agent bearer tokens with clientInfo as a display hint only; SQLite; get_rules delivered via session gating; full-document rule delivery; project_id from day one; enforcement tier scoped to Bridle-mediated actions; stable tool list on upstream failure; OpenAI-compatible embeddings with model/dim guarding; pattern RAG gated behind a spike; CLAUDE.md + AGENTS.md as v1 renderer targets. Deviates from the design doc's original 1-8 ordering by moving the audit log and multi-project schema into phase 1, building the admin API incrementally rather than all at the Web Panel phase, downgrading vendor guardrail sourcing to manual-first, and gating the pattern-example RAG behind a validation spike. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RZerbsHGF9Ka3bKhCjJ9m
1.5 KiB
ADR-0009: Stable tool list, structured errors on upstream failure
Status: Accepted (2026-08-08)
Context
Bridle proxies several upstreams — the Gitea MCP server, Kanboard, Qdrant — any of which can be
down while the others are healthy. The design doc did not specify what a connected agent sees in
that case. Options: keep the tool list stable and error on call; health-check upstreams and omit
their tools from tools/list, notifying via list_changed; or refuse to serve at all unless every
upstream is healthy.
Hiding tools avoids the agent calling something dead, but mutates the tool list mid-session, which some MCP clients cache or otherwise handle badly. Failing the whole session lets one flaky container block unrelated work.
Decision
The tool list stays stable for the whole session and always reflects the agent's permissions, not upstream liveness. A call to a downed upstream returns a clear structured error naming the upstream and the failure mode.
Consequences
- No mid-session tool-list churn, so no dependence on client
list_changedhandling. - A Qdrant outage does not block Gitea or Kanboard work — failure is isolated per upstream.
- Agents will occasionally call a tool that cannot currently succeed. The error must be specific enough that the agent reports the real cause rather than inventing a workaround.
- Upstream health is still tracked and surfaced in the Web Panel; it just does not alter the advertised tool list.