Skip to content

Make the plugin the only Claude Code wiring and add a Codex plugin - #258

Merged
devmaxxx merged 14 commits into
mainfrom
feat/agent-plugins
Oct 19, 2026
Merged

devmaxxx merged 14 commits into
mainfrom
feat/agent-plugins

Conversation

@devmaxxx

Copy link
Copy Markdown
Owner

Summary

Stacked on #257. Makes the plugin the only way zerograph wires into Claude Code, and adds the same plugin for Codex.

  • Claude Code plugin carries the session hook. agent/hook.mjs moves to agent/claude-code/scripts/hook.mjs, wired through hooks/hooks.json on SessionStart, SubagentStart, PreToolUse and PostToolUse. The hook and mcp.mjs now share scripts/launcher.mjs, so binary lookup, the .cmd guard and the PATH cut have one source. The hook reads the plugin's binary option. A checkout that never asked for an index (no zerograph.toml, no legacy hook, no built main worktree) hears nothing. The repo-scout subagent ships in the plugin.

  • Codex plugin, agent/codex/, listed by .agents/plugins/marketplace.json. Codex substitutes nothing in MCP args, so .mcp.json runs a node -e bootstrap that imports scripts/mcp.mjs from $CODEX_HOME/plugins/cache/zerograph/zerograph/<version>/. The hooks run on SessionStart, SubagentStart and PostToolUse (apply_patch|Edit|Write); like before there is no PreToolUse interceptor. The seven commands ship as $zerograph:<name> skills with allow_implicit_invocation: false, plus use-the-graph. The scripts are copies of the Claude Code ones, and agent/codex/plugin.test.mjs fails when they differ. It also fails when the bootstrap's version, the two plugin versions or the crate's disagree.

  • install-agent --claude / --codex run claude plugin marketplace add + plugin install (or codex plugin marketplace add --ref v<version> + plugin add). Where the CLI is missing they print the commands and change nothing. Only once the plugin is in do they remove the earlier install:

    • the local-scope MCP servers in ~/.claude.json for the checkout, its worktrees and removed checkouts;
    • the zerograph hook entries in .claude/settings.json and $CODEX_HOME/hooks.json;
    • the copied hook script and its rule;
    • the zerograph/repo-query skills and repo-scout, while still generated;
    • the stanza, which stays in AGENTS.md while opencode reads it.

    Edited files are left and named. The git-block retirement is unchanged. Legacy templates move to agent/legacy/ for the comparisons.

  • Docs: the README install line and plugin section, docs/install.md (Upgrading, Claude Code plugin, a new Codex plugin section), docs/mcp.md, docs/keeping-fresh.md, agent/codex.md, and a Breaking line in docs/releases/0.7.0.md. The release-note lines for the superseded registration and printed-hook fixes are removed.

  • CI runs the moved hook test and the new Codex plugin test.

Open points:

  • The Codex marketplace pin --ref v0.7.0 resolves only once the tag exists.
  • Codex hook commands on Windows (${PLUGIN_ROOT} under cmd) are untested.
  • --command no longer affects the Claude Code or Codex integration.

Test plan

  • cargo test: all suites green, including 26 install_agent tests covering the plugin steps per harness, a missing CLI, a failed step, a re-run over an older install, edited files kept, the opencode stanza, a linked CLAUDE.md, the Codex hooks file and pruning a live replaced checkout.
  • cargo clippy --all-targets -- -D warnings
  • node --test agent/claude-code/scripts/hook.test.mjs agent/claude-code/scripts/mcp.test.mjs agent/codex/plugin.test.mjs npm/zerograph/test/launcher.test.js: 71 pass.
  • claude plugin validate --strict agent/claude-code and on the repo marketplace; claude plugin test agent/claude-code (26 pass).
  • E2E claude -p --plugin-dir agent/claude-code "/zerograph:impact priceOf" on a scratch repo: the SessionStart brief was injected, plugin:zerograph:zerograph was connected, the command called mcp__plugin_zerograph_zerograph__impact, and the PreToolUse interceptor answered the follow-up grep from the graph.
  • E2E Codex 0.154 with a scratch CODEX_HOME: codex plugin marketplace add <worktree> + plugin add installed 0.7.0, the app server listed the skills, codex exec ran the SessionStart hook, and the MCP bootstrap started the binary as --repo <project> mcp.
  • install-agent --claude --codex against fake claude/codex CLIs over a hand-made 0.6.x install. Both plugins were installed. The hook, the settings entries, the stanza and the ~/.claude.json server were removed; an edited skill and an edited rule were kept with a note.

