Skip to content

Releases

Versions prior to v0.5.0 were released without written notes. See the commit history for changes in older versions.

v0.9.82026-09-03

Kivgraph v0.9.8 keeps Kivgraph-managed runtime integrations in sync after an update.

  • kivgraph update repairs a Kivgraph-managed stale supervisor when the installed unit uses a repairable legacy format, then verifies that the restarted supervisor is installed before continuing.
  • The update protects the supervised daemon process from generic stale process cleanup, including when a refresh or endpoint check fails.
  • Public supervisor restart behavior is covered by regression tests across the update and supervisor layers.

This release changes installed runtime integration behavior, not graph or schema data, so existing installations do not need to rebuild their graph. Install it through the stable channel or run kivgraph update --channel stable to follow the stable release stream.

v0.9.8-dev.12026-09-03

Kivgraph v0.9.8-dev.1 is a development prerelease for testing managed daemon refresh during updates.

  • kivgraph update repairs a Kivgraph-managed stale supervisor when the installed unit uses a repairable legacy format, then verifies that the restarted supervisor is installed before continuing.
  • The update protects the supervised daemon process from generic stale process cleanup, including when a refresh or endpoint check fails.
  • Public supervisor restart behavior is covered by regression tests across the update and supervisor layers.

This development release changes installed runtime integration behavior, not graph or schema data, so existing installations do not need to rebuild their graph. Install it explicitly and use kivgraph update --channel dev to follow the development release stream.

v0.9.62026-09-01

Kivgraph v0.9.6 makes development builds easier to install and keeps graph-backed searches reliable across agent worktrees.

  • scripts/install-dev.sh installs a checkout safely by verifying a local bundle, replacing only the executable atomically, and restoring the previous executable if a supervised daemon restart fails.
  • kivgraph update --channel stable|dev selects the update channel while prerelease installations follow the development channel by default.
  • The search gate recognizes wrapped and file-listing searches correctly and can identify a registered repository from a linked Git worktree, avoiding unnecessary blocking or missed graph-backed guidance.

No stored graph data changed shape, so requires_reindex is false: existing installations can upgrade without rebuilding their graph.

v0.9.72026-09-01

Kivgraph v0.9.7 keeps Kivgraph-managed runtime integrations in sync after an update.

  • kivgraph update refreshes the installed supervised daemon after replacing the bundle, so open chats continue reaching the new daemon without a manual reinstall.
  • The update refreshes Kivgraph-managed hooks, skills, and MCP registrations while preserving user-owned configuration, project-scoped entries, and unrelated integrations.
  • Endpoint migrations require durable Kivgraph ownership evidence, avoiding accidental replacement of ambiguous user configurations.

The update-runtime tests cover supervised daemon restart and owned hook, skill, and MCP refresh. The integration migration tests cover endpoint ownership and token replacement. The release validation passes go test ./... -count=1, make test-ladybug, and make landing-check.

This release changes installed runtime integrations, not graph or schema data, so existing installations can upgrade without rebuilding their graph.

v0.9.42026-08-31

Kivgraph can serve multiple graph profiles from one server. A profile keeps its own configuration, graph state, and indexing lock while sharing the server process, making it practical to work with several projects without running a separate daemon for each one.

  • Profile-aware MCP tools and CLI commands select the requested graph while preserving the existing single-profile configuration and commands.
  • The local index workflow is more reliable for project-local Go modules. Synthetic workspace paths now remain stable across project indexing runs.
  • Oh My Pi can install Kivgraph’s tool-use hook alongside the existing agent integrations, including the first-call guidance and session-scoped budget advisory.
  • MCP tool responses and project status are profile-aware, so callers can identify which graph answered a request and distinguish unavailable profiles from empty graphs.

Nothing stored changed shape, so requires_reindex is false: existing installations can upgrade without rebuilding their graph.

v0.9.52026-08-31

