You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
graft parses a repository with tree-sitter into a local, git-ignored graph of linked markdown nodes
(graft/*.md) plus a per-symbol JSON wiring graph (graft/.graph/wiring.json), then rides along in
Claude Code, Codex/AGENTS.md-reading CLIs, Cursor, Gemini, GitHub Copilot, Kiro, Windsurf, and AdaL —
via a 6-tool MCP server (graft_find_code, graft_file_api, graft_trace_calls, graft_find_all, graft_repo_map, graft_check_freshness), marker-fenced instruction-file sections, and (for Claude
Code specifically) a live statusline plus post-edit hooks that keep the graph auto-synced every turn.
The structural graph (graft build, graft check) is deterministic tree-sitter — no LLM, no key,
no network — and stays that way unless a user opts into graft build --deep for LLM-written
concept summaries under their own provider key.
This proposal maps the split you (the maintainer) already described in review: ak setup installs
the npm-global binary (machine phase, no repo touched), graft init — the project-scoped wiring
step — runs only under ak setup --project (or wherever project setup already runs today per docs/SETUP.md), ak sync owns updates and heals wiring/graph drift, and ak dashboard gets a
graft card/row from the same status facts, per docs/MANAGED-TOOLS.md's five invariants.
Relationship to #115 (GitNexus) and #117 (Graphify) — read before approving scope
This is the third proposed "build a local knowledge graph from this repo, expose it to agents"
companion in this backlog. All three remain unimplemented (open) as of this writing. Per the norm #117 set for #115, here is the comparison a maintainer needs to disposition deliberately rather than
by accretion:
graph.json + Obsidian vault / wiki / HTML / GraphML / Neo4j Cypher export
Plain linked markdown files + a JSON wiring graph — no database, no server, "reads like any other file in the repo"
Cost model
Fully local/deterministic; no LLM calls, no per-run token cost
Pass 1–2 free/local; Pass 3 (docs/papers/images) dispatches paid Claude subagents on every build touching non-code files
Tier 1 (graft build) fully local/deterministic tree-sitter, $0; LLM concept-node/summary layer is a separate opt-in step (graft build --deep), never triggered automatically
Freshness model
PostToolUse hook does a cheap git rev-parse HEAD check and nudges ("index is stale, run gitnexus analyze"); never auto-rebuilds; only fires from a live agent tool call
Opt-in graphify hook install (git hooks) or --watch auto-rebuilds code changes free; non-code changes only nudge
Every query re-stats the working tree first (~3ms, $0, no LLM) and rebuilds only what moved — includes uncommitted/unstaged edits, no "run the reindex" step exists in the happy path. For Claude Code specifically, a background rebuild also runs at the end of any turn that touched code. Strongest freshness guarantee of the three; the only one with no "opt in to staying fresh" step
Install ecosystem
npm — already on this machine via mise's npm backend, not plain global npm (the reason #115 can't reuse #114's logic unchanged, and the reason #116's classifier exists)
Python (pip/pipx/uv tool) — a wholly new ecosystem for Agentic Kit
npm-global (npm install -g @nanonets/graft) — same install lane as ruflo/agentic-qe/hosts today; no evidence yet that this repo's install is mise-managed, so #116's classifier is not a hard prerequisite here (see Goals)
Host file injection
AGENTS.md/CLAUDE.md tagged block (off by default), .claude/skills/gitnexus/
Marker-fenced sections in AGENTS.md/GEMINI.md/.github/copilot-instructions.md; owned files for the rest (.claude/skills/graft/SKILL.md, .cursor/rules/graft.mdc, .kiro/steering/graft.md, .windsurf/rules/graft.md, .adal/skills/graft/SKILL.md). Also writes machine-wide, outside the repo, when the Codex/agents host is selected: ~/.codex/config.toml ([mcp_servers.graft]), ~/.codex/hooks/graft/graft-hooks.cjs, ~/.codex/hooks.json. --no-global skips these three. Neither GitNexus nor Graphify's proposals describe touching machine-wide config — this is a genuinely new risk class for this repo's third graph companion (see Risks)
License
PolyForm Noncommercial 1.0.0
Apache-2.0 (relicensed from MIT)
MIT — the most permissive of the three, and the only one with an OpenSSF Scorecard badge
Auto-update / self-maintenance
None beyond the staleness nudge described above
graphify hook install / --watch, opt-in, free for code
graft upgrade (npm install -g latest) exists as a manual command; a machine-global, TTL-cached (24h), background-spawned update-check (~/.graft/update-check.json) independently nudges ⬆ graft X → Y available from CLI/hook/MCP entry points; a separate wiring-stamp reconciler (graft/.cache/wiring-stamp.json) re-runs init's writes (never a graph rebuild) when the installed binary version is ahead of what wrote the repo's wiring, replaying the exact flags (--no-global/--no-mcp/--no-hooks) the original init was given
Maturity
—
—
Active, pre-1.0: 24 npm releases in ~5 weeks (0.1.0 on 2026-07-15 → 0.10.1, pushed 2026-08-18), 3591 GitHub stars, 317 forks, 57 open issues
A reasonable disposition once all three are read together: GitNexus and graft compete directly for
the same "structural code graph, $0 by default" niche, with graft's always-fresh-per-query model and
markdown-node design being a meaningfully different (arguably stronger) bet on freshness and
readability than GitNexus's graph-database + nudge-only approach, at the cost of graft being a
younger, faster-moving (pre-1.0) project versus GitNexus's more conservative footprint. Graphify
occupies clearly adjacent-but-different territory (multi-modal corpus, paid LLM passes) and is not in
direct competition with either. Setup should not silently let a user enable graft and GitNexus
together and pay to build two overlapping graphs of the same code — same guidance #117 gave for
GitNexus/Graphify. This issue does not resolve which of GitNexus/graft the project should carry
forward (or whether both, clearly labeled); it names the overlap so a maintainer decides on purpose.
Why this belongs in Agentic Kit
graft's upstream CLI already provides the same shape of managed-companion primitives #114/#115/#117
established as the pattern:
a published npm package, @nanonets/graft, with a single graft bin;
graft init --dry-run / --agents <ids> / --yes / --no-global / --no-mcp / --no-hooks / --no-build / --all-agents / --list-agents — a scriptable, non-interactive wiring surface with
no-TTY-writes-nothing-by-default behavior (CI/Dockerfile-safe out of the box);
graft check --json — a drift/freshness report Agentic Kit can parse without guessing;
graft version (installed + latest npm) and a documented, single self-update command
(graft upgrade) Agentic Kit should own rather than let the user or graft's own nudge drive
independently — see docs/MANAGED-TOOLS.md invariant 2 and checklist item 4;
an idempotent, merge-not-clobber writer for .claude/settings.json and every shared instruction
file, matching this repo's own ADR-0023 fail-closed / no-clobber expectations;
no telemetry, MIT license, an OpenSSF Scorecard badge — a stronger trust posture than either sibling
proposal.
Current Agentic Kit architecture
The seams #114/#115/#117 already document apply unchanged:
src/commands/setup.mjs — machine phase installs enabled global tools/hosts; project phase (ak setup --project, or automatically when .git exists in cwd per docs/SETUP.md) performs
per-repo wiring. graft's own init/machine split maps directly onto this existing boundary —
arguably more cleanly than any prior companion, since graft's upstream CLI already separates "get
the binary" (npm install -g) from "wire this repo" (graft init) the same way ak setup already
separates machine and project phases.
ADR-0016 (Accepted) and ADR-0023 (Implemented) govern this exactly as they do the sibling proposals.
Relevant precedent from this repo's own history: issue ak setup ships ruflo without native SQLite bindings under npm 12; ak dual run then fails with a native↔WASM memory conflict #45 ("ak setup ships ruflo without native
SQLite bindings under npm 12") is a direct analog to graft's native tree-sitter dependency tree
(tree-sitter, tree-sitter-go, tree-sitter-java, tree-sitter-python, tree-sitter-typescript,
plus tree-sitter-wasms/web-tree-sitter as a WASM path) — this needs the same
clean-machine/cross-platform install proof ADR-0023 already requires, not a new standard.
Also relevant: this machine's ambidextrous dual-host bridge already owns [mcp_servers.ruflo] in ~/.codex/config.toml (see this repo's own CLAUDE.md). graft's init
writes [mcp_servers.graft] into the same file. Two independent writers touching ~/.codex/config.toml is a new collision class this proposal must design around explicitly — see
Risks.
Goals
Let users opt into graft during ak setup (machine phase) or through an explicit config change.
Run graft initonly during project setup (ak setup --project, or wherever project setup
already triggers per docs/SETUP.md), non-interactively, using ak's own already-resolved enabled
host set to drive graft init --agents <ids> --yes.
Default to graft build (structural, $0) on first wire; treat graft build --deep (LLM-enriched,
costs tokens under the user's own key) as a separate, explicit opt-in — never triggered by setup or
sync automatically.
Keep graft's own machine-wide Codex writes (~/.codex/config.toml, ~/.codex/hooks.json, the hook
shim) under explicit Agentic Kit control: default to --no-global when wiring the Codex/agents
host during project setup, and let a separate, explicitly-opted-in flag hand that scope to graft
instead of silently letting two tools race on the same file (see Risks).
Surface presence, install method, ownership, version drift, per-host wiring, graph freshness
(graft check --json), and degraded states in ak status and the Dashboard.
Make ak sync the single owner of the npm package update (per docs/MANAGED-TOOLS.md invariant 2)
and of wiring/graph drift repair — reusing graft's own idempotent graft init replay and graft check/graft build rather than reimplementing graft's wiring-diff logic.
Detect and neutralize graft's own machine-global daily update-check nudge
(~/.graft/update-check.json, spawned from CLI/hook/MCP entry points) as the "auto-update
machinery" docs/MANAGED-TOOLS.md checklist item 4 requires Agentic Kit to detect and own, so ak status/ak sync remains the single drift story (invariant 4) rather than a second nudge
surfacing independently inside a live agent session.
Remove only Agentic Kit-owned wiring and packages on ak uninstall; preserve graft/'s local
cache, graft/.cache/wiring-stamp.json, and any user notes appended below a node's generated block
unless the user explicitly requests a data purge.
Enabling graft build --deep (LLM-enriched nodes) by default, or ever triggering it from ak setup
or ak sync automatically.
Modeling graft as an execution host, inference provider, routing target, or AgentDB/Ruflo memory
replacement.
Letting graft's own graft init mutate ~/.codex/config.toml/hooks.json by default when Agentic
Kit already owns Codex MCP bridge wiring in that same file — see Goal 5 and Risks.
Copying graft/'s markdown nodes or wiring graph into AgentDB/Ruflo memory. graft's local files
remain graft's own regenerable cache.
Auto-installing language servers for graft build --lsp's optional compiler-grade edges
(rust-analyzer, clangd, gopls, pyright, typescript-language-server); best-effort/user-provided only.
Primary use cases
1. Global install, zero repo footprint until opted in
ak setup --with-graft installs @nanonets/graft globally. No repo is touched. A user can run ak setup on a fresh machine and never see a graft/ directory appear anywhere until they explicitly
run project setup somewhere.
2. Project onboarding wires it in one step
ak setup --project in a repo the user has opted into graft for runs graft init --agents <ak's enabled hosts> --yes, builds the structural graph once, and verifies it — no manual per-host
configuration, matching #114's use case 1.
3. Fresh answers without a reindex step
A teammate pulls a large upstream change. The next graft ask/MCP call re-stats the tree and rebuilds
what moved automatically ($0, ~ms) — no ak sync or manual reindex is required for correctness; ak sync exists for package/wiring drift, not for keeping the graph fresh turn-to-turn, which graft
already owns end-to-end.
4. Drift repair
The npm package is upgraded, a host's wiring file goes missing, or .claude/settings.json's graft
block is stripped by an unrelated edit. ak status reports the observed problem via graft check --json plus host-file presence checks; ak sync performs the smallest owned repair by replaying graft init with the recorded host set and flags.
5. Safe Codex coexistence
A user enables both the Codex host and graft. Setup defaults to --no-global for graft's Codex wiring
so Agentic Kit's own [mcp_servers.ruflo] entry in ~/.codex/config.toml is never at risk of being
overwritten or duplicated by a second independent writer; graft's Codex integration is limited to AGENTS.md unless the user explicitly opts into graft's own global hook/MCP registration.
6. Clean removal
ak uninstall removes only Agentic Kit-owned wiring by default. --remove-graft also removes the
owned npm package after confirmation. graft/'s local cache and any user notes under generated node
blocks survive unless a separate, confirmed purge flag is passed.
Product principles
Complement, do not duplicate GitNexus. If both are ever enabled, Setup discloses the overlap
named above rather than silently building two graphs of the same code.
Structural first, LLM enrichment is a separate decision.graft build --deep is never
triggered by any Agentic Kit-driven path without explicit opt-in.
Agentic Kit's existing machine-wide surfaces are never contested. graft's ~/.codex/ writes
default off; enabling them is a distinct, disclosed choice, not a side effect of enabling graft.
One package update owner.ak sync updates the npm package; graft's own graft upgrade is
never invoked by Agentic Kit, and graft's own background update-check nudge is detected and
suppressed so it can't disagree with ak status.
Observed truth drives status. Parse graft check --json, graft version, the package on disk,
and per-host wiring-file presence; never infer healthy from process exit alone.
Presence is not ownership. A mise/Homebrew/manual graft install is visible, never auto-updated
or removed.
Reuse graft's own reconciliation instead of reimplementing it. graft's init is already
idempotent and replays the exact flags a prior wiring was given (recorded in graft/.cache/wiring-stamp.json); Agentic Kit's sync adapter should drive that mechanism rather
than hand-roll its own wiring diff.
Unknown stays unknown. A malformed graft check --json payload, an unqueryable version, or a
partially-wired repo is degraded/unknown, never reported healthy by default.
Proposed user experience
Setup
ak setup --with-graft # machine phase: npm install -g @nanonets/graft only
ak setup --no-graft # explicit opt-out (default until this ships)
ak setup --project # project phase, only if graft is enabled: graft init --agents <enabled hosts> --yes
ak setup --project --graft-deep # also runs graft build --deep once, after confirming a provider key is set
ak setup --project --graft-codex-global # opts Codex wiring into graft's own ~/.codex/ writes (off by default per Goal 5)
Interactive setup should default to No and, before mutation, explain:
a global npm package will be installed (machine phase) with no repo touched yet;
project setup will build a local, git-ignored code graph from this repo's source and wire it into
the enabled agent hosts' instruction files (and, for Claude Code, a statusline + hooks);
the structural graph never calls a model or leaves the machine; LLM-enriched nodes are a separate,
explicit choice under the user's own provider key;
Codex wiring stays inside AGENTS.md only unless the user explicitly opts graft into its own ~/.codex/ writes, which are machine-wide and shared by every repo.
Status
graft ok 0.10.1 npm-managed · wired: claude,codex · graph fresh
graft warn npm 0.9.1 installed, 0.10.1 available · sync upgrades it
graft warn wiring stamp behind installed binary · sync refreshes
graft warn graft/ missing or graft check reports drift · sync rebuilds
graft warn installed externally · not owned by ak
graft info management disabled
The collector should distinguish: absent; present-external; present-owned; package update available;
per-host wired vs missing; wiring-stamp version behind the installed binary (graft's own signal);
graph fresh/stale/missing per graft check --json; whether Codex global wiring is enabled and by
whom; doctor/version check unavailable → unknown, not healthy.
Sync
ak sync should:
install/upgrade @nanonets/graft via npm only when enabled — never call graft upgrade;
read graft/.cache/wiring-stamp.json for the currently-recorded host set and flags, union with
what's actually on disk (mirroring graft's own reconcileWiring logic), and replay graft init --agents <that set> --yes plus the recorded --no-global/--no-mcp/--no-hooks flags — reusing
graft's own idempotent writer rather than diffing files by hand;
run graft build (never --deep) only when graft check --json reports drift beyond what the
query-time auto-refresh already handles (e.g., after a fresh clone with no graft/ yet);
verify independently via graft check --json plus host-file presence, never trusting apply's exit
code alone;
leave the daily update-check nudge suppressed/ignored as ak's own drift read remains authoritative.
Repeated sync must be a true no-op.
Removal
ak uninstall # remove Agentic Kit-owned graft wiring (host files, MCP/hook entries)
ak uninstall --remove-graft # also remove the owned npm package, after confirmation
ak uninstall --purge-graft-data # also delete graft/ and graft/.cache/, confirmed, exact-path guarded
Default uninstall preserves graft/'s local graph and any user notes below a node's generated block;
an external install is never touched; a data purge never runs unless separately confirmed.
Configuration and ownership model
Extend the existing versioned integration envelope (#114's precedent), not a new top-level boolean:
Must preserve: desired enablement; deep-enrichment opt-in; desired host set; whether graft's own
Codex-global writes are permitted; observed install method/ownership; the exact wiring opts last
applied (so sync's replay matches what the user actually chose, not graft init's all-true default).
Migration is additive; existing configs default to disabled/unowned.
src/lib/adapters/graft.mjs — detect/plan/apply/verify/undo against the shared lifecycle contract.
Do not add graft to HOST_REGISTRY or PROVIDER_REGISTRY — same rule as every prior companion.
Lifecycle contract
detect — read desired config; resolve npm install state (disk-first, per invariant 1); parse graft check --json and the wiring stamp; inspect enabled-host wiring files (marker-fenced sections
owned skill/rule files); return normalized facts without writing.
plan — deterministically compute package install/upgrade, wiring replay (host set + opts diff),
graph (re)build (only if graft check reports drift beyond query-time auto-refresh), and undo
operations; disclose every host-file/.claude/settings.json/Codex-global mutation before it happens;
no-op for disabled or externally-owned state.
apply — install the npm artifact; invoke graft init --agents <ids> --yes with the recorded
wiring opts (defaulting --no-global unless codexGlobal is explicitly enabled); run graft build
(never --deep unless deep: true and a provider key is confirmed present) only when planned; record
ownership receipts only after verified success; report ok/degraded/failed/skipped.
verify — independently re-run graft check --json; observe actual host-file state; never trust
apply's exit code as proof.
Record the maintainer's explicit call on the GitNexus/graft overlap named above (both, one, or
clearly-labeled-alternatives) — this phase does not proceed to build without that decision on file.
Define the ~/.codex/config.toml dual-writer boundary (Goal 5) as a documented invariant, not just
a default flag value.
QA gate: ADR is current; the GitNexus/graft disposition and the Codex-global-writer boundary are
both written down before Phase 1 starts.
Keep collection read-only; no network calls beyond what a pre-existing npm/version check already
makes.
QA gate: every classification outcome (absent / external / owned-healthy / owned-drifted /
malformed-check / missing-stamp) is fixture-covered and honestly labeled.
Phase 2 — Setup and installation (machine phase only)
Add --with-graft/--no-graft to ak setup; persist opt-in intent; install the npm package.
No project mutation happens in this phase, by construction — this is the split the maintainer asked
for, and it should be provably true (a machine-only setup run leaves zero graft/ directories
anywhere).
QA gate: clean-machine ak setup --with-graft (no --project) installs the binary and touches no
repository; hermetic on Linux/macOS/Windows including native tree-sitter binding resolution (#45
precedent).
Phase 3 — Project wiring under ak setup --project
Wire graft init --agents <ids> --yes (structural build only) into project setup, gated on Goal 5's --no-global default for Codex.
Pre-mutation disclosure names every file graft init --dry-run reports before writing.
Verify via graft check --json before recording success.
QA gate: project setup with graft enabled produces the expected host files and a fresh graph; a
Codex-enabled run with codexGlobal: false leaves ~/.codex/config.toml's [mcp_servers.ruflo]
entry byte-identical.
Phase 4 — Sync, upgrades, and drift repair
Fold the npm package into the existing drift story (invariant 4); reconcile wiring via graft's own
stamp-replay mechanism; rebuild only on graft check drift, never on a timer.
Suppress/ignore graft's own background update-check nudge as the checklist's "auto-update machinery"
case (Goal 8).
Add the Dashboard card + banner fold from the same status facts.
QA gate: two consecutive syncs cause zero additional writes; status/JSON/Dashboard/plan agree;
graft's own update nudge never appears alongside a disagreeing ak status line in a fixture session.
Phase 5 — Safe removal, data purge, documentation
Add owned-wiring teardown, explicit package removal, and a separately confirmed graft/ + graft/.cache/ purge.
Update README/SETUP/MANAGED-TOOLS/UPGRADING/TROUBLESHOOTING and uninstall help.
Add adapter-conformance, clean-machine, and cross-platform regression evidence.
QA gate:pnpm run check passes; install → user drift → uninstall preserves user changes;
uninstall on a never-managed machine creates or removes nothing.
graft's [mcp_servers.graft]/hook entries added without disturbing Agentic Kit's own [mcp_servers.ruflo] entry
Codex disabled after prior codexGlobal: true ownership
Agentic Kit removes only graft's owned Codex-global entries
Data and privacy tests
structural build never calls a model or leaves the machine;
--deep never runs without explicit deep: true and a confirmed provider key;
default uninstall preserves graft/'s notes and cache;
purge refuses unresolved/broad paths and is exact-path guarded.
Acceptance criteria
graft is represented as an optional managed companion, not a host/provider or AgentDB/Ruflo
replacement.
ak setup --with-graft (machine phase) installs the npm package and touches no repository.
graft init runs only under project setup (ak setup --project, or wherever project setup
already triggers), scoped to Agentic Kit's own enabled host set via --agents/--yes.
Codex/agents wiring defaults to --no-global; graft's own ~/.codex/config.toml/hooks.json
writes require a separate, explicit opt-in and never disturb Agentic Kit's own [mcp_servers.ruflo] entry.
graft build --deep never runs without explicit opt-in and a confirmed provider key.
ak status/JSON distinguish presence, ownership, install method, version drift, per-host wiring,
graph freshness (graft check --json), and Codex-global-write ownership.
ak sync --dry-run is non-mutating; repeated ak sync is idempotent.
ak sync is the only caller of npm install -g @nanonets/graft@latest; Agentic Kit never invokes graft upgrade.
graft's own background update-check nudge is detected and does not produce a second, disagreeing
drift story in ak-managed sessions.
Wiring drift repair reuses graft's own stamp-replay mechanism rather than a hand-rolled diff.
Default uninstall removes only Agentic Kit-owned wiring/package; graft/ and its notes survive
unless a separately confirmed purge is requested.
The GitNexus/graft overlap (Relationship section) is disclosed to the user at setup time when
both would be enabled together, not silently allowed.
Shared lifecycle conformance, clean-machine, cross-platform, migration, and no-clobber tests
pass.
pnpm run check passes.
Success measures
A new opt-in installation reaches healthy verified state through one ak setup --with-graft + ak setup --project pair.
A second setup/sync performs zero writes when nothing changed.
A Codex + graft user's ~/.codex/config.toml never shows a diff attributable to graft unless they
explicitly opted into codexGlobal.
Package upgrade plus wiring-stamp replay converges in one sync, with no duplicate host entries.
Uninstall leaves unrelated host configuration byte-equivalent and preserves graft/ by default.
A user who also has GitNexus proposed/enabled sees the overlap named at setup time, not discovered
later as duplicated cost.
Risks and mitigations
Risk
Mitigation
Two independent writers (ak's Codex bridge, graft's own init) racing on ~/.codex/config.toml/hooks.json
--no-global default for graft's Codex wiring; explicit opt-in required to hand that scope to graft; Codex dual-writer matrix test (above) as a named regression guard
Third overlapping "code knowledge graph" proposal alongside #115/#117 fragments the backlog / duplicates future implementation cost
Relationship section forces an explicit maintainer disposition in Phase 0 before any code lands
graft's own daily update-check nudge disagrees with ak status's drift read inside a live agent session
Detect and treat as "auto-update machinery" per docs/MANAGED-TOOLS.md checklist item 4; suppress/ignore rather than let it stand as a second source of truth
Native tree-sitter bindings fail to install on some platform/Node combination
Claude Code supports one active statusLine entry; graft's own live statusline could collide with an existing kit- or aqe-owned statusline
Detect an existing statusLine entry before wiring graft's; surface the conflict rather than silently overwriting (this needs its own design decision in Phase 3 — flagged here, not resolved)
Pre-1.0 project (24 releases in ~5 weeks) — upstream CLI surface may still be shifting
Pin fixtures to a specific graft version in tests, same practice #116 already recommends for mise ls --json; treat graft check --json's shape as versioned, not assumed-stable
graft build --deep accidentally triggered by an automated path, incurring unexpected LLM spend under the user's key
Explicit deep: true config gate plus a provider-key presence check before Phase 3/4 ever run it; never triggered by setup/sync defaults
Overlap with GitNexus leads a user to enable both and pay to build two structurally-similar graphs
Setup-time disclosure named in Goals/Non-goals; not silently allowed
Definition of done
This issue is complete when a user can install graft's binary during ak setup's machine phase with
zero repository footprint, wire it into a specific project only via ak setup --project, have ak sync own every subsequent update and wiring/graph-drift repair (reusing graft's own idempotent
replay mechanism rather than duplicating it), see accurate presence/ownership/freshness state in ak status and the Dashboard, safely coexist with Agentic Kit's own Codex MCP bridge without either tool
clobbering the other's ~/.codex/config.toml entry, and cleanly remove everything Agentic Kit owns —
while the GitNexus/graft overlap this issue names has been deliberately dispositioned by a maintainer,
not silently absorbed.
Executive brief
Add first-class, opt-in management of graft (
@nanonets/graft)as a per-repository code-context-graph companion, following the same shape as
#114 (deja-vu),
#115 (GitNexus), and
#117 (Graphify).
graft parses a repository with tree-sitter into a local, git-ignored graph of linked markdown nodes
(
graft/*.md) plus a per-symbol JSON wiring graph (graft/.graph/wiring.json), then rides along inClaude Code, Codex/AGENTS.md-reading CLIs, Cursor, Gemini, GitHub Copilot, Kiro, Windsurf, and AdaL —
via a 6-tool MCP server (
graft_find_code,graft_file_api,graft_trace_calls,graft_find_all,graft_repo_map,graft_check_freshness), marker-fenced instruction-file sections, and (for ClaudeCode specifically) a live statusline plus post-edit hooks that keep the graph auto-synced every turn.
The structural graph (
graft build,graft check) is deterministic tree-sitter — no LLM, no key,no network — and stays that way unless a user opts into
graft build --deepfor LLM-writtenconcept summaries under their own provider key.
This proposal maps the split you (the maintainer) already described in review:
ak setupinstallsthe npm-global binary (machine phase, no repo touched),
graft init— the project-scoped wiringstep — runs only under
ak setup --project(or wherever project setup already runs today perdocs/SETUP.md),ak syncowns updates and heals wiring/graph drift, andak dashboardgets agraft card/row from the same status facts, per
docs/MANAGED-TOOLS.md's five invariants.Relationship to #115 (GitNexus) and #117 (Graphify) — read before approving scope
This is the third proposed "build a local knowledge graph from this repo, expose it to agents"
companion in this backlog. All three remain unimplemented (open) as of this writing. Per the norm
#117 set for #115, here is the comparison a maintainer needs to disposition deliberately rather than
by accretion:
graph.json+ Obsidian vault / wiki / HTML / GraphML / Neo4j Cypher exportgraft build) fully local/deterministic tree-sitter, $0; LLM concept-node/summary layer is a separate opt-in step (graft build --deep), never triggered automaticallyPostToolUsehook does a cheapgit rev-parse HEADcheck and nudges ("index is stale, rungitnexus analyze"); never auto-rebuilds; only fires from a live agent tool callgraphify hook install(git hooks) or--watchauto-rebuilds code changes free; non-code changes only nudgepip/pipx/uv tool) — a wholly new ecosystem for Agentic Kitnpm install -g @nanonets/graft) — same install lane as ruflo/agentic-qe/hosts today; no evidence yet that this repo's install is mise-managed, so #116's classifier is not a hard prerequisite here (see Goals)AGENTS.md/CLAUDE.mdtagged block (off by default),.claude/skills/gitnexus/CLAUDE.md/AGENTS.md/GEMINI.md/Copilot/Antigravity/Kiro "always-on" blocks + 15+ per-hostSKILL.mdfilesAGENTS.md/GEMINI.md/.github/copilot-instructions.md; owned files for the rest (.claude/skills/graft/SKILL.md,.cursor/rules/graft.mdc,.kiro/steering/graft.md,.windsurf/rules/graft.md,.adal/skills/graft/SKILL.md). Also writes machine-wide, outside the repo, when the Codex/agentshost is selected:~/.codex/config.toml([mcp_servers.graft]),~/.codex/hooks/graft/graft-hooks.cjs,~/.codex/hooks.json.--no-globalskips these three. Neither GitNexus nor Graphify's proposals describe touching machine-wide config — this is a genuinely new risk class for this repo's third graph companion (see Risks)graphify hook install/--watch, opt-in, free for codegraft upgrade(npm install -glatest) exists as a manual command; a machine-global, TTL-cached (24h), background-spawned update-check (~/.graft/update-check.json) independently nudges⬆ graft X → Y availablefrom CLI/hook/MCP entry points; a separate wiring-stamp reconciler (graft/.cache/wiring-stamp.json) re-runsinit's writes (never a graph rebuild) when the installed binary version is ahead of what wrote the repo's wiring, replaying the exact flags (--no-global/--no-mcp/--no-hooks) the originalinitwas givenA reasonable disposition once all three are read together: GitNexus and graft compete directly for
the same "structural code graph, $0 by default" niche, with graft's always-fresh-per-query model and
markdown-node design being a meaningfully different (arguably stronger) bet on freshness and
readability than GitNexus's graph-database + nudge-only approach, at the cost of graft being a
younger, faster-moving (pre-1.0) project versus GitNexus's more conservative footprint. Graphify
occupies clearly adjacent-but-different territory (multi-modal corpus, paid LLM passes) and is not in
direct competition with either. Setup should not silently let a user enable graft and GitNexus
together and pay to build two overlapping graphs of the same code — same guidance #117 gave for
GitNexus/Graphify. This issue does not resolve which of GitNexus/graft the project should carry
forward (or whether both, clearly labeled); it names the overlap so a maintainer decides on purpose.
Why this belongs in Agentic Kit
graft's upstream CLI already provides the same shape of managed-companion primitives #114/#115/#117
established as the pattern:
@nanonets/graft, with a singlegraftbin;graft init --dry-run/--agents <ids>/--yes/--no-global/--no-mcp/--no-hooks/--no-build/--all-agents/--list-agents— a scriptable, non-interactive wiring surface withno-TTY-writes-nothing-by-default behavior (CI/Dockerfile-safe out of the box);
graft check --json— a drift/freshness report Agentic Kit can parse without guessing;graft version(installed + latest npm) and a documented, single self-update command(
graft upgrade) Agentic Kit should own rather than let the user or graft's own nudge driveindependently — see
docs/MANAGED-TOOLS.mdinvariant 2 and checklist item 4;.claude/settings.jsonand every shared instructionfile, matching this repo's own ADR-0023 fail-closed / no-clobber expectations;
proposal.
Current Agentic Kit architecture
The seams #114/#115/#117 already document apply unchanged:
src/commands/setup.mjs— machine phase installs enabled global tools/hosts; project phase (ak setup --project, or automatically when.gitexists in cwd perdocs/SETUP.md) performsper-repo wiring. graft's own
init/machine split maps directly onto this existing boundary —arguably more cleanly than any prior companion, since graft's upstream CLI already separates "get
the binary" (
npm install -g) from "wire this repo" (graft init) the same wayak setupalreadyseparates machine and project phases.
src/commands/status.mjs,src/commands/sync.mjs,src/commands/uninstall.mjs,src/lib/versions.mjs,src/lib/adapters/lifecycle.mjs,tests/kit/adapter-lifecycle-conformance.test.mjs,docs/MANAGED-TOOLS.md,docs/ddd/integration-management.md— same contract described in feat: manage deja-vu as an optional cross-host session-memory companion #114/feat: manage GitNexus as an optional local code-intelligence companion #115/feat: manage Graphify as an optional multi-modal knowledge-graph companion #117.SQLite bindings under npm 12") is a direct analog to graft's native tree-sitter dependency tree
(
tree-sitter,tree-sitter-go,tree-sitter-java,tree-sitter-python,tree-sitter-typescript,plus
tree-sitter-wasms/web-tree-sitteras a WASM path) — this needs the sameclean-machine/cross-platform install proof ADR-0023 already requires, not a new standard.
[mcp_servers.ruflo]in~/.codex/config.toml(see this repo's own CLAUDE.md). graft'sinitwrites
[mcp_servers.graft]into the same file. Two independent writers touching~/.codex/config.tomlis a new collision class this proposal must design around explicitly — seeRisks.
Goals
ak setup(machine phase) or through an explicit config change.@nanonets/graft@latestglobally via npm — the same lane ruflo/agentic-qe/hosts alreadyuse; no dependency on feat: reusable mise-backend-aware install-method classifier for managed/companion tools #116's mise-backend classifier unless disk evidence later shows a
mise-installed graft on some user's machine (unlike feat: manage GitNexus as an optional local code-intelligence companion #115, nothing here requires it as a
prerequisite).
graft initonly during project setup (ak setup --project, or wherever project setupalready triggers per
docs/SETUP.md), non-interactively, usingak's own already-resolved enabledhost set to drive
graft init --agents <ids> --yes.graft build(structural, $0) on first wire; treatgraft build --deep(LLM-enriched,costs tokens under the user's own key) as a separate, explicit opt-in — never triggered by setup or
sync automatically.
~/.codex/config.toml,~/.codex/hooks.json, the hookshim) under explicit Agentic Kit control: default to
--no-globalwhen wiring the Codex/agentshost during project setup, and let a separate, explicitly-opted-in flag hand that scope to graft
instead of silently letting two tools race on the same file (see Risks).
(
graft check --json), and degraded states inak statusand the Dashboard.ak syncthe single owner of the npm package update (perdocs/MANAGED-TOOLS.mdinvariant 2)and of wiring/graph drift repair — reusing graft's own idempotent
graft initreplay andgraft check/graft buildrather than reimplementing graft's wiring-diff logic.(
~/.graft/update-check.json, spawned from CLI/hook/MCP entry points) as the "auto-updatemachinery"
docs/MANAGED-TOOLS.mdchecklist item 4 requires Agentic Kit to detect and own, soak status/ak syncremains the single drift story (invariant 4) rather than a second nudgesurfacing independently inside a live agent session.
ak uninstall; preservegraft/'s localcache,
graft/.cache/wiring-stamp.json, and any user notes appended below a node's generated blockunless the user explicitly requests a data purge.
except the npm install itself and the optional, explicitly-triggered update check), cross-platform
(native tree-sitter bindings must be proven on Linux/macOS/Windows, per the ak setup ships ruflo without native SQLite bindings under npm 12; ak dual run then fails with a native↔WASM memory conflict #45 precedent), and
testable against the shared adapter-lifecycle harness.
Non-goals
graft build --deep(LLM-enriched nodes) by default, or ever triggering it fromak setupor
ak syncautomatically.replacement.
graft initmutate~/.codex/config.toml/hooks.jsonby default when AgenticKit already owns Codex MCP bridge wiring in that same file — see Goal 5 and Risks.
install is detected and labeled external, never auto-updated (same rule feat: manage deja-vu as an optional cross-host session-memory companion #114/feat: manage GitNexus as an optional local code-intelligence companion #115/feat: manage Graphify as an optional multi-modal knowledge-graph companion #117 already set).
scope; this issue does not require it to land first).
graft/'s markdown nodes or wiring graph into AgentDB/Ruflo memory. graft's local filesremain graft's own regenerable cache.
graft build --lsp's optional compiler-grade edges(rust-analyzer, clangd, gopls, pyright, typescript-language-server); best-effort/user-provided only.
Primary use cases
1. Global install, zero repo footprint until opted in
ak setup --with-graftinstalls@nanonets/graftglobally. No repo is touched. A user can runak setupon a fresh machine and never see agraft/directory appear anywhere until they explicitlyrun project setup somewhere.
2. Project onboarding wires it in one step
ak setup --projectin a repo the user has opted into graft for runsgraft init --agents <ak's enabled hosts> --yes, builds the structural graph once, and verifies it — no manual per-hostconfiguration, matching #114's use case 1.
3. Fresh answers without a reindex step
A teammate pulls a large upstream change. The next
graft ask/MCP call re-stats the tree and rebuildswhat moved automatically ($0, ~ms) — no
ak syncor manual reindex is required for correctness;ak syncexists for package/wiring drift, not for keeping the graph fresh turn-to-turn, which graftalready owns end-to-end.
4. Drift repair
The npm package is upgraded, a host's wiring file goes missing, or
.claude/settings.json's graftblock is stripped by an unrelated edit.
ak statusreports the observed problem viagraft check --jsonplus host-file presence checks;ak syncperforms the smallest owned repair by replayinggraft initwith the recorded host set and flags.5. Safe Codex coexistence
A user enables both the Codex host and graft. Setup defaults to
--no-globalfor graft's Codex wiringso Agentic Kit's own
[mcp_servers.ruflo]entry in~/.codex/config.tomlis never at risk of beingoverwritten or duplicated by a second independent writer; graft's Codex integration is limited to
AGENTS.mdunless the user explicitly opts into graft's own global hook/MCP registration.6. Clean removal
ak uninstallremoves only Agentic Kit-owned wiring by default.--remove-graftalso removes theowned npm package after confirmation.
graft/'s local cache and any user notes under generated nodeblocks survive unless a separate, confirmed purge flag is passed.
Product principles
named above rather than silently building two graphs of the same code.
graft build --deepis nevertriggered by any Agentic Kit-driven path without explicit opt-in.
already has enabled, via
--agents, never--all-agents.~/.codex/writesdefault off; enabling them is a distinct, disclosed choice, not a side effect of enabling graft.
ak syncupdates the npm package; graft's owngraft upgradeisnever invoked by Agentic Kit, and graft's own background update-check nudge is detected and
suppressed so it can't disagree with
ak status.graft check --json,graft version, the package on disk,and per-host wiring-file presence; never infer healthy from process exit alone.
or removed.
graft/'s local cache/notes are different deletion scopes.initis alreadyidempotent and replays the exact flags a prior wiring was given (recorded in
graft/.cache/wiring-stamp.json); Agentic Kit's sync adapter should drive that mechanism ratherthan hand-roll its own wiring diff.
graft check --jsonpayload, an unqueryable version, or apartially-wired repo is degraded/unknown, never reported healthy by default.
Proposed user experience
Setup
Interactive setup should default to No and, before mutation, explain:
the enabled agent hosts' instruction files (and, for Claude Code, a statusline + hooks);
explicit choice under the user's own provider key;
AGENTS.mdonly unless the user explicitly opts graft into its own~/.codex/writes, which are machine-wide and shared by every repo.Status
The collector should distinguish: absent; present-external; present-owned; package update available;
per-host wired vs missing; wiring-stamp version behind the installed binary (graft's own signal);
graph fresh/stale/missing per
graft check --json; whether Codex global wiring is enabled and bywhom; doctor/version check unavailable → unknown, not healthy.
Sync
ak syncshould:@nanonets/graftvia npm only when enabled — never callgraft upgrade;graft/.cache/wiring-stamp.jsonfor the currently-recorded host set and flags, union withwhat's actually on disk (mirroring graft's own
reconcileWiringlogic), and replaygraft init --agents <that set> --yesplus the recorded--no-global/--no-mcp/--no-hooksflags — reusinggraft's own idempotent writer rather than diffing files by hand;
graft build(never--deep) only whengraft check --jsonreports drift beyond what thequery-time auto-refresh already handles (e.g., after a fresh clone with no
graft/yet);graft check --jsonplus host-file presence, never trusting apply's exitcode alone;
ak's own drift read remains authoritative.Repeated sync must be a true no-op.
Removal
Default uninstall preserves
graft/'s local graph and any user notes below a node's generated block;an external install is never touched; a data purge never runs unless separately confirmed.
Configuration and ownership model
Extend the existing versioned integration envelope (#114's precedent), not a new top-level boolean:
{ "integrations": { "version": 3, "tools": { "graft": { "enabled": true, "deep": false, "hosts": ["claude", "codex"], "codexGlobal": false } }, "ownership": { "graft": { "install": { "method": "npm", "package": "@nanonets/graft", "managedBy": "agentic-kit" }, "wiredHosts": ["claude", "codex"], "wiringOpts": { "global": false, "mcp": true, "hooks": true } } } } }Must preserve: desired enablement; deep-enrichment opt-in; desired host set; whether graft's own
Codex-global writes are permitted; observed install method/ownership; the exact wiring opts last
applied (so sync's replay matches what the user actually chose, not
graft init's all-true default).Migration is additive; existing configs default to disabled/unowned.
Proposed architecture
Managed companion adapter
src/lib/graft.mjs— package/version read,graft check --jsonparsing, wiring-stamp read(
graft/.cache/wiring-stamp.json), host-file presence checks.src/lib/adapters/graft.mjs— detect/plan/apply/verify/undo against the shared lifecycle contract.Do not add graft to
HOST_REGISTRYorPROVIDER_REGISTRY— same rule as every prior companion.Lifecycle contract
detect — read desired config; resolve npm install state (disk-first, per invariant 1); parse
graft check --jsonand the wiring stamp; inspect enabled-host wiring files (marker-fenced sectionsplan — deterministically compute package install/upgrade, wiring replay (host set + opts diff),
graph (re)build (only if
graft checkreports drift beyond query-time auto-refresh), and undooperations; disclose every host-file/
.claude/settings.json/Codex-global mutation before it happens;no-op for disabled or externally-owned state.
apply — install the npm artifact; invoke
graft init --agents <ids> --yeswith the recordedwiring opts (defaulting
--no-globalunlesscodexGlobalis explicitly enabled); rungraft build(never
--deepunlessdeep: trueand a provider key is confirmed present) only when planned; recordownership receipts only after verified success; report
ok/degraded/failed/skipped.verify — independently re-run
graft check --json; observe actual host-file state; never trustapply's exit code as proof.
undo — reverse order: Codex-global entries (if owned) → per-host wiring → npm package; preserve
external installs and user-modified wiring; retain receipts on partial failure.
Phased implementation plan
Phase 0 — ADR alignment and the GitNexus disposition call
clearly-labeled-alternatives) — this phase does not proceed to build without that decision on file.
~/.codex/config.tomldual-writer boundary (Goal 5) as a documented invariant, not justa default flag value.
QA gate: ADR is current; the GitNexus/graft disposition and the Codex-global-writer boundary are
both written down before Phase 1 starts.
Phase 1 — Detection and normalized facts
npm-global, matching the existing lane, not feat: reusable mise-backend-aware install-method classifier for managed/companion tools #116'sclassifier by default).
graft check --jsonandgraft/.cache/wiring-stamp.jsonfixtures, including malformed/missing/stale cases.
--agentsids (agents→Codex,claude,gemini, …).makes.
QA gate: every classification outcome (absent / external / owned-healthy / owned-drifted /
malformed-check / missing-stamp) is fixture-covered and honestly labeled.
Phase 2 — Setup and installation (machine phase only)
--with-graft/--no-grafttoak setup; persist opt-in intent; install the npm package.for, and it should be provably true (a machine-only setup run leaves zero
graft/directoriesanywhere).
QA gate: clean-machine
ak setup --with-graft(no--project) installs the binary and touches norepository; hermetic on Linux/macOS/Windows including native tree-sitter binding resolution (#45
precedent).
Phase 3 — Project wiring under
ak setup --projectgraft init --agents <ids> --yes(structural build only) into project setup, gated on Goal 5's--no-globaldefault for Codex.graft init --dry-runreports before writing.graft check --jsonbefore recording success.QA gate: project setup with graft enabled produces the expected host files and a fresh graph; a
Codex-enabled run with
codexGlobal: falseleaves~/.codex/config.toml's[mcp_servers.ruflo]entry byte-identical.
Phase 4 — Sync, upgrades, and drift repair
stamp-replay mechanism; rebuild only on
graft checkdrift, never on a timer.case (Goal 8).
QA gate: two consecutive syncs cause zero additional writes; status/JSON/Dashboard/plan agree;
graft's own update nudge never appears alongside a disagreeing
ak statusline in a fixture session.Phase 5 — Safe removal, data purge, documentation
graft/+graft/.cache/purge.QA gate:
pnpm run checkpasses; install → user drift → uninstall preserves user changes;uninstall on a never-managed machine creates or removes nothing.
Test strategy
Adapter conformance
Shared lifecycle harness: read-only detection, deterministic planning, non-mutating dry-run, idempotent
apply, observed verification, ownership-scoped undo, honest degradation on malformed/unavailable
graft checkoutput.Installation matrix
ak setup --with-graftinstalls npm package onlygraft initwith recorded optsgraft checkreports drift--deepfailed, never greenCodex dual-writer matrix
codexGlobal: false(default)~/.codex/config.toml/hooks.jsonuntouched by graft; graft wiring limited toAGENTS.mdcodexGlobal: true(explicit opt-in)[mcp_servers.graft]/hook entries added without disturbing Agentic Kit's own[mcp_servers.ruflo]entrycodexGlobal: trueownershipData and privacy tests
--deepnever runs without explicitdeep: trueand a confirmed provider key;graft/'s notes and cache;Acceptance criteria
replacement.
ak setup --with-graft(machine phase) installs the npm package and touches no repository.graft initruns only under project setup (ak setup --project, or wherever project setupalready triggers), scoped to Agentic Kit's own enabled host set via
--agents/--yes.agentswiring defaults to--no-global; graft's own~/.codex/config.toml/hooks.jsonwrites require a separate, explicit opt-in and never disturb Agentic Kit's own
[mcp_servers.ruflo]entry.graft build --deepnever runs without explicit opt-in and a confirmed provider key.ak status/JSON distinguish presence, ownership, install method, version drift, per-host wiring,graph freshness (
graft check --json), and Codex-global-write ownership.ak sync --dry-runis non-mutating; repeatedak syncis idempotent.ak syncis the only caller ofnpm install -g @nanonets/graft@latest; Agentic Kit never invokesgraft upgrade.drift story in
ak-managed sessions.graft/and its notes surviveunless a separately confirmed purge is requested.
both would be enabled together, not silently allowed.
precedent).
pass.
pnpm run checkpasses.Success measures
ak setup --with-graft+ak setup --projectpair.~/.codex/config.tomlnever shows a diff attributable to graft unless theyexplicitly opted into
codexGlobal.graft/by default.later as duplicated cost.
Risks and mitigations
ak's Codex bridge, graft's owninit) racing on~/.codex/config.toml/hooks.json--no-globaldefault for graft's Codex wiring; explicit opt-in required to hand that scope to graft; Codex dual-writer matrix test (above) as a named regression guardak status's drift read inside a live agent sessiondocs/MANAGED-TOOLS.mdchecklist item 4; suppress/ignore rather than let it stand as a second source of truthstatusLineentry; graft's own live statusline could collide with an existing kit- or aqe-owned statuslinestatusLineentry before wiring graft's; surface the conflict rather than silently overwriting (this needs its own design decision in Phase 3 — flagged here, not resolved)mise ls --json; treatgraft check --json's shape as versioned, not assumed-stablegraft build --deepaccidentally triggered by an automated path, incurring unexpected LLM spend under the user's keydeep: trueconfig gate plus a provider-key presence check before Phase 3/4 ever run it; never triggered by setup/sync defaultsDefinition of done
This issue is complete when a user can install graft's binary during
ak setup's machine phase withzero repository footprint, wire it into a specific project only via
ak setup --project, haveak syncown every subsequent update and wiring/graph-drift repair (reusing graft's own idempotentreplay mechanism rather than duplicating it), see accurate presence/ownership/freshness state in
ak statusand the Dashboard, safely coexist with Agentic Kit's own Codex MCP bridge without either toolclobbering the other's
~/.codex/config.tomlentry, and cleanly remove everything Agentic Kit owns —while the GitNexus/graft overlap this issue names has been deliberately dispositioned by a maintainer,
not silently absorbed.