AI-assisted authoring โ via MCP, not via perch¶
The architecture: perch ships zero LLM client code. AI-assisted authoring happens in the agent's host (Claude Desktop, Cursor, Zed, custom MCP client) using perch-mcp as the workspace. The agent brings its own AI access; perch provides the file operations, validation, and analysis.
This is the design report for AI-assisted .perch authoring. An earlier draft of this doc proposed baking LLM client adapters into perch itself; that was the wrong shape. The right one is agent โ MCP โ perch. perch never holds an API key, never makes an outbound LLM call, never embeds a provider SDK. The agent already has all of those; the agent's user already trusts it; perch's role is the workspace, not the AI.
1. Why MCP and not a baked-in AI client¶
Four reasons:
-
The trust boundary already exists. The user installed Claude Desktop / Cursor / Zed. They already gave that app their API key. They already accepted that app sending data to a model. Adding a second trust boundary (in perch) duplicates the audit surface without adding capability.
-
The AI is the agent's responsibility, not the tool's. This is the same logic that makes
gitbetter off NOT shipping an LLM client. The agent callsgit; the agent reasons about diffs; the agent's host owns the model access. Same here. -
MCP is exactly the integration shape for this. Model Context Protocol exists so an agent can call tools and read resources in a structured, sandboxable way.
perch-mcpalready exposesperch_listandperch_runfor execution. Addingperch_read_file,perch_write_draft,perch_check,perch_scan,perch_presentextends the same surface for authoring. -
Zero LLM code in perch keeps the security story clean. A
perchbinary that never makes outbound HTTP to an LLM provider is much easier to reason about than one with a provider adapter and a configurable system prompt.--no-networkactually means no network.
2. The architecture¶
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ User โ
โ โโโ โ
โ "Back up postgres โ
โ weekly to S3" โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ types in
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ LLM provider
โ Claude Desktop / โโโโโโโโโโโโโโโโโโโบ (Anthropic / OpenAI / Ollama)
โ Cursor / Zed / โ agent's
โ any MCP client โ existing
โ โ AI access
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ MCP JSON-RPC over stdio
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ perch-mcp โ
โ โโโ โ
โ Tools: โ
โ perch_list / _run โ โ execution (already shipped)
โ perch_read_file โ โ authoring (new)
โ perch_write_draft โ
โ perch_diff โ
โ perch_apply_draft โ
โ perch_check โ
โ perch_scan โ
โ perch_present โ
โ Resources: โ
โ perch://skill โ โ skills/perch/SKILL.md
โ perch://op-catalog โ โ docs/op-reference.md
โ perch://file/<path> โ โ current .perch source
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ in-process Go calls
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ perch core โ
โ โโโ โ
โ capyloader โ
โ interpreter โ
โ ops registry โ
โ scan analyzer โ
โ validate โ
โ (no LLM code anywhere) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
perch never sees a model, an API key, or an HTTP request to an LLM provider. The agent does all of that on its own. perch-mcp is the bridge โ it lets the agent read, draft, validate, analyze, and commit changes to a .perch file, using the same Go libraries that power the CLI.
3. The agent's flow (concretely)¶
User types into Claude Desktop's chat:
"Add a command that backs up our postgres database to S3 every week."
The agent's host invokes its model with all of the user's chat history plus MCP tool definitions. The model decides to:
- Read the workspace โ calls
perch_read_fileto get the currentcommands.perch. The MCP server returns the source. - Read the authoring guide โ fetches the
perch://skillresource. The MCP server returnsskills/perch/SKILL.md. - Read the op catalog โ fetches
perch://op-catalog. Now the model has SKILL.md + every op in scope. - Compose โ using its host's LLM, the model generates a
command backup_postgres โฆ endblock. - Validate as it goes โ calls
perch_write_draftto put the proposal intocommands.perch.draft, thenperch_checkto verify it parses. Ifperch_checkreturns errors, the model iterates. - Analyse โ calls
perch_scanon the draft. Returns the needs-{shell, network, write} report + risk findings. - Show the user โ the agent presents the generated command + the scan analysis + a diff vs. the live file, all in the agent's chat UI, not in perch.
- Wait for approval โ the user clicks the agent's "Apply" button (whatever Claude Desktop / Cursor calls it).
- Commit โ the agent calls
perch_apply_draft. The MCP server atomically renames.draftโ.perchand signals the change.
perch's role across all 9 steps: read files, run analyzers, hold a .draft until told to commit. No LLM. No keys. No prompts. It's a workspace, not an AI.
4. The new MCP tools โ minimal surface¶
Five new tools on top of the existing perch_list / perch_run. Each is a thin wrapper around an existing Go function:
| Tool | Wraps | Purpose |
|---|---|---|
perch_read_file |
os.ReadFile |
Return the current .perch source so the agent has context |
perch_write_draft |
os.WriteFile to *.draft |
Propose a change without touching the live file |
perch_check |
usecases/validate |
Run --check against the live file or a draft |
perch_scan |
usecases/scan |
Run --scan against the live file or a draft |
perch_present |
usecases/scan + per-command help |
Plain-English summary of every command |
perch_diff |
golang.org/x/tools/internal/diff (or stdlib) |
Server-rendered diff between live and draft |
perch_apply_draft |
os.Rename of .draft โ .perch |
Commit after user approval |
That's it. Each tool has a JSON schema; the agent's host generates the schema as it does for any MCP server. The reuse of existing Go code (validate, scan) means no logic is duplicated โ the agent sees exactly what perch --check and perch --scan see at the CLI.
Plus MCP resources (read-only, content addressable)¶
| Resource URI | Returns |
|---|---|
perch://skill |
skills/perch/SKILL.md โ the authoring guide |
perch://op-catalog |
docs/op-reference.md โ every built-in op |
perch://language |
docs/language.md โ the grammar reference |
perch://file/<path> |
The named .perch file's source |
Resources are the MCP-native way to hand "background context" to a model. They cost the agent zero per-request bandwidth once cached and they let the agent load the right docs as needed rather than having SKILL.md inflated into every system prompt.
5. What changes inside perch-mcp¶
The existing cmd/perch-mcp/ binary already handles MCP framing (JSON-RPC over stdio, content-length framed). It currently registers two tools. We add the seven above + four resources. Everything else stays the same.
Concrete code shape:
cmd/perch-mcp/
main.go unchanged โ wiring
tools/
list.go existing โ perch_list
run.go existing โ perch_run
read_file.go NEW
write_draft.go NEW
check.go NEW (calls usecases/validate)
scan.go NEW (calls usecases/scan)
present.go NEW (renders the scan + per-command help into prose)
diff.go NEW
apply_draft.go NEW
resources/
skill.go NEW (returns embedded skills/perch/SKILL.md)
ops.go NEW (returns embedded docs/op-reference.md)
language.go NEW (returns embedded docs/language.md)
file.go NEW (reads requested .perch from disk)
Estimated ~600 LOC. About a day-and-a-half of focused work.
Safety invariants enforced by the server¶
The MCP layer enforces a few things the agent can't bypass even if it wants to:
- No execution from authoring tools.
perch_write_draftwrites to*.draftonly.perch_apply_draftis the only path to the live file, and it explicitly checks the draft--check-passes before renaming. - The agent can read its workspace, not the whole disk.
perch_read_fileandperch://file/<path>reject paths outside the workspace root (configurable viaperch-mcp --workspace DIR, default = cwd). - No new running of perch commands during authoring.
perch_runexists, but the agent should not call it on a freshly-authored command without the user explicitly asking. We can't enforce that in code, but we can document it as a sharp edge for any MCP-client author reading our docs.
6. What happens on the user's screen¶
Two real workflows the design supports:
6.1 Claude Desktop user¶
- User runs Claude Desktop with
perch-mcpconfigured inclaude_desktop_config.json. - User opens a chat: "Add a command to back up postgres weekly."
- Claude (the assistant inside Claude Desktop) does the 9-step flow in ยง3.
- Claude shows the user the generated command + the scan analysis + the diff in the chat. This is the Claude Desktop UI doing its native job โ perch isn't involved in rendering.
- User clicks "Approve" (Claude Desktop's UI element). Claude calls
perch_apply_draft. Done.
6.2 perch --server user, wanting AI assistance¶
This is the case from the earlier (now-superseded) draft. The right answer here is:
Recommend Claude Desktop running alongside perch --server.
The user has two windows open: Claude Desktop for chat + AI, perch's web UI for clicking buttons to run commands. Both connect to perch-mcp; both see the same .perch file; changes Claude makes appear in perch's web UI on the next refresh. The user gets:
- A polished chat UI for prompting (Claude Desktop's job)
- A polished command-runner UI for invoking (
perch --server's job) - Synchronisation through the file (which is where state belongs)
What we explicitly do NOT do: embed a chat panel inside perch --server. That would require perch to take on LLM client code, key management, provider adapters โ exactly the design we just rejected.
If a user wants a single-window AI experience in their browser, the right path is for Claude Desktop / similar to ship a web UI mode, or for someone to build a thin web-MCP-bridge that puts a chat panel in front of any MCP server. That's a separate project; not perch's concern.
7. What this saves us¶
Compared to the discarded "AI in perch" design:
| Concern | Earlier design | This design |
|---|---|---|
| LLM provider adapters in perch | 3โ4 (Anthropic / OpenAI / Ollama / LM Studio) | 0 |
| API key handling in perch | required (ai.toml + env var refs) | none โ agent owns it |
| System prompt embedded in perch binary | yes (SKILL.md) | exposed as an MCP resource โ agent reads when needed |
| Streaming SSE endpoint in perch's web UI | yes (/api/ai/compose) |
none โ agent has its own chat UI |
| Outbound HTTP from perch to LLM provider | yes | none โ --no-network actually means no network |
New panel UI in server.html |
substantial | none |
New use case in usecases/ |
aiconfig + provider wiring |
none |
| Per-user opt-in mechanism | ~/.config/perch/ai.toml |
none โ the agent's already-configured |
| LOC of new code | ~1,500 | ~600 (just MCP tools + resources) |
| Trust-boundary additions | one (perch โ LLM) | zero |
The MCP design is strictly less code, strictly less trust surface, strictly more aligned with existing protocols.
8. Implementation plan¶
Phase 1 โ Authoring tools (1.5 days)¶
perch_read_filetoolperch_write_drafttool (with workspace-root check)perch_checktool (wrapsusecases/validate)perch_difftool (server-rendered)perch_apply_drafttool (with --check gate)
Ship criterion: an agent connected via MCP can read the file, propose a change, validate it, diff it, and commit it.
Phase 2 โ Analysis tools (0.5 day)¶
perch_scantool (wrapsusecases/scan)perch_presenttool (wrapsusecases/scan+usecases/commandhelpinto prose)
Ship criterion: an agent can produce capability + risk reports without running the script.
Phase 3 โ Resources (0.5 day)¶
perch://skill(embedded SKILL.md)perch://op-catalog(embedded op-reference.md)perch://language(embedded language.md)perch://file/<path>(reads from workspace)
Ship criterion: the agent can read_resource("perch://skill") and get the authoring guide as context without us inflating any prompts.
Phase 4 โ Documentation + recipes (0.5 day)¶
- Update mcp.md with the seven new tools' schemas.
- Add a short "authoring with Claude Desktop" walkthrough to the LLM control plane doc.
- Recipe: a Claude Desktop
mcpServersentry that points atperch-mcpwith the workspace flag.
Total ~3 focused days. Half the previously-estimated effort, with a stronger trust story.
9. What this is NOT¶
- It is not an AI feature in perch. perch core gains nothing.
perchandperch --serverandperch-lspcontinue to have no LLM code. The only addition is MCP tools, which are how agents already talk to tools. - It is not autonomous. The agent still asks the user to approve every change.
perch_apply_draftexists precisely so there's a human-clicked moment. - It is not bundled. A user who doesn't use Claude Desktop / Cursor / Zed / any MCP client gets exactly the perch they have today. The MCP server only runs when someone invokes
perch-mcp. - It is not a chatbot. Agents make MCP tool calls and read MCP resources. There's no chat protocol inside perch. The chat lives in the agent's host.
- It is not a substitute for
--check/--scan. Those run on the host (via the CLI) and in the agent (via MCP). Same code, same results, same gates. The agent isn't allowed to commit a draft that doesn't pass--check.
10. Composition with existing features¶
| Existing | Role in this design |
|---|---|
perch-mcp |
The integration point. Gains 7 tools + 4 resources. |
skills/perch/SKILL.md |
Reused verbatim as the perch://skill MCP resource. Same content that helps Claude Code write good perch from a CLI now helps any MCP-connected agent write good perch from any chat. |
usecases/validate |
Wraps to perch_check tool. |
usecases/scan |
Wraps to perch_scan tool, also feeds perch_present. |
usecases/commandhelp |
Feeds perch_present (per-command help). |
--audit FILE.ndjson |
Unchanged. The agent's calls go through perch_run (existing), which already records to the audit log. |
perch --server |
Unchanged. If the user wants AI alongside it, they open Claude Desktop in another window pointed at the same workspace. |
The authoring-AI story is a layer the agent adds on top, not a layer perch adds inside. That's the architecture choice the earlier draft got wrong and this one gets right.
11. Summary in one paragraph¶
AI-assisted authoring happens entirely in the agent's host. perch ships zero LLM client code, zero API-key handling, zero outbound LLM HTTP. The agent (Claude Desktop, Cursor, Zed, custom MCP client) uses its own already-configured AI access to compose .perch snippets, and connects to perch-mcp for the workspace operations โ read the file, propose a draft, run --check and --scan, render a diff, commit after the user approves. SKILL.md, the op catalog, and the language reference are exposed as MCP resources the agent loads on demand. The whole new surface is ~600 LOC of MCP tools that wrap existing usecases/validate and usecases/scan. The user sees AI assistance in their agent's chat UI; perch sees only tool calls. --no-network continues to mean no network, because nothing in perch ever calls a model. That's the design.