Kivgraph updates now restart the supervised daemon reliably when profiles are configured. The daemon publishes its endpoint at installation scope, where both lifecycle commands and integrations expect to find it.

  • kivgraph update replaces and restarts the supervised daemon instead of leaving the previous release running after an upgrade.
  • kivgraph mcp install reaches a profile-backed daemon without requiring --stdio or a manually copied endpoint file.
  • Profile graph data remains isolated while the installation continues to use one supervised daemon and one shared control endpoint.

No stored graph data changed shape, so requires_reindex is false: existing installations can upgrade without rebuilding their graph.

v0.9.32026-08-30

Kivgraph reports that it ran. The first-run ping designed in v0.9.2’s --introspection release, and received since by landing/src/install-report.mjs, now has a sender: serve and the daemon each report the event the first time a given version runs on a machine, and scripts/install.sh and scripts/install.ps1 report a second, independent one when they finish. One event, five fields, off the command’s own path — a goroutine bounded to two seconds, every error dropped, so a machine with no network runs identically to one with it. KIVGRAPH_TELEMETRY=0 turns both off before anything is written, and an opted-out machine leaves no local marker either, so opting back in reports the version actually running rather than nothing. The complete field list, what is never sent, and the incident that shaped the endpoint’s validation are documented at https://kivgraph.dev/telemetry/.

  • kivgraph index indexes the current project without a configured registry. It detects the project’s languages and runs a local, .kivgraph-scoped full rebuild; kivgraph index --full keeps its old meaning, the explicit rebuild over the configured registry.
  • Uninstalling is a command now, not a manual cleanup. scripts/uninstall.sh and scripts/uninstall.ps1 ship on every release, remove what the installer placed, and refuse to touch configuration or graph state they did not create.
  • mcp install asks before it provisions a daemon. A missing or stale supervised daemon used to appear silently; installing now prompts for consent, and --daemon or --stdio bypass the prompt explicitly. A busy 127.0.0.1:7788 resolves to another loopback port once, and that choice is persisted and reused rather than re-resolved on every command.
  • A supervised daemon now carries the PATH of the shell that installed it. Neither systemd nor launchd reads a shell profile, so a unit declaring no PATH silently lost a node installed through nvm or Homebrew — every TypeScript repository failed to index with nothing in the logs to say why. daemon install records that shell’s PATH on both backends now, and a resync that keeps failing stops retrying instead of rebuilding the whole corpus every six seconds forever.
  • Every one of the 98 published MCP tool arguments describes itself, including the nested objects of get_source and index_project. Schema description coverage was the cited reason behind a 3.4/5 mean tool score on Glama; a test now fails the next argument that ships without one.
  • A session is briefed on the first Kivgraph tool call it makes, not only at skill install. The advisory attaches the call budget through additionalContext and never refuses a call — gating the tools themselves would put friction on the one behaviour the gate exists to encourage.

Nothing stored changed shape, so requires_reindex is false: an existing installation upgrades without a pass.

v0.9.12026-08-28

Windows is a published platform. windows/amd64 joins linux/amd64 and darwin/arm64 on the release page, in the installer, in kivgraph update and in the MCP Registry entry. Nothing stored changed shape, so an existing installation upgrades without a pass.

  • The release publishes a .zip, not a tarball, because that is what the tools on that platform read. The archive is normalised to a fixed timestamp and a sorted entry list before packing, so two builds of one tag produce a byte-identical file; and it is checked for backslash separators where it is made, rather than leaving a reader to discover at install time that their packer wrote paths the installer refuses.
  • scripts/install.ps1 mirrors scripts/install.sh, check for check. The two implement one set of pre-extraction rules and a gate fails the build if either grows a rule the other does not have — a check that exists on the platform you use and not on the one you do not is how an installer stays wrong for a year. The installer also installs the Visual C++ redistributable, because kivgraph.exe does not start without it and Windows Update services the redistributable rather than any copy a bundle could carry.
  • kivgraph update works there. It looks for the platform’s own archive, reads a zip through the same containment, count and size guards the tarball reader uses, and replaces a bundle whose binary is still running — measured rather than assumed, because Windows keeps an executing image open and the rename that moves the old bundle aside is the step an update turns on.
  • The daemon has an owner. A logon task through Task Scheduler, at LeastPrivilege, matching what the launchd and systemd backends already do: every existing backend is a user agent, and a service would have been a different guarantee wearing the same name.
  • The socket and the worker’s pipe carry a DACL this process sets, rather than one inherited from wherever somebody pointed the state directory. Both say the same sentence once, in internal/privateobject.

