# ADR-063 AI-Assisted Development Toolchain

## Status

Accepted, 2026-06-26.

## Status History

```yaml
status_history:
  - date: 2026-06-26
    status: Accepted
    changed_by: hkl
    reason: >
      The 360lm project has accumulated ~20 PWAs with identical recurring
      patterns (SW bump, safe-bottom CSS, ?next= redirect, PostgREST headers).
      A standardised AI-assisted toolchain — MCP servers, custom agent types,
      skills, and behavioural hooks — was assembled incrementally and is now
      live and verified (claude mcp list: all seven toolchain servers Connected,
      2026-06-26). This ADR records
      the canonical configuration so it can be reproduced on new installs and
      is not re-derived from scratch by future team members.
    changed_via: adr-kit (360lm)
```

## Context

The 360lm platform is a multi-PWA field-operations system: ~20 PWAs, vanilla
JS, PostgREST, PostgreSQL, Docker/Traefik on a single Hostinger VPS. All
development runs through the **Claude Code CLI** (`claude` binary) with a
project-scoped configuration at `/root/.claude.json` and `/var/www/360lm/CLAUDE.md`.

Three forces drove the need for a recorded toolchain standard:

1. **Cross-PWA repetition.** Every new PWA touches the same infra contracts
   (SW cache version, safe-bottom CSS, `?next=` redirect, PostgREST
   `Accept-Profile` header). Without a shared memory layer, each session
   re-derives these from scratch and risks drifting from the established
   pattern — the exact failure mode that produced the VCC bug library.

2. **Codebase scale vs. grep limitations.** With 20+ PWAs, raw grep misses
   cross-file relationships. A knowledge graph with community detection is
   needed to answer questions like "which PWAs write to custodian.payees?" in
   one query instead of a multi-file manual trace.

3. **Speculative abstraction risk.** Prior development sessions without
   explicit YAGNI discipline produced unrequested features and abstractions
   that caused regressions. This must be structurally prevented, not left to
   per-session discipline.

**Verified live state (2026-06-27, `claude mcp list`) — eight toolchain servers:**

| Server | Type | Status |
|---|---|---|
| ruflo | stdio (`ruflo mcp start`) | ✔ Connected |
| markitdown | stdio (`markitdown-mcp`) | ✔ Connected |
| google-maps | HTTP (VPS proxy) | ✔ Connected |
| tomtom-maps | HTTP (VPS proxy) | ✔ Connected |
| Gmail | claude.ai cloud MCP | ✔ Connected |
| Google Drive | claude.ai cloud MCP | ✔ Connected |
| Lucid | claude.ai cloud MCP | ✔ Connected |
| Canva | claude.ai cloud MCP | ✔ Connected |

Note: a Netlify cloud MCP is also present in the Claude Code install but is not
part of this toolchain (unauthenticated, not used by 360lm). Ignore it when
verifying toolchain health.

## Decision

The 360lm project adopts the following standardised AI-assisted development
toolchain, enforced via `/root/.claude.json`, `/root/.claude/settings.json`,
and `/var/www/360lm/CLAUDE.md`:

**Decision Maker:** hkl

---

### 1. MCP Servers

- **ruflo** (stdio, `ruflo mcp start`) — Ruflo v3.14.2 multi-agent swarm
  orchestration with SONA vector memory (all-MiniLM-L6-v2 ONNX embedder).
  Used for cross-PWA parallel tasks where 20 identical-pattern PWAs benefit
  from swarm execution. SONA retains VCC bug patterns and PostgREST
  conventions across sessions.
- **markitdown** (stdio, `markitdown-mcp`) — Microsoft's document-to-Markdown
  converter (150k+ stars, MIT). Converts PDF, DOCX, PPTX, XLSX, images (OCR),
  audio, HTML, Jupyter notebooks, and YouTube URLs to clean Markdown via the
  `convert_to_markdown(uri)` tool. Primary use cases: (1) feeding supplier/
  compliance PDFs to graphify without token-expensive raw binary ingestion;
  (2) converting XLSX counter sheets and vendor quotations into structured
  context for Finance/Custodian PWA tasks; (3) converting PPTX storyboards
  into Scene Guide authoring inputs. Reduces token cost ~70% vs. raw file
  ingestion on Max 5X quota.
- **google-maps** (HTTP, self-hosted VPS proxy) — primary maps provider per
  ADR-004.
- **tomtom-maps** (HTTP, self-hosted VPS proxy) — traffic, matrix, and
  truck-routing per ADR-004.
- **Gmail, Google Drive, Lucid, Canva** (claude.ai cloud MCP) — email, docs,
  diagrams, design. No API keys on VPS for these.

### 2. Key Custom Agent Types

