ADR-0009: GOAT home directory (~/.goat) and file-based MCP config
Status: Accepted · 2026-08-29 · Amends the config-storage clause of ADR-0006, refined by ADR-0033
Context
M4 needs a home for MCP server config. ADR-0006 said "GRDB, edited via native forms." JB's counter-proposal: a ~/.goat directory with config/mcp-servers.json, working dir configurable in Settings.
The ecosystem settles it. Every MCP server README says "add this JSON to your config." Claude Desktop's mcpServers shape is the lingua franca; dotfile homes are the dev-tool norm (~/.claude, ~/.ssh, ~/.config). A database row cannot be pasted from a README, hand-fixed in BBEdit, or checked into a dotfiles repo. GOAT's audience is exactly the people who do all three.
Decision
Two roots, one rule: files you own live in the GOAT home; machine state lives in App Support.
~/.goat/ # GOAT home: yours. Default; overridable.
├── config/
│ └── mcp-servers.json # Claude Desktop-compatible (see below)
└── memory/ # the wiki moves here from App Support (ADR-0005 intent: "a folder you own")
├── MEMORY.md # global Markdown index + notes
└── llm-wiki/ # global LLM Wiki authority
~/.goat/projects/<name>_<uuid>/ # Pen control folder
└── memory/ # Pen-only local memory
~/Library/Application Support/GOAT/ # machine state: the app's
├── goat.sqlite # chats, projects, tool grants, call log
├── Attachments/
└── Logs/- Home resolution:
GOAT_HOMEenv var → Settings override (Settings → General, "GOAT home") →~/.goat. mcp-servers.jsonformat: Claude Desktop'smcpServersmap, verbatim semantics. An entry withcommand/args/envis a stdio server; an entry withurl/headersis Streamable HTTP. GOAT extension keys are additive ("disabled": truefirst). Import from Claude Desktop = read the same shape and merge, near enough to a file copy.- The file is the source of truth. Settings → MCP renders a native editor over it, plus "Open Config File" for hand edits; a file watcher hot-reloads and reconnects changed servers. Invalid JSON never crashes: Settings shows the parse error inline with an open-in-editor button.
- Not in the file: per-tool permission grants and the call log stay in GRDB. Connection config is shareable; security state is not. A pasted config must never smuggle in "always allow".
Consequences
README snippets paste straight in; configs are versionable (dotfiles repo away); Claude Desktop import becomes trivial; the memory folder gets more discoverable than a hidden Library path. Costs: hand edits can break JSON (validated, surfaced inline, never fatal), and two storage roots to document. The yours-vs-the-app's split is the documentation. ADR-0006's native-forms UI survives, now as an editor over the file.
Alternatives considered
GRDB-only (rejected: fights the paste-a-snippet ecosystem), JSON in App Support (rejected: hidden from the people who hand-edit it), TOML/YAML (rejected: the ecosystem speaks this exact JSON dialect).