Six defects were found by running the suite on a Windows host rather than by reading it, and every one of them was a check that reads as careful and answers the wrong question off Unix.

  • filepath.IsAbs is false for a rooted path with no volume. \sdk\x.dart and /outside/manifest.json are resolved by Windows against the current drive, so a validator that joined them to a repository root concluded they were inside it. In internal/workspace that guard is a security boundary, and it was returning nil for exactly the input it exists to refuse.
  • shlex.split deletes a Windows path separator, because it is a POSIX shell lexer and a POSIX shell treats a backslash as an escape. A configured Python analyzer arrived as C:toolsnodepyright-langserver, and the loader reported it as unavailable rather than as destroyed.
  • A file URI is not a file path. file:///c%3A/x.py hides the drive behind a percent-encoded colon, so the Python worker recorded 63 resolved declarations as TARGET_NOT_INDEXED and emitted no exact edge at all. The Dart loader had the mirror image: it built file://C:/x, in which the drive is the authority, and the analysis server rejected every request.
  • CreateProcess searches PATH but does not append PATHEXT, so a bare pyright-langserver was not found with pyright-langserver.CMD beside it — which is how npm installs it.
  • filepath.Base(path) == "dart" is false for dart.exe, so the SDK was launched with no subcommand, printed its usage and exited. Two of the three places that asked answered wrongly; the third already carried || == "dart.exe" beside it, which is the drift executable.BaseName now removes by asking once.
  • Claude Desktop ships as an MSIX package, and MSIX redirects a packaged application’s writes into its own container. It reads its configuration from %LOCALAPPDATA%\Packages\Claude_<hash>\LocalCache\Roaming\Claude\, not from the documented %APPDATA%\Claude — so kivgraph mcp install --target claude-desktop reported success and wrote a file the application never reads. Both markers that detected it were absent on a real Store install.

The last one arrived with a sibling: removing an MCP entry deleted our server and wrote the emptied mcpServers back as {}. The hook path already deleted an emptied section and said why — a remove should leave a file that looks like one nobody installed into — and only a configuration that existed beforehand, holding somebody else’s key, could show that the other path did not.

Two smaller things fall out of the same work and apply everywhere. A .gitattributes makes line endings a property of the repository rather than of whoever cloned it, so a Windows contributor no longer gets every shell script with CRLF terminators. And internal/durable states the fsync rule once where four copies had agreed with each other.

v0.9.22026-08-28

kivgraph serve --introspection publishes the complete MCP tool catalog before an index exists. It is for the inspectors and registries that read tool definitions to score a server and have nothing to read when the handshake publishes nothing. Nothing stored changed shape, and normal serve is unchanged.

  • It lists tools; it does not create one. Starting it publishes no generation, fabricates no empty graph and relaxes no disk-space check. Every read tool it lists answers INDEX_NOT_READY until a generation exists — graph_status reports an empty graph rather than refusing, as it always did — and index_project stays behind its consent gate, answering PERMISSION_REQUIRED without approval.
  • The definitions are the served ones, registered from the same place a published server registers them, so what an inspector scores is what a client gets. A second schema-only surface would have drifted from the first, and the score would have described a server nobody runs.
  • The handshake still says the graph is missing. What a client is told depends on whether a generation is published, never on this flag: telling it otherwise would route work to tools that cannot answer instead of to the command that repairs them.
  • Only serve has it, and a serve given it answers from its own process instead of relaying to a running daemon — the catalog being asked about is its own, and a daemon nobody asked for introspection would have answered a different question.

