Files
Agentic-Bridle/docs/implementation-plan.md
wtclaude 06917d43e2 docs: add phased implementation plan and architecture decision records
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
2026-08-08 14:33:27 -05:00

9.2 KiB
Raw Permalink Blame History

Agentic Bridle — Phased Implementation Plan

Status: approved 2026-08-08 by Colby Whitlock (org lead) Source design: Agentic Bridle MCP Plan.md Decision records: docs/adr/

This document turns the design doc into an ordered, dependency-correct build plan. Every architectural decision it depends on is recorded as an ADR; this plan is the schedule, the ADRs are the reasoning.


Locked decisions

Area Decision ADR
Deployment One Rust binary (gateway, rules, memory, admin API, panel); Qdrant / Kanboard / Gitea MCP / embeddings as separate compose services, all traffic routed through the binary 0001
Transport Streamable HTTP only (/mcp) 0002
Auth Bridle-issued per-agent bearer tokens; clientInfo is a display hint, never a permission source 0003
Storage SQLite (bridle.db) 0004
Rule delivery get_rules tool, with hard gating — every other tool errors until get_rules succeeds in that session 0005
Rule scope Full rendered document, never a dynamic subset 0006
Multi-project project_id in schema and tool signatures from day one; single-project UX at 1.0 0007
enforcement tier Scoped to Bridle-mediated actions; bypass documented as a known limit 0008
Degradation Stable tool list always; downed upstreams return structured errors 0009
Embeddings Generic OpenAI-compatible endpoint; model + dimension recorded in collection metadata, mismatched writes refused 0010
Pattern RAG Gated behind a throwaway validation spike 0011
Renderers v1 CLAUDE.md + AGENTS.md (Codex); Kimi/DeepSeek dialects post-1.0 0012

Phase 0 — Foundations

Size: small

Cargo workspace, docs/adr/ populated, compose skeleton (bridle plus profiles for with-qdrant, with-kanboard, with-embeddings), Gitea CI on pull request, .env.example, Docker secrets wiring.

Exit criterion: docker compose up yields a health-checked binary that completes an MCP initialize over Streamable HTTP and advertises zero tools.

Phase 1 — Gateway core

Size: large

The security and accountability spine. Everything later assumes it exists.

  • Streamable HTTP MCP server; session lifecycle and per-session state, including the rules-fetched flag that phase 2's gate depends on.
  • Token auth → agent identity → permissions lookup. Token issuance, rotation, and revocation through the admin API.
  • SQLite schema carrying project_id throughout: projects, agents, tokens, permissions, audit_log.
  • Append-only audit log written from the first request, with source attribution (user / agent / vendor).
  • Docker-secrets loading, structured logging, per-request timeouts.
  • Admin API skeleton — the Web Panel's contract starts here so it is not written twice.

Exit criterion: two agents connect under distinct authenticated identities with different permission sets; a forged clientInfo changes nothing about what either may do; every call appears in the audit log correctly attributed.

Phase 2 — Rules server, renderers, gating

Size: large

The core thesis of the project.

  • Canonical schema v1 with schema_version and JSON Schema validation: guardrails, patterns, provenance, agent profiles, permissions.
  • Storage and full CRUD admin API.
  • get_rules(project_id, agent_type) plus the gate: any other tool call before it returns a structured error naming the required call.
  • CLAUDE.md and AGENTS.md renderers under golden-file tests. Renderer correctness is the deliverable of this phase, so it carries real test coverage.
  • Agent-proposal tools (propose_guardrail, add_pattern) writing to an approval queue. Nothing auto-applies.

Exit criterion: one edit in Bridle demonstrably changes behavior in a live Claude Code session and a live Codex session; a session that skips get_rules cannot use any tool.

Phase 3 — Upstream proxy and Gitea

Size: medium

  • Generic upstream-MCP client with connection pooling and health tracking.
  • Tool namespacing, stable across restarts (see open item 1).
  • Per-agent tool filtering driven by the phase-1 permissions table.
  • Credential injection per request; upstreams never hold their own tokens.
  • Failure isolation per ADR-0009.

