Repository navigation
Graft now looks after itself: the agent bootstraps a project's memory, keeps it in sync with the files it came from, and maintains it without asking you. Install from the Claude Code or Codex marketplace, and eight bugs found in review are fixed.
Added
- Zero-touch lifecycle. After
/graft-initthe agent runs graft on its own: the rule it writes (and thegraftskill's new Lifecycle section) has it bootstrap a project progressively the first time it meets it, recall before substantial work, supersede a note the code contradicts on the spot, save durable knowledge after the work (with--source file:when it comes from a file), and do maintenance only when it is due and only a bounded batch, without asking the user in the normal path. The newgraft status [--root DIR]gives it everything in one cheap JSON (well under a second, never starts the daemon): the project's bootstrap state,maintain statuswhen a daemon is running, the changed / removed sources as of the last scan, and anextlist of housekeeping steps (bootstrap,apply-safe,resolve,refresh-sources,scan) with priorities. The Claude Code plugin adds two hooks run by the binary itself (graft hook session-start|prompt): a one-line housekeeping hint at session start, and the note of aSTRONGmatch injected as context on each prompt. Both never start the daemon, stay silent on any failure, and can be turned off withGRAFT_HOOKS=0orGRAFT_HOOK_PROMPT=0(#6). - Project bootstrap.
/learn bootstrap [path]builds a new project's memory unattended: no plan to approve, no node cap to choose. It maps the project into topics (docs, build manifests, configuration, public contracts, the implementation, optionally the local commit history), ranks them by importance with the area of the current task first, and spends a bounded budget per run on distilled knowledge nodes (decisions, invariants, module boundaries, procedures, gotchas, contracts), never file summaries, generated code or secrets, with keywords reconciled against the graph, duplicates skipped and every node linked to its files with--source. Re-runs only revalidate what changed and continue with the pending topics. The coverage state lives in the new CLI-onlygraft project status|mark|reset(topic map, runs, files backing nodes), which never starts the daemon (#3). - Autonomous maintenance.
graft maintainsplits graph upkeep between Graft and the agent.apply-safedoes the mechanical part on its own: theconsolidatepass, collapsing exact duplicates (same title and body, oldest kept, the others superseded), purging retired nodes after a retention window, and recording the run.scanreports what needs judgment as candidates with deterministic ids, evidence and suggested actions (near duplicates, possible supersessions, contradictions, file sources that changed or disappeared, keyword spelling variants, isolated never-read notes) without touching the graph; it re-hashes the project's file sources likesources diff, and its work is bounded (--limit,maintenance.*knobs). The agent checks each candidate against the current code and applies one narrow action withresolve(keep,stale,retire,restore,supersede,merge,refresh, ...).keephides a candidate until its evidence changes, so repeated scans converge.retireis a reversible soft delete: retired nodes vanish fromquery/retrieve/exploreand can be restored untilmaintenance.retention_days(default 30) elapse. Every resolution goes to an audit log (graft maintain log), andgraft maintain statusgives agents a cheap view of pending work and inserts since the last run.graft getnow shows the node'sstate. Thememory-auditskill drives this loop, and the MCP server exposes it asgraft_maintain_*tools. (#5) - Memory provenance.
graft insert --source <locator>(repeatable:file:<path>,url:<url>,conversation,manual) records where a memory comes from. File sources are stored relative to their project root with a BLAKE3 fingerprint and a project id (the normalizedoriginremote, else the root path), so one profile shared across repositories never confuses twoREADME.md. Re-inserting identical content attaches the new sources to the existing node.graft sources diff [--root DIR]re-hashes the recorded files and lists each as unchanged / changed / removed with the memories it supports;graft sources refresh <id>stores the new fingerprints after a memory was revalidated, without touching its content.graft getshows the sources, which survive export/import,profile mergeand remote sync. Also accepted byPOST /v1/insertand the MCPgraft_inserttool. (#4) /learn docs [path]ingests all the documentation of a repository (README,docs/, ADRs, guides, CONTRIBUTING, ARCHITECTURE) and nothing else: no issues, PRs, comments or web pages. Discovery is deterministic (tracked files only, skipping vendored, generated and submodule trees, licenses and agent instruction files), each document is distilled into retrieval-shaped nodes deduplicated against the graph, large doc sets run in bounded, resumable batches, and with--sourceprovenance a re-run only processes new or changed documents (#15).graft query --explainlists every candidate the verifier scored, in vector order, with its rank, hit level and signals, to see why a question got the answer it did.- Plugin marketplace for Claude Code and Codex. The repo is now a marketplace for both agents:
/plugin marketplace add AEndrix03/Graftthen/plugin install graft@grafton Claude Code,codex plugin marketplace add AEndrix03/Graftthencodex plugin add graft@grafton Codex. The plugin carries the six skills (namespaced asgraft:<name>) and updates through the marketplace. /graft-initinstalls thegraftCLI when it is missing, after asking, by running the official installer; offersgraft upgradewhen the CLI is older than the plugin; and offers to remove skill copies left by an oldergraft setup, which would otherwise show every skill twice.bench/: reproducible benchmarks.run.pymeasures recall quality and latency on a private daemon with built-in defaults, over 65 notes and an independently written held-out question set (the author's dev set is kept apart and reported as optimistic).agent.pyasks Claude Code the same questions with and without graft and grades the answers, reporting right and made-up answers, tokens and time.charts.pyrenders the README charts from the results.- The installers write a minimal
config.yaml(just the paths that depend on the install location) instead of copying the 403-line example. Built-in defaults cover the rest, so tuning improvements in later releases reach existing installs;config.example.yamlships alongside as the documented reference. - One-line installers at the repo root:
install.sh(Linux/macOS) andinstall.ps1(Windows). They download the prebuilt release archive for the platform, verify it against the publishedSHA256SUMSand refuse to continue on a mismatch, extract into~/.graft, fetch the BGE-M3 model once, writeconfig.yamlwith absolute paths without overwriting an existing one, put~/.graft/binonPATH, and run a smoke check. No compiler, no submodules, no MSYS2. graft setupwith no argument now sets up every agent whose config directory exists on the machine, and the installers run it for you, so the only manual step left is/graft-initinside the agent.
Changed
- The skills moved from
integrations/standard/skillstoplugins/graft/skills, the single source for the plugin,graft setupand the release archives (installed layout unchanged).graft setupskips Claude Code and Codex when the graft plugin is installed there. - CI and the release
prepjob fail when the plugin manifests'versiondiffers fromVERSION. - GitHub Release notes now contain only that version's
CHANGELOG.mdsection instead of the whole file, and the release workflow refuses to start when the version has no dated changelog entry. graft setupinstalls skills and nothing else. All hook installation,settings.json/hooks.json/config.tomlmerging and instruction-file writing were removed from the binary (~290 lines, plus the shipped hook scripts). Agent wiring is done by/graft-initfrom inside the agent./graft-initasks one question (global or project) instead of four, and writes the rule toCLAUDE.md+.claude/rules/graft.mdon Claude Code, orAGENTS.mdelsewhere.- The
graftskill was rewritten around the prompter model: a near hit is useful, a miss is a gap to fill, short search-engine-style queries,classifyfor keywords, verify before trusting aSTRONG, supersede (graft maintain resolve) rather than delete a stale node, and a one-line end-of-turn recap. scripts/install.sh/scripts/install.ps1are nowscripts/build-from-source.sh/scripts/build-from-source.ps1- they build from source and are for contributors, GPU builds and platforms without a prebuilt archive.
Fixed
- On Windows a second daemon connection from the same process failed, and the CLI then auto-started a second
graftdon the same socket: closing a connection calledWSACleanupwithout resetting the "Winsock initialised" flag. - Concurrent daemon requests could interleave their SQLite transactions: every worker shares one connection, and
SQLITE_OPEN_FULLMUTEXserializes single calls, not aBEGIN IMMEDIATE ... COMMITsequence, so parallel inserts, consolidate or sync failed with storage errors or committed another request's half-done work. Every storage call now holds a mutex on the connection for its whole duration. Two identical inserts racing past the content-hash check now both return the same node, the second withduplicate: true, instead of failing (#7). graft profile merge --overwritecould delete graph relationships that existed only in the target. When the target held the same content under a different node id, the merge'sINSERT OR REPLACEdeleted the target node, and with it every edge and keyword link pointing at it, then re-created the node under the source id. The merge now maps each source node onto the target node with the same content hash (or id), updates its metadata in place, inserts only nodes the target lacks, and imports the source's edges, keyword links and embeddings onto the retained ids (#11).- Stopping the daemon while a request was in flight could crash it: client threads were detached and nothing waited for them, so shutdown freed the database, the models and the HTTP server while a request was still using them. The daemon and the HTTP server now count their client threads; shutdown stops accepting, shuts down the client sockets so an idle or half-sent connection cannot hold it up, and waits for the threads still working (up to 30 s per listener, after which it exits without freeing the state they use). SIGINT/SIGTERM no longer close the listening socket from the signal handler, which did not wake
accept()on Linux (#8). - Stopping the HTTP server hung forever on Linux, and with it daemon shutdown when
http.enabledis on: closing the listening socket wakes a blockedaccept()on Windows but not on Linux. The accept loop now waits inselect()with a 200 ms timeout and checks the stop flag. Every ctest test also has a 300 s timeout, so a hang fails CI instead of holding the runner for 6 hours. http.bind: localhostandhttp.bind: "::1", both documented as valid local binds, were rejected at startup: the server parsed the address withinet_addr, IPv4 numbers only. It now resolves it withgetaddrinfoand listens on IPv4 or IPv6, preferring IPv4 when a name resolves to both; the loopback check runs on the resolved address (#13).graft profile exportcopied onlygraft.db, so after a daemon crash it silently dropped memories committed tograft.db-walbut not yet checkpointed. Export and import now use the SQLite backup API: the snapshot includes the WAL, and an import can no longer have a stale WAL replayed over it (#10).- A keyword containing
,is now rejected. The content hash joins keywords with,, so["a,b", "c"]and["a", "b,c"]hashed alike and the second insert came back as a false duplicate. Existing hashes are unchanged; the CLI says to pass each keyword as its own--keyword(#12). - A
GRAFT_DB_KEYwith many single quotes overflowed a heap buffer when opening the database: each quote is doubled inPRAGMA key, but the buffer was sized for the key's own length. The statement is now built withsqlite3_mprintf(#9). - The source-build scripts ended by suggesting
graft insert --summary ... --detail ..., flags removed long ago: the request went out with an empty title and body and the daemon rejected it. They now print--title/--body, and the CLI refuses an unknown option or a known one missing its value (exit code 2) instead of silently ignoring it (#14). - Building from source on Linux and macOS works again:
src/cli/autostart.ccalled the POSIXmg_spawn_daemonwith the Windows-only process-handle argument added by the daemon log fix, so the CLI failed to compile on every non-Windows platform. - The MCP server pins
mcp<2. A freshpip install -e .pulledmcp2.x, whereFastMCPno longer exists, and the server refused to start with "mcp SDK not installed". - The daemon's startup failure reason now reaches the user.
graftdalready printed the real cause on stderr ("embed init failed", "storage open failed", "socket listen failed"), but on Windows it was spawned DETACHED with no stdio redirection, so the output was discarded and the CLI only said "socket did not become ready in 20000 ms". The spawned daemon now inherits a handle to the log on both platforms, the log lives at$GRAFT_HOME/graftd.logas the docs always claimed (it used to sit next to the binary), and a failed auto-start quotes the tail of it. - A daemon that exits during startup is detected immediately on Windows instead of after the full 20 s poll: a missing model now reports in about 1 second.
cteston Windows no longer fails with0xc0000139(STATUS_ENTRYPOINT_NOT_FOUND) for the six tests that import llama/ggml directly: CMake now prepends the llama.cpp build directories and the toolchain runtime directory to the test PATH. The CLI was unaffected because the linker drops its unused llama imports, which is what made the failure look like a code problem. 11/11 tests pass.
Removed
- The harness hook scripts (
query_inject.js,mark_candidate.js,propose_memoryze.js) are no longer installed bygraft setup; they stay available as an opt-in inintegrations/optional/hooks/, and the Claude Code plugin now ships its own prompt and session hooks.scripts/install-codex-hooks.*is gone. - The duplicated per-agent skill copies under
integrations/claude-code/skills/;plugins/graft/skills/is the single source.