v0.8.12026-08-27

A gate in front of grep, and a skill you can actually change. Nothing stored changed shape and no pass has to run again: both additions read the graph that is already published.

  • kivgraph hook install registers a gate that runs before the agent’s own tools and refuses a search when the graph answers it better. It closes on one fact — two or more things declare the name, so a text search cannot separate what it finds — and that is the only threshold the measurements support. Over the six questions of benchmarks/mcp-token-cost the factor splits by how many things share a name and not at all by how many references a symbol has: the three we lose (DiscoverGo 0,83x, MergeAll 0,85x, CanonicalColumns 0,91x) are all unambiguous names, and the two we win biggest (Publish 6,42x, BuildPlan 1,92x) are the shared ones. A reference-count floor was written first and removed: the corpus has nothing above four references, so any number would have been invented.
  • The refusal names the call to make instead, and quotes the rows it is talking about, because a refusal without a next step is an obstacle rather than a redirect. KIVGRAPH_DISABLE_HOOK=1 runs one anyway.
  • Four clients host it: Claude Code, Claude Desktop, Codex and OpenCode. The first three read the same verdict off stdout, so one command serves them and only the file it is registered in differs. OpenCode gets a generated plugin, because its tool.execute.before returns Promise<void> and the only way to stop a tool there is to throw. Oh My Pi is the one that cannot: its own documentation calls its hook subsystem legacy.
  • It costs 2 ms on the path that allows and 5,6 ms when it asks the daemon, measured on this repository’s graph. Classification is pure and runs before the configuration is read, so nearly every call leaves by the first path. Every failure — unreadable payload, no configuration, a directory no registered repository holds, no daemon — writes nothing and exits 0. An explicit allow on that wire does not mean “carry on”, it means “skip the permission prompt”, so the gate never sends one.
  • kivgraph skill install now writes one file and links the clients to it. Three installed clients used to mean three copies and no source, which left the obvious question unanswered: what you do to change it. Editing one copy did not reach the others and the next install took it away. The canonical file is ~/.config/kivgraph/skills/kivgraph/SKILL.md, beside config.yaml, and one edit reaches every client.
  • An upgrade keeps that edit. Reinstalling is what an upgrade does, so install writes the canonical only when it is absent or still holds the shipped skill; skill status says when it carries local edits, and --force takes the shipped version back. A copy from an earlier install becomes a link without asking, because the bytes are the ones we would have written. Project scope still copies: that path is committed, and a link to an absolute path under one machine’s home would arrive broken on every other clone.
  • The desktop app is detected by the entry it actually ships. The Linux marker this repository looked for, claude.desktop, does not exist — the package installs com.anthropic.Claude.desktop — so mcp install and skill install were not detecting Claude Desktop either.

v0.8.22026-08-27

Two caches that were blind to a language, and a release that publishes itself to the MCP Registry. Nothing stored changed shape, and the two fixes correct themselves on upgrade rather than asking for a pass.

  • A Rust entry never invalidated, so the cache served facts from source that had been edited away. isFingerprintedSource listed nine extensions across four languages and .rs was not one of them, and neither Cargo.toml nor Cargo.lock was a manifest it knew. A Rust unit adds its workspace root as an input tree, so the walk matched no file at all and hashed the empty string — e3b0c442…b855, the same constant for every crate, before and after every edit. Editing a .rs file therefore invalidated nothing.
  • No reindex is needed, and the reason is worth stating rather than trusting. The stored fingerprint was the hash of nothing; the one this build computes is the hash of the crate. They differ, and a fingerprint that does not match is never taken for a hit, so the stale entry falls out on the first pass after the upgrade and the facts are produced again from the source that is actually there.
  • The extensions now come from config.SourceExtensions over SupportedLanguages, so a language the configuration accepts cannot be one the cache is blind to. Cargo.toml and Cargo.lock join the manifests, and the empty-tree hash is asserted by name so a tree that matches nothing cannot pass quietly again.
  • The watcher had the same shape of bug, in the other direction. isSource carried its own switch and knew Go, TypeScript and Rust, so a repository declaring Python or Dart — both of which this build indexes — had every source file skipped by the reconciliation scan. No change to a .py, .pyi or .dart file was ever a change the reconciler could see, and nothing asked for a reindex on one. The two bugs are siblings: the watcher missing a language means no reindex is asked for, and the cache missing one means a reindex that runs answers from a stale entry.
  • Both tables now live beside the SupportedLanguages that decides what a configuration may declare, and internal/agenthook — which carried a third copy and disagreed with the first — reads it too. A new accepted language arriving with no files is what the old bug looked like, and a test now refuses it. The aliases are keys of their own: a configuration saying py is as valid as one saying python.

Kivgraph is now published to the official MCP Registry as io.github.Luqueee/kivgraph, from the release itself.

  • Each release carries a second archive, kivgraph-<os>-<arch>.mcpb. The registry accepts npm, pypi, nuget, cargo, oci and mcpb packages, and a .tar.gz is none of them; four of the five alternatives would mean distributing Kivgraph a second way rather than describing the way it already is. Nothing is built twice — the .mcpb packages the same bundle directory, so the binary inside it is the same file, byte for byte, and both archives are attested.
  • The MCPB manifest runs server/bin/kivgraph serve, which is the command kivgraph mcp install already writes into a client configuration. Installing the bundle and installing the binary run the identical process.
  • The bundle is nested under server/ rather than flattened, because it already carries its own manifest.json — the provenance one — and flattening would put two different files at one path with one winning in silence. It also keeps the relative RUNPATH intact: the binary finds lib/liblbug.so beside itself, so the tree has to move as a unit.
  • The archive is reproducible, because a fileSha256 published to the registry stops describing anything otherwise. Two runs over one bundle produce the same digest, the extracted binary reports its version — which is what proves the relative RUNPATH survived packaging — and answers initialize and tools/list with its twelve tools over stdio.
  • One limitation is carried rather than hidden. A registry package has no field saying which platform it is for, so both platforms are sibling packages and only compatibility.platforms inside each archive distinguishes them. A client that picks the wrong one gets a binary that will not execute; there is nowhere in the current schema to prevent that, and shipping a single platform to sidestep it would be worse.

The benchmark harness also stopped reporting a maximum as a percentile. find_cross_repo_consumers failed a release at 11,6 ms and a pull request at 5,6 ms against a 5 ms limit, and neither number was a p95: the tests measured twenty calls in total and that operation is ten per cent of the workload, so the figure was the worse of two. At two thousand calls the worst p95 over fifty runs on a machine held at a load average near 37 is 0,067 ms, and the median is 0,048 ms — the limits were never tight, only the tail of a two-sample maximum was.

v0.8.02026-08-26

Requires reindex: run kivgraph index --full after updating. Until you do, a graph published by the previous version still answers, without this version's facts.