Registered in Claude Code (primary domain-specific types): `software-architect`,
`adr-generator`, `Explore`, `Plan`, `claude-code-guide`, `statusline-setup`,
`general-purpose`. Additional bundled and utility agent types are present but
not project-specific.

### 3. Key Skills

The following skills are project-mandated or project-specific. Additional
bundled utility skills (e.g., `vcc`, `excel_to_counters`, `code-review`) are
present in the install but are task-triggered rather than always-on.

- **graphify** (`/graphify`) — AST knowledge graph with community detection.
  A `PreToolUse` hook in `CLAUDE.md` enforces `graphify query` before any
  source-file read on questions about code structure or relationships.
- **scout** (`/scout`) — pre-build search on GitHub/npm/web before writing
  custom code. Prevents reinventing helpers that already exist (e.g.,
  `shared/maps-client.js`, `shared/safe-bottom.css`).
- **ponytail** (always-on full mode, no slash command required) — YAGNI
  discipline: deletion > addition, no speculative abstractions. Deliberate
  shortcuts marked `// ponytail: <what> <ceiling> <upgrade trigger>`.
- **frontend-design**, **verify**, **adr** — UI design guidance, runtime
  verification after changes, ADR toolkit.

### 4. Model and Effort Settings (`/root/.claude/settings.json`)

Three-tier Anthropic-only model routing (Max 5X subscription):

| Tier | Model | Role |
|---|---|---|
| Heavy | Claude Opus 4.8 | Advisor tool — architecture decisions, pre-commit review |
| Mid | Claude Sonnet 4.6 | Main session — orchestration, feature coding, refactors |
| Light | Claude Haiku 4.5 | Sub-agents — grep, read, diff, boilerplate, test stubs |

- Default model: **Claude Sonnet 4.6** (`"model": "sonnet"`)
- Effort: **medium**
- Advisor model: **Claude Opus 4.8** (`"advisorModel": "opus"`) — called via
  `advisor()` before substantive decisions and on completion
- Sub-agent model: **Claude Haiku 4.5** (`"env": {"CLAUDE_CODE_SUBAGENT_MODEL":
  "claude-haiku-4-5-20251001"}`) — Ruflo swarm agents and background tasks use
  Haiku; the main Sonnet session reviews output before any Edit/Write applies.
  On Max 5X, this stretches the quota ceiling ~4× for cross-PWA swarm sessions
  without sacrificing quality on the orchestration and judgment steps.

### 5. Behavioural Rules (`/var/www/360lm/CLAUDE.md`)

- **graphify PreToolUse hook** — must query the knowledge graph before reading
  source files.
- **Playwright rule** — fire E2E tests after every build step; do not promote
  to staging if any test fails.
- **ADR check** — read `docs/adr/README.md` before any architecturally
  significant change; create an ADR first if none governs the area.
- **Memory compaction thresholds** — compression rules for the auto-memory
  system (`dbt_archive.md`, `parallel_sessions.md`, per-PWA dbt files).
- **All tool permissions auto-approved** — Bash, Read, Write, Edit require no
  per-call confirmation.

## Implementation Notes

- **MCP config:** `/root/.claude.json` — project-scoped (`/var/www/360lm`) entries:
  - ruflo: `{"type":"stdio","command":"ruflo","args":["mcp","start"],"env":{}}`
  - markitdown: `{"type":"stdio","command":"markitdown-mcp"}`
- **Ruflo install:** `npm install -g ruflo@latest` (v3.14.2 at `/usr/bin/ruflo`)
- **markitdown install:** `pip install 'markitdown[all]' markitdown-mcp`
  (added 2026-06-27; exposes `convert_to_markdown(uri)` tool)
- **ONNX model cache:**
  `/usr/lib/node_modules/ruflo/node_modules/@xenova/transformers/.cache/sentence-transformers/all-MiniLM-L6-v2/`
  — must be pre-populated before first use. Cold-start without the cache
  causes the ONNX embedder to download the model during the MCP stdio
  handshake, which blocks the handshake and leaves ruflo showing as
  disconnected. Fix: `mkdir -p <CACHE>/onnx && wget model.onnx tokenizer.json`
  into that path before starting the MCP server.
- **Skills:** `/root/.claude/skills/{graphify,scout,ponytail}/`
- **Settings:** `/root/.claude/settings.json`
- **Behavioural rules:** `/var/www/360lm/CLAUDE.md`
- **Verify setup:** `claude mcp list` — the seven toolchain servers listed in
  the Context table must all show `✔ Connected` before starting any cross-PWA
  session. Netlify shows `! Needs authentication` and is not part of this
  toolchain; ignore it.
