feat(installer): user-defined custom targets — codegraph targets add, spec-driven families - #1459
Conversation
|
@colbymchenry would appreciate your take on this PR — it lets new AI coding agents integrate CodeGraph with a one-line spec instead of a registry PR. Also, calling on the authors of the other open target PRs — you know your agents best, and I'd love a sanity check on whether the spec form actually covers them: @leihanchen @Inference1 — your Grok Build targets (#1324 / #1396) map to: codegraph targets add '{"id":"grok","displayName":"Grok Build","family":"toml","configDir":"~/.grok","homeEnvVar":"GROK_HOME","localConfigDir":".grok"}'Does this match Grok's behavior as you implemented it? (One known difference from #1324: no AGENTS.md for local installs — the family follows Codex there.) @ZevGit — Qwen Code (#968) should be fully covered by the @SEPURI-SAI-KRISHNA — Windsurf (#952) is one knob short: the @liuwenji007 — Qoder (#1277) matches the If your agent is covered by a spec, this mechanism would get you unblocked without waiting on a registry merge; if I've mis-read any of your agents' config formats, corrections very welcome. Thank you! |
|
@quickbeard nice writeup — the family/spec direction makes a lot of sense for the long tail of simple targets, and thanks for the shout-out. Confirming the Windsurf detail: yes, the stdio entry is { command, args } with no type field — Windsurf's documented examples omit it, and I found the editor is happier without it, so an omitTypeField (or equivalent) knob on the mcp-json family would cover #952 exactly. Config path is ~/.codeium/windsurf/mcp_config.json, global-only (no project-local config), os.homedir()-based on all three platforms. One extra gotcha worth baking into the spec/notes: Windsurf doesn't pick up mcp_config.json live — the user has to open the MCP panel and hit Refresh, otherwise it looks like the install silently failed. I'm happy either way on mechanism — whatever gets Windsurf support in. If #1459 lands, glad to contribute the omitTypeField knob + a Windsurf spec here; if the maintainer would rather take a small focused built-in in the meantime, #952 is green (contract suite passing) and ready. @colbymchenry — happy to go whichever direction you prefer. |
Adds spec-driven custom installer targets so agents without a built-in target (opencode forks like CoDev Code colbymchenry#1272, Codex-shaped TOML agents like Grok Build colbymchenry#1324) can be wired up with a small declarative spec instead of a registry PR. - Extract the opencode and codex targets into family factories (opencode-family.ts, toml-family.ts) — behavior-preserving, pinned by the existing 162-test installer contract suite. Add a third generic mcp-json family for standard mcpServers-JSON agents. - targets/custom.ts: spec schema + validation (id shape, reserved words, builtin collisions, path-shape rules), tolerant loader (invalid specs skip with a warning, never crash the installer), strict add/remove persistence to ~/.codegraph/targets.json (CODEGRAPH_TARGETS_FILE override). - Registry merges customs after built-ins; --target <id>/auto/all, the interactive multiselect, uninstall's sweep, and --print-config all see them with no further changes. - CLI: codegraph targets add|list|remove. - 30 new tests in __tests__/custom-targets.test.ts; design doc at docs/design/custom-installer-targets.md; CHANGELOG entry.
0d0ae50 to
d46e3f1
Compare
|
Thanks for the ping — and for mapping the open target PRs onto a shared family/spec approach. That direction makes a lot of sense to me, especially for long-tail agents like Qoder where a full registry entry is heavy. You’re right that the MCP side is the same
The I’ve also just refreshed #1277 (conflict resolution + a shorter CHANGELOG). Happy to confirm an entry shape against a real Qoder install, or trim further once the family knobs land. Thanks again for looping us in. |
What
Adds user-defined custom installer targets:
codegraph targets add <spec.json>registers an agent from a small declarative spec, and from then oncodegraph install --target <id>,--target auto/all, the interactive multiselect,codegraph uninstall's sweep, and--print-configall treat it exactly like a built-in.codegraph targets list/removemanage registrations, stored in~/.codegraph/targets.json.A spec names a family — one of the config shapes CodeGraph already knows how to write — plus the paths that identify the agent:
opencodemcp.<name>wrapper, XDG dirs,.jsonc-over-.jsonpreferencetoml[mcp_servers.codegraph]tablemcp-jsonmcpServersJSON objectWhy
Every fork or clone of an existing agent currently costs a permanent registry entry, a bespoke target file, and a maintainer support surface — and they keep coming. A census of the eight open new-target PRs right now, mapped against this mechanism:
opencode-family specGROK_HOMEtoml-family spec~/.qwen/settings.json+QWEN.mdmcp-json-family spec (instructionsFileName: "QWEN.md")mcpServerswithout atypefield, global-onlytype) — trivial follow-up if wantedmcpServersat a platform-dependent dir (Application Support/%APPDATA%)mcp-json; portable specs would need platform-conditional dirsmcp.servers, absolute binary path +--pathinjectionSo four of the eight collapse into one-line user-side specs as-is, two more are a small family knob away, and the two that don't fit are exactly the "behavioral writes stay in reviewed built-in code" cases the design doc scopes out. The config-shape families stay reviewed, tested code owned by this repo; the paths become user data — and the next OpenCode/Codex/Gemini-shaped agent needs no PR at all (#1440 shows the registry keeps growing even from the maintainer side).
I maintain the codev fork and opened #1272 — this PR is the generalization I'd rather see land than a per-fork target.
How
targets/opencode-family.ts,targets/toml-family.ts(new) — the OpenCode and Codex implementations extracted into spec-driven factories. Behavior-preserving: the built-ins are now thin instantiations, and the existing 162-test installer contract suite passes unchanged against them. The toml family gains the two knobs Grok needs:homeEnvVar(env override for the config dir) and optionallocalConfigDir(project-scoped installs; unset = global-only, which is how Codex keeps its exact current behavior).targets/mcp-json-family.ts(new) — plainmcpServersshape withserversKey/configFileName/instructionsFileNameknobs.targets/custom.ts(new) — spec schema + validation (id shape^[a-z][a-z0-9-]{0,31}$, reserved words, built-in collisions, config dirs must be absolute or~/-prefixed, local dirs relative with no..), a tolerant loader (an invalid spec or unparseable file degrades to a one-line warning — the installer never crashes because of a bad spec;targets addis strict and refuses invalid specs up front), and add/remove persistence.targets/registry.ts—getAllTargets()appends loaded customs after the built-ins;getTarget/listTargetIds/detectAll/resolveTargetFlagresolve against the merged list.ALL_TARGETSstays the frozen built-in list.TargetIdwidens tostring(BuiltinTargetIdkeeps the union).bin/codegraph.ts— thetargetscommand group (spec from a file path or inline JSON).docs/design/custom-installer-targets.md. CHANGELOG entry under[Unreleased].A spec never says what to write — only where, under a family's rules. That keeps the installer contract (sibling preservation, byte-identical idempotent re-runs, uninstall reverses install) provable per family instead of per spec, and keeps a typo'd spec from scribbling outside an agent config dir.
Deliberate scope calls (flagging for maintainer judgment)
%APPDATA%legacy sweep stays opencode-only — it's a factory flag the built-in sets, not a spec field. It heals damage a past CodeGraph release did, and only the built-in OpenCode target ever had that install base; exposing it would make custom installs touch%APPDATA%\<app>dirs their agents never read.claude-jsonfamily that writes the MCP entry plus the well-knownmcp__<server>__*permission string is listed as future work if Claude-fork demand shows up.Tests
__tests__/custom-targets.test.ts(new, 30 tests: validation matrix, loader tolerance, per-family install/idempotency/sibling-preservation/uninstall contracts, registry merge, add/remove round-trip)installer-targets.test.ts(162 tests — regression net proving the OpenCode/Codex factory extractions are behavior-preserving)tscdist/(add → list → install codev + grok specs → verify written configs incl.GROK_HOMEoverride and jsonc comment survival → uninstall reverses → remove)If this lands I'm happy to close #1272 in its favor (it addresses #1274 via the spec above). #1324 / #1396 (Grok Build) and #968 (Qwen Code) become achievable without registry entries as-is, and #952 (Windsurf) / #1277 (Qoder IDE) get there with the small family knobs noted in the census above.
Demo