A tool for the question that names no symbol, a traversal that shows its route, and an index that no longer dies whole. Reindex after updating: the TypeScript loader reads more of a project than it did, and a published graph only grows when the pass runs again.

  • find_by_intent takes a plain-language description and returns ranked symbols — or, under view: "files", just the files to open. Measured against git grep -l -i on 24 questions over three repositories, none of which can contain an identifier of its own answer: the phrase alone finds 6 of 24, the phrase plus the identifier words a caller can guess finds 11, and naming repo as well finds 17, against 7 for the native search. A session costs the same either way — 0.96x, ceiling 1.09x — so the accuracy is free. It reads no code from disk: the term index is derived when the snapshot is read, in 22 ms, and nothing about the stored format changed.
  • trace_dependencies returns the path. It could say whether A reaches B; now it shows the route it took, so a claim of reachability can be checked instead of trusted.
  • A go.mod that holds no Go is not a failed index, and neither is a repository whose analyzer this machine lacks. Either one used to fail the whole pass: on a machine where a Hugo theme sat inside an indexed repository, a real index of five repositories produced nothing at all. Both are absences now — counted, named, and carried in index --full --json. Thanks to @Tutitoos for finding and fixing it.
  • TypeScript reads the project the compiler reads: a jsconfig as the project of a JavaScript package, an include entry naming a directory as the tree under it, and the source extensions the compiler accepts. On this workspace that is 22.299 symbols before and 32.419 after — +45 % — which is why this release asks for a reindex.
  • kivgraph audit inspects registered repositories without indexing them, and a bare kivgraph prints the command table instead of an error.
  • What an index could not load is now published, not just counted. All four languages carry not_loaded in the report and in the --json result; two of those counters existed and were printed nowhere. A language with no code reports zero symbols and so does a repository that could not be read, so a count that only lives in a log is a warning nobody has.
  • Details in docs/adr/0072-la-recuperacion-por-intencion-y-las-tres-senales-que-no-entraron.md and docs/adr/0073-la-prosa-no-paga-el-esquema.md.

v0.7.02026-08-25

kivgraph mcp install now registers a client against one daemon by default, and the daemon has an owner that starts it and restarts it. Nothing to reindex.

  • The daemon is the default registration. mcp install writes a url entry instead of a command, so every editor shares one process. On a workspace of 108.737 symbols with eight idle clients that is 11 MB of private pages against 80, and 61 against 328 while they are answering; peak is 26-29 MB against 179-186. --stdio writes exactly what the previous default wrote, and --daemon still parses.
  • An entry a previous install wrote is replaced, not refused. Switching transports leaves one registration and not two, without --force. An entry naming a different kivgraph installation still needs it.
  • kivgraph daemon install gives the daemon an owner — a launchd agent on macOS, a systemd user unit on Linux — keyed by state directory, so two configurations can hold two supervised daemons. daemon status and doctor report whether one exists; daemon remove takes it out. A platform with no supported supervisor says so instead of pretending it installed something.
  • kivgraph daemon --addr and --allow-remote work. They were declared in the flag set and printed by the help, and the daemon read them before they were parsed: it could only ever bind 127.0.0.1:7788. Anyone who passed --addr got the default port and no warning.
  • Three conditions still write the stdio entry, and each names itself: --scope project, because a url entry carries a token and that file gets committed; a platform with no supervisor; and a machine that has not run kivgraph init yet. None of them depends on whether a daemon happens to be running.
  • Details in docs/adr/0068-el-demonio-tiene-dueno.md and docs/adr/0069-el-demonio-es-el-defecto.md.

v0.6.02026-08-24

One process can now serve MCP to every editor you have open, and a server that nobody queries no longer pays for the graph. No reindex needed.

  • kivgraph daemon serves many clients from one process, over HTTP and a unix socket at once. kivgraph mcp install --daemon registers a client against it, writing a url entry instead of a command. HTTP is the door that matters: no MCP client configuration dials a unix socket. See Register with a client.
  • The graph is read by the first query that needs it, not at startup. On a workspace of 108.737 symbols, a server nobody asks anything holds 10 MB per client instead of 33, eight editors starting at once peak at 183 MB instead of 994, and a new client connects in 14–23 ms instead of 96–151. Measured in benchmarks/daemon-cost; with load the figures are unchanged. Details in docs/adr/0067-el-grafo-se-lee-cuando-alguien-pregunta.md.
  • An unreadable snapshot no longer kills the server at startup. It reaches a caller as INDEX_NOT_READY, and graph_status gains an optional snapshot_unreadable field naming the reason, so «could not be read» stops looking like «never indexed». Additive: a client that ignores it sees no change.
  • At eight clients the daemon costs 61 MB against 328 while answering, and 11 against 80 while idle. At one client it costs a couple of megabytes more than a plain serve, so it is worth running from the second client on.
  • Fixes: the daemon publishes its HTTP endpoint before binding the socket, so a client can no longer reach a daemon whose daemon.json does not exist yet; the unix socket is created with its mode already set, which is what made it work on bind-mounted filesystems; and the global help and shell completion now name the daemon’s --addr and --allow-remote.