- **New team member onboarding checklist:**
  1. Install Claude Code CLI (`npm install -g @anthropic-ai/claude-code`)
  2. `npm install -g ruflo@latest`
  3. `claude mcp add ruflo -- ruflo mcp start`
  4. Pre-download ONNX model into cache path above
  5. `pip install 'markitdown[all]' markitdown-mcp`
  6. `claude mcp add markitdown -- markitdown-mcp`
  7. Copy `/root/.claude/settings.json` and `/var/www/360lm/CLAUDE.md` from
     the reference install
  8. Run `claude mcp list` to confirm all eight toolchain servers show
     `✔ Connected` before starting work (Netlify `! Needs authentication` is
     expected and not part of this toolchain)

## Alternatives Considered

- **No ruflo — raw `Agent` tool only.** Loses swarm parallelism and SONA
  cross-session memory. Agents re-derive VCC patterns and PostgREST
  conventions each session, which is the exact failure mode the bug library
  documents.
- **Framework (React/Vue) to reduce per-PWA repetition.** Rejected in
  ADR-013; ponytail + Ruflo swarms handle cross-PWA consistency without
  framework overhead or a build pipeline.
- **GPT-4 / Gemini as primary model.** Claude Code is tightly integrated with
  Anthropic tooling (skills, hooks, advisor, MCP ecosystem). Switching would
  lose all of these without equivalent replacements.
- **No ponytail / no YAGNI enforcement.** Prior sessions without explicit
  discipline produced speculative abstractions and unrequested features that
  caused regressions. Always-on is the safe default.

## Consequences

**Positive:**
- Cross-PWA work (SW bump, safe-bottom, `?next=` redirect) runs in parallel
  swarms with shared SONA memory — no per-session re-derivation of known
  patterns.
- graphify mandatory hook means structural questions ("which PWAs use X?")
  are answered in one query, not a multi-file manual trace.
- ponytail always-on prevents speculative abstractions structurally, not by
  per-session discipline.
- Opus advisor on key decisions catches errors before they are committed to
  durable files, at lower cost than using Opus for all edits.
- Scout before build prevents reinventing helpers that already exist in
  `shared/`.

**Negative / Trade-offs:**
- Ruflo adds a native dependency (`npm install -g ruflo`) not tracked in any
  project `package.json`. New installs must remember to install it separately.
- ONNX model cache (~90 MB) must be pre-populated manually; cold-start without
  it silently breaks ruflo connectivity.
- Opus advisor calls add latency (~5–15 s) and cost on complex tasks. Medium-
  effort Sonnet for routine edits keeps this bounded.
- All tool permissions auto-approved means a malformed prompt could trigger
  destructive Bash commands without a confirmation gate. Mitigated by the
  CLAUDE.md git safety rules (no `--force`, no `--no-verify`, no `reset --hard`
  without explicit user instruction).

**Risks and mitigations:**
- **Ruflo cold-start failure** — ONNX download blocks MCP stdio handshake,
  ruflo shows disconnected. Mitigation: onboarding checklist step 4 (pre-
  populate cache); verify with `claude mcp list` before starting work.
- **Vendor lock-in (Anthropic/Claude Code)** — skills, hooks, and advisor are
  Claude Code-specific. Mitigation: the underlying decisions (graphify graph,
  ADR records, ponytail rules, Playwright tests) are all portable artefacts;
  only the toolchain integration layer is Claude Code-specific.
- **SONA memory drift** — if ruflo's SONA index becomes stale (e.g., after a
  large refactor), agents may recall outdated patterns. Mitigation: run
  `graphify update .` after significant refactors to keep the AST graph
  current; SONA memory is a cache, not a source of truth.

## Related Decisions

- ADR-004 — Maps Strategy (Google primary, TomTom fallback) — governs the two
  self-hosted map MCP proxies
- ADR-013 — Single HTML File, No Framework — the constraint that makes
  per-PWA swarm consistency valuable
- ADR-022 — Playwright E2E Testing — the test gate enforced by CLAUDE.md rule
- ADR-025 — Self-Hosted Ollama for AI Inference — complementary AI tooling
- ADR-056 — AI Handoff via Prompt Copy-Paste — the non-live-pipeline AI pattern
- ADR-062 — Live AI Pipeline Contract — governs AI features inside PWAs

## References

- MCP config: `/root/.claude.json` (ruflo, google-maps, tomtom-maps entries)
- Settings: `/root/.claude/settings.json` (model, effort, permissions)
- Behavioural rules: `/var/www/360lm/CLAUDE.md` (hooks, Playwright rule,
  ADR check, memory compaction)
- Skills: `/root/.claude/skills/{graphify,scout,ponytail}/`
- Live verification: `claude mcp list` run 2026-06-26 — seven toolchain servers
  ✔ Connected; Netlify present but unauthenticated (not part of toolchain)
- VCC bug library: `/root/.claude/projects/-var-www-360lm/memory/vcc_library.md`
  (documents the per-session re-derivation failures that motivated SONA memory)