Exit criterion: an agent completes a full Gitea PR workflow through Bridle while holding no Gitea token itself; killing the Gitea MCP container degrades only Gitea tools.

Phase 4 — Kanboard wrapper

Size: medium

Thin REST-to-MCP translation inside the binary. Validates both the author-our-own-upstream path and the bundled-versus-external compose story.

Exit criterion: task CRUD from an agent against a bundled Kanboard and against an external one, switched by environment variable alone.

Phase 5 — Session memory

Size: medium

Qdrant integration, pluggable embeddings with model/dimension guarding, <project>_sessions collections, remember and recall tools, retention and purge.

Exit criterion: a decision recorded by Claude Code is recalled by Codex in a later session; swapping embedding models is detected and refused rather than silently corrupting the collection.

Phase 5.5 — Pattern RAG spike

Size: small, throwaway

Index one real example repo with naive chunking, run roughly ten realistic queries, and judge whether the retrieved chunks would actually improve an agent's output. This is an explicit go/no-go gate on phase 6 — the spike code is discarded either way.

Exit criterion: a written go/no-go recommendation with the queries and retrieved chunks as evidence.

Phase 6 — Pattern-example RAG

Size: large — conditional on phase 5.5 passing

Repo fetch → tree-sitter AST-aware chunking → tagged upsert; search_pattern_examples(query, arch_tag?); refresh_pattern_example(reference_tag) with clean replacement of prior vectors.

Exit criterion: a named pattern's example repo is indexed and returns relevant code for a natural-language query; a refresh fully replaces prior vectors for that tag.

Phase 7 — Web Panel

Size: large

Served by the same binary. The admin API already exists from phases 16, so this phase is a client against it: approval queue, rules editor, secrets (write, rotate, revoke — never display), audit browser, memory browser, integration status.

Exit criterion: every phase 16 operation is achievable through the UI with no CLI or database access.

Phase 8 — Guardrail sourcing

Size: small

Manual paste-a-document flow producing proposed guardrails into the existing approval queue. Automated vendor-doc fetching only if the manual workflow proves its worth.

Exit criterion: a vendor guidance document becomes a reviewable proposal that requires explicit approval before entering the canonical ruleset.

Phase 9 — Multi-project, hardening, 1.0

Size: medium

Project switcher on the day-one schema, backup and restore, install documentation, packaging, release.

Exit criterion: a second person can stand up Bridle from the README against their own Gitea and reach a working agent session.


Cross-cutting

  • Security review on every phase that touches authentication or secrets.
  • Documentation written as features land, not retrofitted.
  • One ADR per architectural decision.
  • Golden-file and integration tests from phase 2 onward.

Deviations from the design doc's original 18 ordering

  • Audit log and multi-project schema moved to phase 1. Both are cheap to add upfront and expensive to retrofit across five subsystems.
  • Web Panel moved after memory, but its admin API is built incrementally from phase 1 rather than all at the end.
  • Vendor guardrail sourcing downgraded to manual-first. Scraping vendor documentation is fragile; the manual path captures most of the value at a fraction of the cost.
  • Pattern-example RAG gated behind a spike rather than committed to outright.

Open items

Not blocking phase 0. Sensible defaults noted where they exist.

  1. Tool namespacing convention. Proposed default: gitea__create_pr (double underscore). Effectively permanent once agents start depending on it.
  2. Audit log integrity. Plain append-only table, or hash-chained and tamper-evident?
  3. Approval queue notifications. Panel-only, or out-of-band webhook/email when an agent proposes a change?
  4. Web Panel stack. Server-rendered Rust templates versus an embedded SPA. Not blocking until phase 7.
  5. Kanboard instance and auth model. API user versus application token.
  6. CI. Gitea runner availability, and whether PR-gated CI starts at phase 0.
  7. Repository visibility and whether GPLv3 remains the license.