The plugin now starts zerograph's MCP server itself and ships seven
slash commands that call its tools: ask, impact, trace, changes,
explain, status and refresh. Each pre-approves only the
mcp__plugin_zerograph_zerograph__* tools it calls and tells the model
how to read the answer: open the top path:line, and pair a "nothing
uses this" with a text search. A use-the-graph skill tells the model
when to reach for those tools instead of grep.

The server is declared in plugin.json and started by scripts/mcp.mjs,
which finds the binary the way the status mod does: the binary option
when it is absolute, else zerograph on PATH outside the checkout.
plugin.json can substitute the option but not branch on it.

The MCP server gains cache_status, the report `cache status` prints,
and reindex now starts a first build where no store stands rather than
an update, each taking the writer lock in its own process.

install-agent --claude's local-scope server would run beside the
plugin's, so the docs say to remove it when the plugin is installed.
- Refuse to start npm's zerograph.cmd shim through cmd when its path or
  the checkout's holds & | < > ^ " % !, which cmd would act on, and say
  so on stderr.
- Hand the server a PATH cut to the entries outside the checkout.
- Compare PATH entries with the checkout both as spelled and with links
  followed, so a symlinked alias does not let a checkout binary through.
- Require the exec bit on a PATH candidate on POSIX.
- Outside git, take the nearest ancestor holding .zerograph/ as the
  repository, as the CLI does, before falling back to the project dir.
- cache_status no longer creates the cache directory: a cache not made
  yet reports as empty.
- Document the bare node the plugin config starts, the .cmd refusal and
  the cut PATH.
Main's Status now carries the models and the unreadable bytes, so the
report of a cache not made yet is compared whole instead of through a
Vec method it no longer is.
The Claude Code plugin now carries the session hook (moved from
agent/hook.mjs to agent/claude-code/scripts/hook.mjs) beside its MCP
server, and both find and start the binary through one shared
launcher.mjs, so they cannot disagree about which zerograph is safe to
run. The hook takes the plugin's binary option, and a checkout that
never asked for an index hears nothing from it.

agent/codex/ is a new Codex plugin listed by
.agents/plugins/marketplace.json: the MCP server through a bootstrap
that finds the installed plugin under CODEX_HOME (Codex substitutes
nothing in MCP args), the hook on SessionStart, SubagentStart and after
an apply_patch, and the commands as explicit-only skills. Its scripts
are copies of the Claude Code plugin's, held identical by
plugin.test.mjs, which CI now runs.

install-agent --claude and --codex install the plugin through the
claude or codex CLI, print the commands when the CLI is missing, and
only once it is in take out what earlier releases wrote: the
local-scope MCP servers for the checkout and its worktrees, the hook
entries and script, the skills and subagent while still generated, and
the instructions stanza (kept in AGENTS.md while opencode reads it).

BREAKING CHANGE: install-agent --claude/--codex no longer register an
MCP server, write hooks, skills or a stanza; they install the plugin
and remove those files from an earlier install. --command no longer
reaches Claude Code or Codex.
- Hook entries are retired per command, so a command sharing a matcher
  group with ours stays.
- A symlinked settings file, rule, subagent or hook script is left
  and named instead of unlinked.