v0.6.12026-08-24

Everything described under v0.6.0, which was tagged but never published: its build failed before the release step, so v0.6.1 is the first downloadable version of that work. Nothing to reindex.

  • The check that every release note names a real tag ran for the first time in this release and failed in CI while passing locally. CI checks out shallow and fetches no tags, so git tag returns nothing there — and an unreadable tag list is not evidence that a tag does not exist. It now skips and says so, instead of failing and pointing at the wrong thing. The check itself is unchanged wherever tags are present.

v0.6.22026-08-24

Everything described under v0.6.0, which is the first version of this work that actually publishes. v0.6.0 and v0.6.1 were tagged and both builds failed before the release step, so neither exists as a download. Nothing to reindex.

  • What failed was a check on this repository’s own release notes, not the product: it verified that every note names a real git tag, and it read that from whatever tags the checkout happened to carry. CI fetches none by default, and a checkout on a tag ref carries exactly one — the version being built, which is a partial list that looks complete. CI now fetches the tags, and the check skips instead of failing when it cannot tell a partial list from a complete one. Where the list is real it is unchanged.

v0.6.32026-08-24

Everything described under v0.6.0, which is the first version of this work that actually publishes. v0.6.0, v0.6.1 and v0.6.2 were tagged and every build failed before the release step, so none of them exists as a download. Nothing to reindex.

  • All three failures came from one check on this repository’s own release notes, never from the product. It verified that every note names a real git tag, reading that from whatever tags the checkout happened to carry: none by default, and exactly one — the version being built — when the checkout is a tag. fetch-tags cannot fix it either, because combined with a tag ref it makes git fetch the commit and the tag to the same place and the checkout fails outright. The check now runs where the tag list is real, a developer’s clone, and skips with a reason where it is not.

v0.6.42026-08-24

Everything described under v0.6.0, which is the first version of this work that publishes. v0.6.0 through v0.6.3 were tagged and every build failed before the release step, so none of them exists as a download. Nothing to reindex.

  • Three of those failures were one check on this repository’s own release notes, fixed in v0.6.3. The fourth was a test of the reconciliation tick that builds a published generation as its fixture: publishing enforces the production space policy — at least 15 % of the filesystem free — and the macOS runner had less. That is a precondition of the host, not of the code under test, so it now skips and names the reason instead of failing. It still runs, and still defends the invariant, wherever the host has the space.

v0.5.02026-08-22

Requires reindex: run kivgraph index --full after updating. Until you do, a graph published by the previous version still answers, without this version's facts.

A method now belongs to the type that declares it as its receiver, and that changes what a Go or Rust type reaches.

  • trace_dependencies on a Go struct or a Rust type now includes the reach of its methods. It did not before: a method is declared outside its type’s own span — func (h *T) M() in Go, an impl block in Rust — while a TypeScript class holds its methods inside its braces. The same question returned a complete answer for TypeScript and a silently incomplete one for the other two. Measured on the private benchmark corpus at depth: 1, a Go handler with nine methods went from 3 rows to 53, and a Rust type with two impl blocks from 2 to 18.
  • get_blast_radius is unchanged. A type’s own methods are not its consumers, so containment is not an answer to what breaks if you change it.
  • graph_status now reports schema_version_expected and schema_outdated beside schema_version, so a graph built by an older binary says so instead of leaving the comparison to you.

The canonical schema goes from 3 to 4. A generation published by the previous version still opens and answers normally — it is outdated, not corrupt — but it cannot carry facts its resolver never emitted, so a Go or Rust type’s reach stays incomplete until you rebuild it.