Skip to main content

astria 1.0.8: provenance you can see, agents that can't answer from the past

· 5 min read

1.0.8 makes the graph honest about what it knows and what it's guessing, tells you when it's stale, embeds with a code-aware model, and installs into sixteen agent platforms — including several it now drives as native tools. Install or upgrade with npm install -g @nodesify/astria.

Trust markings on every edge​

A call edge was previously either source-verified (EXTRACTED) or reconstructed (INFERRED) — but a bare call name that binds to exactly one definition in the graph is much more than a co-occurrence guess. 1.0.8 introduces the RESOLVED tier: uniquely-bound call edges are upgraded above inference and deliberately kept below source extraction, so --detail high (compiler-grade facts) and the health checks still exclude them. On this repo, 3,013 of 11,828 call edges became RESOLVED; the rest stay honestly INFERRED, and affected now labels the tier of every hop in a blast radius instead of presenting inference as fact.

The same audit fixed direction: explain used to render the explained node as the source of every arrow, inverting caller/callee on incoming edges. Connections now render --> (this node calls/imports the neighbor) versus <-- (the neighbor calls/imports this node). And astria health's file-cycle detection consumes only edges the source literally contains — the old INFERRED-inclusive version chained 82 unrelated files into one phantom "cycle", and ten health points rested on that artifact.

The graph discloses its own staleness​

Edits that arrive through paths without hooks — print-mode sessions, editors, plain typing — used to leave an agent confidently answering from a stale graph unless it noticed a raw timestamp. Every query header now reports how many manifest files changed since the build (# 3 file(s) changed since this build — run astria update before trusting answers). The check is stat-only, costs milliseconds, and clears itself on the next update. The MCP tool descriptions teach the same discipline: query_graph explains the file:line anchors and provenance tiers, affected says to run it before changing a shared symbol, and "No confident match" is documented as a rephrase hint, not an error.

Code-aware embeddings, one measured calibration​

astria-embed swaps bge-small-en-v1.5 for jina-embeddings-v2-base-code (768 dims, 8k-token context, still fully local — no API key, offline after a one-time ~615 MB download). Every cosine threshold that used to be a scattered bge-scale constant now lives in one measured calibration table (astria_core::calibration), anchored by the calibrate example rather than inherited: jina's noise p95 sits at 0.24–0.44 where bge compressed half of all nodes above 0.55. Model-swap separability improved structurally — 0.79% of node pairs clear cosine 0.60 under jina versus 23.1% under bge.

Rust /// doc comments are extracted now too (extraction rules v12 — previously Rust had zero docstrings), feeding the doc-evidence ranking and the embedding text. Combined with a description-shaped semantic path that lets strong embeddings rank when a question shares no vocabulary with the graph ("auth flow"), the self-corpus golden moved: MRR 0.636 → 0.682, hit@1 51.4% → 60.0%, hit@10 unchanged at 91.4%. The embedder loads once per process, dropping the MCP server's steady-state embedded query from ~1.4 s to ~140 ms.

Sixteen platforms, one command​

astria install --all wires every supported platform in one run. New since 1.0.7: VS Code (workspace-native MCP), Codex (user-global TOML, merge-safe), Trae, Windsurf, Kiro (its documented .kiro/settings/mcp.json), OpenCode, plus cline, roo, amp — and pi, which gets native astria_query/astria_map/astria_explain/astria_path/astria_affected tools through an auto-discovered extension, a few hundred context tokens instead of 10k+ of MCP definitions. Every flavor was verified against the real vendor CLIs and vendor docs, not just schemas — that process caught and fixed install-path bugs in Kiro, OpenCode, and VS Code configs before release.

The external runner's deterministic baseline — question-derived rg terms, term-occurrence ranking, source windows — now has a checked-in comparison (worked/external-baseline/). Across eight Click/Express/ripgrep golden questions, structural astria retrieval ranked the defining file first 8/8 at every budget from 250 to 4,000 tokens (184–234 delivered tokens per response at the 250 budget); the single-pass baseline never ranked it first at any budget, with best ranks 4–12. Boundaries are stated in the write-up: deterministic baseline, not an expert iterative searcher; n=8 symbol-heavy questions.

Smaller and steadier​

  • No-confident-match floor — when no node matches any of a question's answer-identifying terms and nothing covers even half of them, query returns an explicit miss naming the missing vocabulary instead of traversing 445 nodes of unrelated code. Weak-but-on-topic matches still traverse, and ASTRIA_QUERY_SEED_FLOOR=off restores always-traverse.
  • Rust constants are nodes (rules v11) — value questions ("which embedding model") were structurally unanswerable before; the answer's carrier wasn't a node.
  • Model swaps self-heal on update — foreign-model vectors re-embed through the ordinary refresh, or print the one-time --embed migration command instead of stranding silently.
  • Entry-intent matching requires intact phrases — "domain files" no longer contains its way into matching "main file", killing a class of false entry-point overrides that won outright, not nudged.
  • Corpus mode is explicit — the hidden prose_share > 0.95 switch is now ASTRIA_CORPUS_MODE=docs|code, disclosed in the query header.
  • astria add --transcript <file|-> — pipe any transcription tool straight into the graph: whisper ... | astria add --transcript -.
  • A judge-layer A/B harness (scripts/bench/quality/judge-ab.mjs) productizes the mode experiment; LoCoMo QA accuracy is decomposed into retrieval vs reader vs ceiling legs, and Graphify's structural substrate is now a measured null result on prose.

Full detail in the changelog.