- $CODEX_HOME/hooks.json is rewritten where its link points.
- The MCP launcher takes ZEROGRAPH_BIN before the binary option, as the
  hook does, and treats the unsubstituted option as unset.
- On Windows the claude and codex CLIs are found as npm .cmd shims too.
- The docs no longer promise a refresh after every edit.
…he CLI does

- When the checkout is the home directory, an ancestor of it or a
  filesystem root (a ~/.zerograph or a dotfiles ~/.git), the PATH cut is
  skipped in both the MCP launcher and the session hook, since it took
  nvm, cargo and ~/.local/bin with it.
- PATH is matched case-insensitively only on Windows.
- A quoted Windows PATH entry is judged without its quotes and kept as
  written.
- The checkout is looked up from the real path of the session
  directory, as the CLI canonicalizes its working directory.
Carries #257's launcher fixes into the shared launcher.mjs: no PATH cut
when the checkout is the home directory, above it or a filesystem
root; PATH matched case-insensitively only on Windows; a quoted
Windows entry judged without its quotes and kept; the checkout found
from the session directory's real path. The hook now finds its
checkout through the launcher, and a PATH entry that does not exist yet
is compared with its existing part's links followed, so it still names
a checkout reached through /var or another link.
The checkout lookup follows links with realpathSync.native, which on
Windows also expands 8.3 short names such as RUNNER~1, so the tests now
build their expected paths the same way. The POSIX PATH-key case uses
POSIX literals, since a drive letter's colon split a Windows host's real
paths.
The checkout lookup follows links with realpathSync.native, which on
Windows also expands 8.3 short names such as RUNNER~1, so the tests now
build their expected paths the same way. The POSIX PATH-key case uses
POSIX literals, since a drive letter's colon split a Windows host's real
paths.
…agent-plugins

# Conflicts:
#	agent/claude-code/scripts/mcp.test.mjs
@devmaxxx
devmaxxx deleted the branch feat/plugin-commands October 19, 2026 10:14
@devmaxxx devmaxxx closed this Oct 19, 2026
@devmaxxx devmaxxx reopened this Oct 19, 2026
@devmaxxx
devmaxxx changed the base branch from feat/plugin-commands to main October 19, 2026 10:14
# Conflicts:
#	.github/workflows/ci.yml
#	README.md
#	agent/claude-code/scripts/hook.mjs
#	agent/claude-code/scripts/mcp.mjs
#	agent/claude-code/scripts/mcp.test.mjs
#	docs/install.md
#	docs/mcp.md
- The risk line reads Codex's apply_patch: every file a patch adds,
  updates or moves to is scored, not only Claude Code's file_path.
- install-agent takes a hook script out only after the entries that run
  it are gone, in .claude/settings.json and in $CODEX_HOME/hooks.json,
  and only while it is the text 0.6.0-0.6.4 wrote (kept in
  agent/legacy/zerograph-hook.mjs).
- Files git tracks are left for the team and listed in one line;
  --retire-repo takes them out once every teammate has the plugin.
- A re-run after a binary upgrade moves the plugin with it: Claude Code
  refreshes the marketplace and runs plugin update, and Codex removes
  and re-adds a marketplace pinned to an older tag.
- The Codex MCP bootstrap finds the newest installed version instead of
  naming one, says so when none is installed, and passes the ZEROGRAPH_*,
  model cache, proxy, certificate and locale variables through.
- Codex hooks carry a commandWindows form that reads PLUGIN_ROOT in node.
- mcp.mjs drops its own copy of the unset-option placeholder.
- scripts/sync-plugin-scripts.sh copies the launcher scripts into the
  Codex plugin.
- Docs and release notes name the commands the code runs.
On Windows the report holds backslash paths, so a string suffix with
forward slashes never matched.
@devmaxxx
devmaxxx merged commit 6799e6a into main Oct 19, 2026
7 of 8 checks passed
@devmaxxx
devmaxxx deleted the feat/agent-plugins branch October 19, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant