Repository navigation
Releases: Nodesify/astria
Releases · Nodesify/astria
Release list
v1.1.1
1.1.1 — 2026-10-06
Maintenance release; no user-facing behavior changes.
- Migrate the native-module packaging toolchain from
@napi-rs/cliv2 to v3.10.8: the napi config moves fromtriplesto flattargets(v3 rejects the duplicate target v2'sdefaultsexpansion produced) and the release workflow switches to the v3-onlycreate-npm-dirscommand. The generated platform packages were verified locally before the pipeline's first tagged run. - TypeScript 7.0.2 (native compiler) across
packages/astria-cliandpackages/viewer; typecheck, emit builds, the CLI test suite, and the viewer bundle were all verified on it. - Dependency and CI maintenance:
@types/node22.20.5, Rust crate and npm devDependency bumps, GitHub Actions pinned updates, and internal planning docs removed with dogfood output ignored. - The musl probe workflow now asserts the known rustc ≥ 1.99 condition (no cdylib without
-crt-static) instead of failing permanently viacontinue-on-error, so its check run is green while the workaround is needed and red the day rustc fixes it.
What's Changed
- chore(homebrew): sync packaging formula to 1.1.0 by @erictong0602 in #119
- docs(contributing): platform trusted-publisher bootstrap complete by @erictong0602 in #120
- docs(bench): record October 6 paired run vs Graphify 0.9.77 by @erictong0602 in #121
- chore(deps): bump Rust crates, npm devDeps, and GitHub Actions by @nodesify-technology in #123
- chore(repo): remove internal planning docs, ignore dogfood output by @nodesify-technology in #122
- chore(deps): bump @types/node to 22.20.5 (lockfile only) by @nodesify-technology in #124
- chore(deps): migrate @napi-rs/cli to v3.10.8 by @nodesify-technology in #125
- ci(musl-probe): assert the status-quo leg so red means red by @nodesify-technology in #126
- chore(deps-dev): bump typescript from 5.9.3 to 7.0.2 by @dependabot[bot] in #109
- chore(release): 1.1.1 — napi v3 packaging migration and dependency maintenance by @nodesify-technology in #127
New Contributors
- @dependabot[bot] made their first contribution in #109
Full Changelog: v1.1.0...v1.1.1
v1.1.0
1.1.0 — 2026-10-06
- Preserve qualified symbol boundaries and import paths when resolving references; ambiguous candidates remain unresolved and inferred bindings retain
RESOLVEDevidence. Extraction cache v15 refreshes previously flattened targets. - Prefer exact implementation definitions for code-oriented queries, with scope and source metadata contributing to ranking.
- Name communities from source modules and packages; reports separately orient production code, documentation, and tests/benchmarks/examples, with source links and explicit relationship evidence.
- Propagate authoritative database decoding errors in analysis, clustering, hyperedge construction, and reports rather than silently discarding rows.
- Add 24 reserved questions on pinned Requests and Commander sources, a bounded iterative search baseline, and separate retrieval/build cost and provenance records. The new corpus and methods have not been evaluated.
- Simplify the README workflow and align architecture documentation with snapshot caching and reference evidence.
- Speculative graph nodes no longer claim a source file. A
stuborreferencenode exists precisely because no file defined the name, so it has no source locus; it previously borrowed whichever file referenced it first. That fabricated a file location for unresolved globals (a loneimport rusqlitebecamehealth.rs -> <first file to mention rusqlite>), producing 743 phantom file-to-file dependencies on this repo, four file "cycles" that do not exist in the source, and a falseFile:line inexplain. A whole-graph invariant pass clears stale loci on every run, so an incrementalupdateheals graphs built by earlier versions.explainnow reports(no source locus — unresolved name, no single owner)instead of naming a file that does not own the symbol. - Fewer false positives from test files.
is_test_filedid not recognise__tests__/,.test.ts, or.spec.ts, so JS/TS test helpers were scored as production code: on this repo a test-onlyassert()ranked as the #3 hub andtest_hubs_skippedstayed0. Hub detection, dead-code candidacy, and file-cycle inputs now use the same corrected matcher. astria health --min-score <n>exits non-zero when the score is belown, so the command works as a CI gate; it previously always exited 0, which made the obvious threshold check silently never fire.astria merge-gatechecks the extraction ruleset (extraction-current) alongside age and HEAD coverage. A graph reused from an older extraction cache passes both of those while reporting facts the current build would extract differently; the gate now fails and points atastria update ..- Ranking surfaces ignore non-code nodes. Hub concentration,
file_cycles,report"Key Files", "surprising connections", and the local embedding layer all exclude speculative nodes, so similarity between two unresolved bare names is no longer presented as structure. - Ground-truth note: measured on this repository, the fix removes 743 fabricated file dependencies, 4 false cycles, and 1,302
similar_toedges that joined two non-symbols; retrieval quality on the golden set is unchanged by these edits (MRR 0.5979 before and after, byte-identical), so this is a correctness and honesty change, not a ranking change.
What's Changed
- chore(release): lockfile entry for win32-x64-msvc@1.0.12 by @erictong0602 in #116
- fix(release): restore musl cdylib under rustc 1.99 (-crt-static) + homebrew 1.0.12 by @erictong0602 in #117
- chore(release): 1.1.0 — graph-evidence honesty and CI gates by @erictong0602 in #118
Full Changelog: v1.0.12...v1.1.0
v1.0.12
[1.0.12] — 2026-10-04
Project-review backlog — 36 defects + 6 engineering improvements (3 October)
Source-backed review of every workspace crate and the CLI; findings and statuses in docs/project-review-2026-10-03.md.
- Security boundaries — HTML exports escape every
<in embedded graph JSON (mixed-case</SCRIPT>could terminate the data element); MCP configuration files are excluded from raw LLM enrichment (literal credentials can no longer leave the machine through a remote backend);bolt+s:///bolt+ssc://now ride rustls with scheme-preserving transport instead of silently downgrading to plaintext TCP; HTTP MCP enforces a whole-request deadline with per-read recomputation and exact loopback matching (127.attacker.exampleis not loopback);yt-dlpmedia downloads are resolved and vetted through the SSRF policy (-J --simulate) before any byte moves; URL classification parses host/path instead of substring-matching the whole URL. - Graph identity & integrity — node ids are case-preserving (
Foo/foostay distinct; matching stays case-folded), with duplicate-id disambiguation rewiring edges to the surviving definition and the extraction cache version advanced to v14 so pre-fix caches invalidate cleanly; automatic global tags check existing names before allocating (no more repo duplication/replacement); merge is atomic — edges reconcile, the database swaps with rollback, artifacts stage as.newand flip only after the swap, and the generation is stamped inside the transaction; global replace runs fully transactionally with relation reconciliation after commit. - Freshness & publication trust — every publication mints a generation stamp (
_meta.graph_generation,generation.txt,_metaingraph.json, report footer) so database, JSON, and report of one build are matchable and snapshot caches key on it; unchanged Google Workspace shortcuts re-check their remote revision instead of trusting shortcut bytes; the merge gate fails on git-detection errors instead of silently skipping its checks. - Semantic backend honesty — token reservations span the whole request+response with guard-based release and per-backend
max_tokenssharing the same constants (the advertised budget is reserved before the call, not audited after); content needing more than the chunk cap fails loudly (ASTRIA_LLM_MAX_CHUNKS) instead of truncating and caching as success; BedrockstopReasonis checked before accepting text; derived-text lookup validates against the extraction-hash family (config-hash lookups that never matched what extraction wrote are gone); malformed LLM replies never become cached empty successes. - Dependency advisories (release day) —
quick-xml0.37/0.39 → 0.41 andcalamine0.34 → 0.36 close RUSTSEC-2026-0194/0195 (quadratic attribute-check and unbounded namespace-declaration DoS in XML parsing, fresh in the advisory database when the release CI first ran); office-crate call sites moved to the 0.41 decoder API. - Everywhere else — XLSX decompression bounds are pre-checked via a bounded
<dimension>zip scan before allocation; non-ASCII document titles can't panic filename creation; watch mode covers every supported file type and directory renames; database decode errors surface instead of silently truncating graphs; Bolt 3 RUN carries its third (extra) field per the official spec; risk traversal propagates errors; the viewer bundle is drift-checked in CI; a version-to-version A/B harness ships inscripts/bench/ab/.
Follow-up review — publication, coverage, health, cache (3–4 October)
- Cache invalidation is part of graph publication — the generation advances inside the core transaction and immediately after every derived pass that commits a content change; unchanged runs reuse the previous generation;
cluster-onlyrepublishes through the same artifact workflow as full pipelines. - Merge-gate coverage is commit identity, not timestamps — the pipeline records
_meta.git_headat publication andverifySourceCommitcompares it with the current HEAD while re-hashing every manifest file (the graph's own versioned scheme); query headers disclose source drift (modified / deleted / size-changed) separately from graph age, and relative manifest paths resolve against the project root so probes work from any cwd. - Health-score heuristics corrected — containment and co-occurrence edges no longer count as reachability (dead-code detection finds real candidates again); hubs must clear max(10, the graph's own 95th-percentile usage degree), and test-file hubs are reported, not scored.
- Multi-project snapshot cache — the process-wide graph cache becomes a bounded LRU keyed by database path + generation (default 3 entries,
ASTRIA_SNAPSHOT_CACHE_ENTRIES1–16); alternating MCP projects share snapshots instead of evicting each other. - Retrieval evidence — the paired runner's report emits exact-symbol ranking (definition recall@5 + MRR) beside file recall and delivered tokens, plus a per-case definition-miss triage list; known failure modes are ranked as evaluation priorities.
- Documentation — architecture claims derive from the registry (language counts drift-checked by
scripts/check-docs-sync.mjs), the snapshot-cache description matches the LRU, and the review backlog carries per-finding status tables.
Platform & integration — team serving, cloud backends, CI artifacts (#B1–B5)
- MCP over HTTP + multi-project serving —
astria mcp --httpserves one or many project graphs over MCP Streamable HTTP (JSON responses;GET /healthzfor liveness) from a single process, complementing the stdio transport. Clients select a project with thex-astria-projectheader or?project=query (unknown names 404 — no silent fallback);--graphis the default project and--projects name=pathadds more. Bearer auth (--token/ASTRIA_MCP_TOKEN) is mandatory whenever the server binds a non-loopback host — unauthenticated remote serving is refused at startup. No async runtime: thread-per-connection, a fresh SQLite handle per request. Transport routing, auth, and project resolution are tested without sockets. - First-class Azure OpenAI, AWS Bedrock, and Kimi backends —
--backend azureauthenticates with Azure'sapi-keyheader against{endpoint}/openai/deployments/{deployment}(+ mandatoryapi-versionquery),--backend bedrockcalls the Bedrock Converse API with real SigV4 request signing (self-contained HMAC-SHA256 implementation pinned to independently computed reference signatures; static keys andAWS_SESSION_TOKENtemporary credentials both work), and--backend kimiis the OpenAI-compatible surface pointed at Moonshot with Kimi's key variables and default model. Bedrock's Converse usage format (inputTokens/outputTokens) joins the usage counter's understood wire formats. All three are documented in env-vars.md with their ASTRIA_* and vendor env names. - Rich PR dashboard —
astria prsnow pulls CI state (statusCheckRollup), review decision, mergeability, author, and diff size in onegh pr listcall, maps PR branches ontogit worktree listlocations, ranks the review queue by urgency (failing CI, requested changes, conflicts, graph blast radius, draft penalty), and prints merge-order risk on--conflicts.--triagegives compact per-PR lines;--jsonemits the ranked queue with every signal. - Git merge driver for the graph file —
astria merge-driver installwires a three-way union-merge driver into.gitattributes+merge.astria.*git config so parallel branches that both commit.astria/graph.jsonmerge instead of conflicting: additions from both sides survive, deletions are respected, fields resolve 3-way (unchanged side takes the changed side), and communities (derived data) resolve to whichever side moved..astria/graph_report.mdgets git's built-inuniondriver.uninstallremoves the wiring;runis the git-invoked entry point. - Docker distribution — a multi-stage Dockerfile in the repo root (Rust+Node builder → slim Node runtime) ships the full CLI with no toolchain inside; analyze a mounted repo or serve the HTTP MCP on exposed port 8620;
--build-arg NAPI_FEATURES=--no-default-featuresproduces a smaller image without the embedding runtime. - Hosted-tier OSS surface —
astria merge-gateis a CI check that fails on missing/stale graphs (publish timestamp vs wall clock and last commit), health-score floors, and diff blast-radius ceilings (--jsonfor pipelines);astria digestrenders a deterministic markdown engineering brief (overview, health, hub concentration, largest communities, LLM spend) for stdout,--out, or cron. These are the same primitives the hosted tier (app.graphify.com) operates for teams. - Deep-clean uninstall —
astria uninstall --purgeremoves every platform install plus the artifacts plain uninstall deliberately leaves: git hooks, merge-driver wiring, the project.astria/data directory, and the~/.astriaglobal store. Explicit-flag consent, no prompt, CI-safe.
Query & graph features (#C1, #C3, #C4)
- CJK query segmentation — the retrieval tokenizer now segments Chinese/Japanese/Korean runs with jieba (dictionary + HMM, built once per process), so "用户登录怎么处理" matches the labels that say 用户 and 登录 instead of arriving as one unmatchable character run. Non-CJK tokenization is byte-for-byte unchanged;
nearest_labelssuggestions now share the tokenizer (with stopword filtering), so did-you-mean works for CJK too. - Clustering controls —
astria cluster-only --resolution <0.0–1.0>requires a minimum share of a node's neighbors to agree on the winning community before the node joins it (default 0.0 = classic propagation; higher values → more, smaller communities, same direction as Louvain's resolution), and--exclude-hubsholds high-degree hub nodes (degree ≥ max(12, 4× mean)) out of label propagation entirely so they can...
v1.0.11
[1.0.11] — 2026-10-02
Code audit — data safety, installer ownership, native loading, CI and site
- DB migrations are atomic and self-healing — each schema step now commits its DDL and its
schema_versionbump in one transaction (SQLite DDL is transactional), and ALTER steps checkPRAGMA table_infofirst. Before, a crash between an ALTER and its version stamp left a database whose next open re-ran the ALTER, failed withduplicate column name, and bricked every later command against that repo; the idempotent guard also repairs databases the old code had already stranded. Regression-tested (interrupted_migration_is_repaired_not_fatal). - The installer no longer wipes unparseable configs —
readJsonused to swallow any JSON parse error and return{}, which the subsequent rewrite made permanent. A non-empty unparseable file now aborts the install with a refusal naming the path; a UTF-8 BOM is tolerated; and.vscode/mcp.json(officially JSONC — comments and trailing commas are legal) is parsed with a conservative comment/trailing-comma stripper so commented team configs install without losing their servers. All installer config rewrites (JSON, the Codex TOML, markdown sections, git hooks) now write via temp-file + rename, so a crash mid-write can never leave a truncated file — which is what previously turned into a wipe on the next install. - Uninstall removes only what install wrote — three ownership gaps closed:
removeAgentMcpdeleted anyastria/graphifyMCP entry regardless of authorship (a user-written entry with those names survived install's own preserve check only to be deleted on uninstall);removeSectiondeleted unmanaged## astriamarkdown sections that install correctly treats as user-owned, and its heading match was prefix-based, so## astria-guidewas caught too; and hook entries were claimed by bare substring — a user's ownastria hook-guard read --strictPreToolUse hook (the command our own docs suggest) was deleted byastria uninstall claude. MCP ownership now uses oneisInstallerServerpredicate across install/uninstall/legacy cleanup; markdown removal requires the managed marker; hook matching keys on the structural fingerprints every installer template carries (a quoted.astria/.graphifypath segment, or the pre-1.0 package name). - The updater hook is no longer appended to shell hooks — appending the JavaScript updater to a
#!/bin/shhook (a user hook, or a husky-style hook undercore.hooksPath) broke that hook with syntax errors on every commit while the graph refresh silently never ran; the old test asserted the appended file content but never executed the hook. Install now appends only to Node-script hooks and skips others with an explicit notice (a foreign Node hook still merges cleanly — both paths tested). - A missing native binary no longer kills the whole CLI — the platform-package
requirehad no try/catch (the crafted diagnostic was unreachable in exactly its target scenario), the musl switch arms require packages that were never published (Alpine was a guaranteed rawMODULE_NOT_FOUND), and the binding loaded at module scope, so evenastria install,astria uninstall, and--versioncrashed before Commander ran. Every require is guarded, the binding loads lazily on first native call, and the diagnostic names the resolved platform target and the musl limitation. - Bolt decoding bounds server-controlled sizes — PackStream list/struct lengths from a Neo4j server fed
Vec::with_capacityunbounded (a hostile LIST_32 length was an allocator abort, uncatchable across the napi boundary), and message deframing had no total-size cap; both are now bounded (element count clamped to remaining bytes, messages capped at 256 MiB with anInvalidDataerror). Hostile-input tests added for all three decoders and the frame cap. - Copilot's skill file installs where Copilot reads it — repo-scoped
.github/skills/in the project (docs.github.com), not~/.github/skills/; the test's own comment already said project-scoped while asserting the home path. Installs clean up the 1.0.9/1.0.10-era home-dir copy, and file-stem layouts (cline/roo) keep their identity guard so a second install still never deletes its own skill. - Smaller correctness fixes — unknown
--platformnow exits 1 (it printedUnknown platformand exited 0, so scripts could not detect the failure); uninstall readsCLAUDE_CONFIG_DIRthrough the same sanitizer install uses and removes both candidate skill roots (the raw env var previously reached anunlinkSyncunvalidated);npm run napi:dev -- --debugbuilds no longer lose to a stale release artifact (candidate order follows the profile just built); bench-snapshot's two pushing jobs are serialized (needs:— the concurrency group serializes runs, not jobs within a run, so one push used to lose the race) with permissions narrowed per job;promptfoois pinned (@0.123.1) instead ofnpx promptfoo@latestwith the judge API key in env. - Website truthiness — homepage language count corrected to 25 (the registry has 25; README already said 25); the 1.0.10 docs version cut and
lastVersionrefresh (default/docswas five releases stale at 1.0.5); release-notes blog posts for 1.0.9 and 1.0.10, which the sidebar's "Release notes" feed stopped at 1.0.8.
Distribution audit — four fixes
- Homebrew formula installed no executable —
std_npm_argsinstalls global-style intolibexec(package atlibexec/lib/node_modules, executables linked atlibexec/bin), but the 1.0.10 formula symlinkedlibexec/node_modules/.bin/astria— a local-install path that never exists underlibexec— and Homebrew'sinstall_symlinkover an empty glob is a silent no-op, sobrew install nodesify/tap/astria"succeeded" with noastriacommand. The formula now symlinkslibexec/bin/*(homebrew-core's idiom for npm packages) atrevision 1; the live tap carries the same fix. - The Claude Code plugin shipped without its MCP server — the plugin root is the repo root (marketplace
source: "./"), and its only MCP registration was the root.mcp.json, which is machine-local and gitignored — so marketplace installs delivered the skill, commands, and subagent but zero MCP servers, despite 1.0.9's "the tracked.mcp.json" changelog claim and the plugin's own description..claude-plugin/plugin.jsonnow declares theastriastdio server inline viamcpServers(the sameastria mcpentryastria installwrites), which ships with the tracked tree. Plugin and marketplace metadata move to1.0.11ahead of the npm package so version-caching plugin managers register the changed plugin — the npm package,server.json, and the registry listing stay at 1.0.10 until the next tagged release. - The release verify step checked versions only — the field that actually broke v1.0.9 (
mcpNamevsserver.jsonname, the 403 namespace case mismatch) was never compared, so a future drift would again surface only at the post-npm registry step where immutability makes it unfixable without burning a version. The step now verifies name vs mcpName, the npm entry's identifier vs the package name, and the per-package version, alongside the top-level version. - mcp-publisher is pinned and checksum-verified — the registry publish step downloaded
releases/latestand executed it with the job's OIDC and GitHub tokens, the only unpinned external code in a workflow where every action is SHA-pinned. Now pinned tov1.8.1with a sha256 check; moving to a newer publisher is a deliberate tag+checksum bump.
What's Changed
- docs: update documentation for astria 1.0.5 by @nodesify-technology in #86
- chore(bench): publish 1.0.5 benchmark snapshots by @erictong0602 in #87
- Release 1.0.6 — chunked document retrieval, cross-conversation ranking, introspection commands by @erictong0602 in #88
- ci: Node 24 action upgrades + runner label pinning by @nodesify-technology in #89
- Release 1.0.7 — judged semantics, drill-down viewer, scoped retrieval by @erictong0602 in #90
- Release 1.0.8 — RESOLVED provenance, code-aware embeddings, sixteen platforms by @erictong0602 in #91
- Release 1.0.9 — official MCP Registry publishing, Claude Code plugin marketplace, Homebrew tap by @nodesify-technology in #92
- Sync main with 1.0.10 — registry namespace fix, hardened release workflow by @erictong0602 in #93
- Sync main — distribution audit fixes: plugin MCP server, brew binary, release gates, pinned publisher by @erictong0602 in #94
- Sync main — full-repo audit: atomic migrations, installer data safety, lazy native loading, bolt bounds by @erictong0602 in ht...
v1.0.10
[1.0.10] — 2026-10-01
Distribution fix — MCP Registry namespace case
- v1.0.9 reached npm but not the registry — the official MCP Registry publish failed with 403: the GitHub OIDC grant is
io.github.Nodesify/*(the org login's case is significant) whileserver.jsondeclaredio.github.nodesify/astria. npm is immutable, and registry validation compares the published package'smcpNameagainst the server name exactly — so both move toio.github.Nodesify/astriain this release; 1.0.9's lowercasemcpNamecan never validate. Automated registry publishing, the Claude Code plugin marketplace, the Homebrew tap, andsmithery.yamlare unchanged from 1.0.9.
What's Changed
- Release 1.0.8 — RESOLVED provenance, code-aware embeddings, sixteen platforms by @erictong0602 in #91
Full Changelog: v1.0.9...v1.0.10
v1.0.9
[1.0.9] — 2026-10-01
Distribution — official MCP Registry, Claude Code plugin marketplace, Homebrew tap, Smithery
- Official MCP Registry publishing is automated — the repo now carries a registry
server.json(io.github.nodesify/astria, stdio transport over the npm package) andrelease.ymlpublishes it viamcp-publisherwith GitHub OIDC after the npm publishes succeed; theverifyjob fails fast whenserver.json's version drifts from the package version. npm packages must declare the matchingmcpNamefor registry validation — added topackages/astria-cli/package.json. The first listing goes live on the next tagged release. - The repository is a Claude Code plugin marketplace —
/plugin marketplace add Nodesify/astriathen/plugin install astria@nodesifyinstalls, in one plugin: the MCP server (the tracked.mcp.json), the graph-first skill (skills/astria/), two slash commands (/astriagraph queries,/astria-riskPR-ready risk report), and anastria-architectsubagent — wired through.claude-plugin/marketplace.json+.claude-plugin/plugin.json. - Homebrew tap —
brew install nodesify/tap/astriainstalls the published npm package; the formula ships in the newNodesify/homebrew-taprepo, with per-release update instructions inpackaging/homebrew/README.md. - Smithery registry config —
smithery.yaml(stdio start command over the published npm package, optionalprojectPath) so smithery.ai lists the server once the repo is connected there. - Discovery metadata — GitHub topics gained
claude-codeandagent-skillsalongside the existingmcp-server/model-context-protocolset.
What's Changed
- Release 1.0.7 — judged semantics, drill-down viewer, scoped retrieval by @erictong0602 in #90
Full Changelog: v1.0.8...v1.0.9
v1.0.8
[1.0.8] — 2026-10-01
Agent experience — staleness disclosure and MCP tools that teach their use
- Queries disclose a stale graph — the header now reports how many manifest files changed since the build (
# 3 file(s) changed since this build — run astria update before trusting answers), next to the existing# graph built atline. Edits through paths without hooks (Claude Code print-mode sessions — which provably do not run PostToolUse hooks — editors without them, plain typing) previously left agents confidently answering from the past unless they noticed a raw timestamp. The check is stat-only against the file manifest (no re-hashing): milliseconds per query even on large repos, and it clears itself on the nextupdate. Verified live: touch a file → disclosure appears;update→ fresh timestamp, silent header. - MCP tool descriptions now teach usage — the descriptions agents see when choosing tools:
query_graphexplains thefile:lineanchors, the provenance tiers, what "No confident match" means (rephrase toward symbol names — not an error), and that the header discloses staleness;explaindocuments the-->/<--real-direction arrows;affectedsays to run it before changing a shared symbol and how to read RESOLVED vs INFERRED hops. Verified through a live MCP handshake that the served descriptions carry the guidance.
Full ecosystem coverage — MCP for every coding tool, five new platforms, install --all
- MCP registration everywhere it is supported — joining claude/cursor/gemini/zcode: VS Code (
.vscode/mcp.json, native workspace MCP — covers every VS Code-based editor including Copilot inside it), Codex (~/.codex/config.toml, user-global TOML — the installer appends a managed[mcp_servers.astria]table and never touches a hand-written one), Trae, Windsurf, Kiro (.kiro/settings/mcp.json— Kiro's documented workspace-scope config), and OpenCode (.opencode/opencode.json). The Copilot coding agent gets skill + instructions only: it has no committed repo MCP file — repository-level MCP is JSON pasted into the repository Settings on github.com. All JSON flavors are project-scoped, idempotent, and merge-safe like the originals;uninstallremoves each, and configs an earlier build wrote at a since-corrected path are migrated away, never duplicated. - Verified against the real vendor CLIs and vendor docs, not just schemas:
codex mcp listshowsastria … enabled(Codex 0.140.0 parsing the appended TOML);gemini mcp listresolves the settings entry;opencode mcp listreports✓ astria connected— it actually launched the server;claude mcp listreaches the project.mcp.jsonserver (⏸ pending Claude Code's documented one-time project approval). Real-tool testing caught two OpenCode bugs schema-following would have shipped: opencode 1.17+ rejects apluginskey inopencode.json(the pre-existing plugin injector wrote one — plugins now drop into the auto-discovered.opencode/plugins/— the convention in opencode's current docs, and verified loadable by probingopencode debug configon 1.17.8, which resolves plugins from both the plural and singular directories — with no config key, and installs upgrade away both earlier layouts), and its MCP schema requires servers directly undermcpwith{type: "local", command: [...], enabled: true}— notmcp.serverswith astdioshape. It caught one in ours too: VS Code 1.137's own--add-mcpwriter uses a bareserversmap (nomcpServerskey, notypefield), so the vscode flavor now matches the vendor's writer exactly, migrating 1.0.8-era entries. User-customized entries are never touched in any flavor. The exact commands every config runs were also proven end-to-end: an MCP stdio handshake againstastria mcp(initialize → 10 tools → realquery_graph/affectedcalls). - Three install-path corrections from a docs audit of this repo's own agent integration (all caught before release, against vendor documentation): Kiro's workspace MCP config is
.kiro/settings/mcp.jsonper kiro.dev's configuration docs — not a bare rootmcp.json, which no Kiro version reads (the dead file a dev build had written is deleted on install/uninstall when it only carries our entry); OpenCode's documented project plugin directory is.opencode/plugins/(plural) — the singularplugin/still loads on 1.17.8 but is not the documented convention, so the installer writes the plural directory and migrates both legacy layouts; and the Copilot coding agent reads repository-level MCP only from repository Settings on github.com (confirmed in github/docs: "Configure MCP servers for your repository" — JSON entered in the Settings UI,mcpServersshape) — the.github/copilot-mcp.jsona dev build wrote is read by nothing and is cleaned up. The injected## astriainstruction block also caught up with the tool surface: it now names all ten MCP tools (it still said six, omittinggod_nodes,list_communities,graph_stats,health), and this repo's trackedAGENTS.mdis now itself a managed section (<!-- astria:managed -->) soastria installkeeps it in sync instead of treating it as user-owned forever. The repository's own tracked dead copies (rootmcp.json,.github/copilot-mcp.json) are dropped in the same change — every working per-tool config stays machine-local behindastria install, withAGENTS.mdand.github/copilot-instructions.md(GitHub's documented repo instructions file) the only tracked agent artifacts. - Six new platforms:
vscodeandwindsurf(MCP-only — no skill-file mechanism to target),cline(skill →~/.clinerules/, AGENTS.md),roo(skill →~/.roo/rules/, AGENTS.md),amp(AGENTS.md — Amp reads it natively), andpi— the Pi coding agent gets an auto-discovered extension (~/.pi/agent/extensions/astria.mjs, every API surface verified against pi 0.87's types) that registers the graph as native pi tools (astria_query,astria_map,astria_explain,astria_path,astria_affected, CLI-backed — pi's own philosophy is registered tools over MCP definitions: a few hundred context tokens vs 10k+), plus automatic graph refresh around tool calls and an/astriaguidance command. Freshness is mode-independent by measurement: pi 0.87 print-mode sessions never delivertool_resultevents to extensions (an instrumented listener captured zero events — not even for the extension's own tool calls), so every graph tool call itself triggers the throttled refresh, awaited until the update process exists before returning — the session exits the instant a tool returns, and an un-awaited detached child never materializes (both failure shapes measured). Verified end-to-end: the parent exiting immediately after the tool returns does not kill the update —graph_published_atadvances. The standard.mcp.jsonstays registered forpi-mcp-adapterusers at zero extra cost — the adapter reads it natively and was observed discovering the astria server. Fully standalone — no adapter required: verified in a pristine pi (--no-extensions -e astria.mjs, every other extension including pi-mcp-adapter disabled) where the extension loads and registers cleanly; pi's own provider serialization consumes plain JSON-schema parameters, which is exactly what the extension registers. All five tools executed through pi's AgentToolResult contract returning real graph data (the MODEL const, RESOLVED-tier blast radii, ranked repo map), and a project without.astria/gets a build-one-first hint instead of a raw CLI error. The full chain was then verified live with a real pi session (glm-4.7): the model called the nativeastria_querytool on its own and answered from the graph —jinaai/jina-embeddings-v2-base-codeatcrates/astria-embed/src/lib.rs:13-15, file:line anchor and all. The platform roster is now sixteen. astria install --all/uninstall --all— one run wires every supported platform; a single-platforminstallnow prints the remaining platforms so multi-tool users discover the rest. Previously the command silently defaulted to claude-only, and a Codex or Trae user who ranastria installgot the wrong layout without a hint.- Tests: the MCP flavor matrix grew from 4 to 9 parametrized JSON flavors (shape, idempotence, preserve-others, removal) plus dedicated OpenCode-shape/migration, Kiro legacy-path migration, Copilot legacy-file cleanup, Codex TOML round-trip (user-config preservation, never-clobber), and file-stem layout tests; install suite 292 assertions green.
Answer trust and first-rank retrieval — RESOLVED edges, honest directions, Rust docstrings, adaptive semantic ranking
RESOLVEDedge tier for uniquely-bound calls — a call expression is extracted from source, but its binding (which definition the bare name means) is name inference; the graph previously called the whole edgeINFERRED, soaffectedmarked all 12 depth-1 callers ofscore_nodesas untrusted. Reference resolution now upgrades a call whose name binds to exactly one definition toRESOLVED(strength 0.85): above co-occurrence inference, deliberately belowEXTRACTED/DECLAREDso--detail high(compiler-grade facts) and health's EXTRACTED-only cycle detection still exclude it. On this repo: 3,013 of 11,828 call edges areRESOLVED; the remaining 8,815 (is_some,join, unbindable names) stay honestlyINFERRED.affectedshows tiers per hop and saves the legend line for genuinely untrusted hops.explain/neighborsshow real edge direction — the explained node was rendered as the source of every connection arrow, inverting caller/callee for incoming edges (the very artifact that mademodel_cached()look like it called its callers). Connections now render-->(this node calls/imports the neighbor) vs<--(the neighbor calls/imports this node), on CLI and MCP;--jsoncarriesoutgoing.- **Rust
///doc com...
v1.0.7
[1.0.7] — 2026-09-28
Jev judge layer — calibrated second opinion over any backend
- New
--judge jevflag (run/update) layers TypeSafe's Jev — a System One decision model that returns typed judgments with calibrated probabilities, not generated text — on top of the selected--backend(claude, openai-compatible, or gemini). The engine still generates every extraction; the judge re-judges it.--backend jevis not accepted and errors with a pointer to--judge(ASTRIA_LLM_JUDGE=jevselects it via env). - Trivial-file gate (on by default, bounded batch sizes) — before a file's first extraction, batched keep/drop judgments (≈1 billed request per 50 files, files >64 KB presumed rich) skip files the judge finds empty or trivial, so they never cost an engine call. Gated files keep their structural extraction; the run summary reports them ("N files gated by Jev").
- Per-file verification — one request per file re-chooses node types and relations from the schema allowlists (replacing the lossy
relates_to/conceptclamps) and gets a keep/drop existence verdict per edge. Spurious edges are dropped (ASTRIA_LLM_JEV_MIN_EDGE_PROBABILITY, default 0.40); kept edges carry the judge's keep probability as a calibratedconfidence_scorein theedgestable — semantic edges previously left it null. - Suggested-question ranking — on runs that rebuilt the graph, the report's suggested questions are re-ordered by judge keep-scores so the most useful one leads. Best-effort: any judge failure keeps the generated order.
- Judge calls count toward
ASTRIA_LLM_BUDGETlike every other response, and the judge configuration (model, thresholds, gate settings, prompt text) fingerprints into the semantic extraction cache — changing it invalidates cached extractions.--judgewithout--backenderrors: the judge wraps an engine, it cannot generate extractions. - Configuration:
ASTRIA_LLM_JUDGE_API_KEY(orTYPESAFE_API_KEY) andASTRIA_LLM_JUDGE_MODEL(defaultjev-latest) are vendor-generic; behavior knobs keep the honestASTRIA_LLM_JEV_*names (_VERIFY,_MIN_EDGE_PROBABILITY,_GATE,_GATE_MAX_BYTES,_GATE_DROP_THRESHOLD,_GATE_BATCH).
HTML visualization rewritten around drill-down
astria export --format htmlnow ships a self-contained canvas viewer (no vis-network, no network access required) that opens as community bubbles — one per community, sized by membership, with edge-weighted links between bubbles. Click a bubble to expand it into member nodes, click a member to focus its 1-hop neighborhood, and search to jump straight to any symbol; "All nodes" expands everything with level-of-detail labels.- The exported layout stays fully precomputed (physics-free), and the viewer draws only what is on screen, so large graphs open and zoom instantly even in sandboxed HTML previewers.
- Viewer source lives in
packages/viewer(TypeScript,npm run build); the minified bundle is embedded atcrates/astria-napi/src/assets/viewer.js. Community bubbles use themed labels from thecommunitiestable when--label-communitiesproduced them. - Relation-aware focus — the exported edge payload now carries the edge kind (
calls,imports, …): the focus panel lists a selected node's neighbors with their relation, and the highlighted 1-hop edges gain direction arrowheads (direction shown where it matters, not on the hairball). - Community search — search matches community names as well as symbols and files; picking a community expands and centers its bubble.
- Accessibility floor — the canvas exposes a
role="img"label with node/community/edge counts plus a visually hidden summary of the controls, so screen readers get a usable description of the export. - Quiet, throttled git hooks —
astria hook installnow writes v4 hooks that invokeupdate . --quiet --if-stale 10: hook-driven rebuilds print nothing (no progress lines, no token benchmark), and skip entirely when the graph was published less than 10 minutes ago, so a burst of commits rebuilds once instead of per commit.astria updategained matching--quiet/--if-stale <minutes>flags; hooks retry plainupdate .against any CLI version that predates the flags, and still never break a commit.
Skills and MCP updated for the new features
- The shipped skills (
packages/astria-cli/skills/skill*.md, full + per-assistant variants) now teach agents the new capabilities: the interactive bubble-viewer export (export --format html,--mode standard|large, thetreeview, and--neo4j-push/--redis-push), the fullupdateflag set (--no-dedup,--embed,--label-communities,--deep,--quiet,--if-stale), and the git hooks (astria hook install|uninstall|status,hook-guard) with their automatic post-commit refresh. Existing installs refresh by re-runningastria install. - The MCP server's client instructions now point agents at the hooks (
astria hook install) for automatic post-edit freshness, and the skill's MCP tool list is corrected to includehealth.
Retrieval ranking tightened for prose corpora
- Chunk labels are a truncated first line of the chunk's own body; scoring no longer amplifies that prefix at label weight for
chunknodes, so a later session whose opening line re-mentions a topic cannot outrank the chunk whose body actually answers the question. - The IDF pre-pass now counts document bodies as well as labels, so terms that are common in bodies but rare in first lines ("group", "friends" in transcripts) stop acting as near-max discriminators, and rare proper nouns carry the ranking.
- Measured on the full LoCoMo set (1,977 questions, structural, no embeddings): recall@1 63.5% → 66.1%, recall@3 79.3% → 80.7%, MRR 0.717 → 0.736, with recall@5/10 at 85.0%. The 35-question code self-check (quality harness) holds recall@5 at 82.9% with MRR 0.636 → 0.659 (a different series from the paired-runner self numbers below — different harness, pinned graphs).
Qualified-name retrieval and the first blind answer-correctness run
- Question terms now score against each node's scope-qualified id (
BaseCommand.get_usagereachessrc_click_core_basecommand::get_usagethrough the id even though every same-name symbol shares one bare label), and id tokens join the IDF pre-pass so ubiquitous scope words ("src", "core") cannot act as rare discriminators. - The seed reservation honors qualified names too: an explicitly named qualified symbol reserves its node a traversal seed instead of losing the slot to a label-tie stranger. Click's additional validation went from 0% to 2/2 exact definitions surfaced, additional ripgrep from 25% to 3/4, and the paired-runner self set's MRR from 0.618 to 0.687 at unchanged file recall; LoCoMo is unchanged.
- Blind answer-correctness judging finally ran (TypeSafe System One judge,
scripts/bench/quality/blind-judge.mjs): both tools answered the same 35 rubric-grounded questions, graded without tool identity — astria 100% PASS, Graphify 77.1% PASS / 2.9% PARTIAL / 20% FAIL. First generated-answer-correctness measurement in the project (single judge, single run, 35 self-corpus questions — not a statistical claim). The same pairs re-graded by the independent promptfoo/OpenRouter judge (gpt-4o-mini) agreed on the ordering at 77.1% vs 65.7% pass. - The paired runner's budgets are configurable (
budgetsarray). A four-point budget-response curve (250/500/1000/2000) shows astria's 250-token answers outscoring Graphify's 2,000-token answers (MRR 0.680 vs 0.531, recall@5 74% vs 69%) while Graphify exceeds each of the two smallest budgets on 48/50 raw responses and astria stays inside budget on all 200 (structural only, one observation per condition). - Two reserved golden tracks exist, authored from pinned source and unused during development:
click.doc-intent-v1.jsonl(8 doc-intent cases) andclick.reserved-v1.jsonl(12 cases, doc- and code-intent, line-exact definitions). First use must be an evaluation run; afterwards they count as exercised. - Held-out evidence grew:
scripts/bench/paired/*.heldout-v2.jsonladds 14 separately authored, line-exact grounded cases (5 Click, 5 Express, 4 ripgrep); current runtime retrieves 5/5, 5/5, 2/4 files and 11/13 v2 definitions in the top five.
Fixed
- Tree export hardening — the symbol-tree hover inspector builds its panel with DOM
textContentinstead ofinnerHTML, and the embedded JSON escapes</script/<!--breakout sequences: the tree viewer now upholds the bubble viewer's labels-as-text safety property, with matching tests. - Docs drift — reference pages corrected against the code: query-log env semantics (
ASTRIA_QUERY_LOGis a literal path;ASTRIA_QUERY_LOG_ENABLEselects the default), the--json20-neighbor cap,--detail highas anEXTRACTED/DECLAREDclass filter,--label-communities/--deep/update --embedflags, missing env-var rows (ASTRIA_LLM_BUDGET,ASTRIA_LLM_COMMUNITY_MAX,NEO4J_*), the realscip_*relations replacing the never-emittedmethod/inherits/forks, schema table columns, memory ingestion timing, andsame_type_aslabel-based grouping. The docs-sync guard no longer counts#[cfg(test)]fixtures as relation emitters (a clamp-testrelation: "forks"had been satisfying the check for a documented relation that does not exist). - Docs drift guard, both directions — the docs-sync check now also fails when ARCHITECTURE.md documents a relation that no production code emits or references (with an explicit
(external only)escape), when anASTRIA_*variable is read but undocumented or documented but never read, when a registered CLI command/flag or MCP tool is missing from its reference page, and when the new generated SQLite schema block is stale. The schema block is generated fromdb.rsinto the architecture page byscripts/generate-schema-docs.mjs(column lists can no longer drift — the first generated block surfaced five previously u...
v1.0.6
What's Changed
- [GPF-1] Add pre-publish CI guard for @napi-rs/cli drift
Goal
CI f... by @nodesify-technology in #56
- [GPF-2] Define 1.0.0 readiness
Goal
One decision document. No cod... by @nodesify-technology in #57
- docs: update documentation for astria 1.0.5 by @nodesify-technology in #86
- chore(bench): publish 1.0.5 benchmark snapshots by @erictong0602 in #87
- Release 1.0.6 — chunked document retrieval, cross-conversation ranking, introspection commands by @erictong0602 in #88
Full Changelog: v1.0.5...v1.0.6
astria v1.0.5
What's Changed
- Release: graph reliability, retrieval correctness and updated documentation by @erictong0602 in #84
- Release v1.0.5 by @nodesify-technology in #85
Full Changelog: v1.0.4...v1.0.5
What's Changed
- Release: graph reliability, retrieval correctness and updated documentation by @erictong0602 in #84
- Release v1.0.5 by @nodesify-technology in #85
Full Changelog: v1.0.4...v1.0.5