All notable changes to Loomweave are documented here. The format is loosely based
on Keep a Changelog, and Loomweave
follows Semantic Versioning for the loomweave binary,
the workspace crates, and the Python plugin.
API versioning for the federation HTTP read API (/api/v1/...) is independent
of product semver: api_version: 1 is the wire-contract version, and bumps
only when an incompatible change is made to that surface. See
docs/federation/contracts.md.
- Doctor bootstrap-state repair.
loomweave doctornow warns when an installed catalogue has never been analysed or lacks its local instance identity.loomweave doctor --fixmaterialises a private project UUID and runs an authoritative analysis to regenerate classifier coverage metadata.
Minor release on top of 1.4.2. (Cargo SemVer 1.5.0; Python wheels 1.5.0.)
- Versioned classifier coverage evidence. Completed analyses now persist
strict
loomweave.classifier-coverage.v1metadata for plugin discovery, source walking, declared classifier tags, and per-plugin matched/analyzed/retained/degraded counts. Tag-backed MCP responses attachloomweave.classification.v1, separating supported-zero results from partial, unsupported, unavailable, or truncated enumeration. - Supported external SQLite federation boundary. Local consumers can check
typed
compatible,older_supported, andincompatibleresults for the read-onlyloomweave.external-sqlite.v1projection before issuing catalogue SQL.loomweave doctorreports this compatibility together with classifier enumeration, active tag declarations, HTTP auth posture, and project instance-ID validity. - Federation seam producer goldens. Loomweave now publishes byte-pinned
classifier coverage/classification, capabilities, bearer/HMAC auth,
identity-ownership, and external-SQLite fixtures. A real Python analysis and
production handlers produce the coverage, classification, capabilities,
identity, and live auth-handler matrix. The external-SQLite cases and the
canonical auth signing vector are synthesized deterministically, then
rechecked against production compatibility/auth code. The live fixture proves
all four Plainweave denominator classes as supported and complete at
5/5/0/0.
- Identity responses prove project ownership. Every successful identity
response, including not-alive and batch envelopes, now carries
api_versionandinstance_id. The unauthenticated capabilities probe advertises the effective protected-route mode (none,bearer, orhmac) without exposing credential names or values, so consumers can authenticate and recheck ownership before joining HTTP identity to local catalogue rows.
Patch release on top of 1.4.1. (Cargo SemVer 1.4.2; Python wheels 1.4.2.)
- Python export rebinding accuracy. Explicit
__all__exports now follow final statically visible module bindings, so a local function or class later replaced by an import, assignment, or other module-scope binding is no longer reported as the runtime exported API object. - Python overload export classification. Recognized
@overloadstubs no longer compete with their implementation for explicit__all__exports; the implementation receivesexported-api, and the module no longer receives the fallbackexported-apitag. - Python reference-resolution fanout. Unshadowed built-in names now bypass Pyright definition queries as known-external references, while imported or potentially shadowed names remain position-resolved so rebinding stays correct. This preserves resolved-reference results while bounding language-server query fanout on large typed files.
- Unix project-anchor validation. Phase 3 now accepts project directory
basenames containing
:when validating protected project anchors on Unix. - Partial-analysis subsystem preservation. Runs with plugin crashes now skip Phase 3 clustering, preserving the prior authoritative subsystem projection instead of reconciling a mixed old/new graph.
- Subsystem finding lifecycle preservation. Before obsolete subsystem entities are removed, acknowledged, suppressed, promoted, or Filigree-linked findings are re-anchored to the project entity with their former subsystem recorded, preventing graph reconciliation from cascading away operator state.
- Versioned duplicate-locator evidence.
LMWV-DUPLICATE-LOCATORnow publishes evidence contract v2 with explicit declaration and collision path keys. The deprecatedfirst_source_file_pathalias preserves the first declaration path instead of the colliding path, while entity collision reads remain compatible with unversioned findings already stored. - Rust public re-export reachability. Targets of uniquely resolved,
externally visible
pub useedges now seed dead-code reachability; test-only re-exports remain excluded fromapp_only. Rust ontology0.8.0invalidates cached extraction values so unchanged files gain the new edge provenance. - Rust dead-code lint scope.
#[allow(dead_code)]and#[expect(dead_code)]now propagate through inline modules and impl blocks, while nestedwarn/deny/forbidlevels correctly cancel inherited keep signals. Direct and impl-level#[cfg(test)]items are also classified as tests forapp_onlyfiltering. Rust ontology0.8.1invalidates cached extraction values for the corrected tags. - Rust compound test cfg classification. Test-only tags now cover compound
predicates that prove an item cannot exist with
test=false, while disjunctions andcfg_attrforms that can admit app code remain app-visible. Rust ontology0.8.2invalidates cached extraction values for the corrected tags. - CI-visible Wardline golden drift. The reusable verify workflow now checks
Loomweave's vendored taint-fact fixture byte-for-byte against the public
Wardline
mainauthority inside the required Rust job, so sibling drift blocks PR merges and releases instead of only failing local workspaces that happen to have both repositories. - Deleted-file graph pruning. Incremental analysis now removes scan-time anchored edges and unresolved call sites owned by vanished source files, while retaining cumulative entity rows long enough to preserve deletion findings and SEI lineage.
- Fail-closed source metadata integrity checks. Index integrity checks now
treat only
NotFoundas a vanished source; other filesystem metadata errors propagate and prevent repair from deleting uncertain file entities. - Stable incremental subsystem materialization. Phase 3 now reconciles the persisted subsystem graph to each run's authoritative clustering result, preserving stable subsystem IDs while removing obsolete subsystem entities and membership edges, including on unchanged incremental reruns.
- Plugin syntax-finding deduplication. Host fallbacks now use each plugin's declared rule namespace and are suppressed per file when the plugin already reported that syntax failure, removing wrong-language duplicate findings for degraded Rust files while retaining fallback coverage for silent plugins. Plugin syntax identities are file-scoped, and legacy duplicate rows merge into the canonical finding without losing status or Filigree linkage. A versioned per-plugin marker forces each plugin through the one-time incremental re-dispatch needed to migrate old indexes, including plugins that leave and later return; the run-level marker is retained when a migration resumes. Reconciliation is symmetric, so a later silent or partial plugin pass can fall back without recreating a duplicate or losing migration audit.
- Plainweave public-surface denominator completeness. Loomweave now exposes
MCP shortcuts and plugin tags for the four public-surface classes Plainweave
uses for intent coverage:
entry-point,http-route,exported-api, andcli-command, including Python__all__ += [...]exports and common main-guard runner wrappers.
- Coverage honesty over higher-looking ratios. Expanding these tags can lower Plainweave coverage on real projects by adding previously invisible public surfaces to the denominator. That is the desired result: Plainweave's prior degraded output was correct; requirements are right; Loomweave now sees more doors.
- Bumped the transitive Rust dependency
crossbeam-epoch0.9.18->0.9.20in both the workspace and standalone Rust-plugin distribution lockfiles to clear RUSTSEC-2026-0204. Lockfile only; no API change.
Feature release on top of 1.3.1. (Cargo SemVer 1.4.0; Python wheels 1.4.0.)
Highlights: a new loomweave-llm provider crate (so loomweave-core links no
outbound HTTP client), the Warpline churn consumer lighting up the churn/recency
read surfaces, Rust-plugin dead-code reachability roots (ADR-054), and a batch of
federation-keying and graph-integrity fixes.
- Warpline churn consumer. Loomweave now consumes Warpline's frozen churn
read to populate the
high_churnandrecently_changedsurfaces (entity_high_churn_list/entity_recent_change_list). The consumer speakswarpline-mcp's newline JSON-RPC with a bounded timeout and honest paging/keying disclosure. Federation is enrich-only and fail-soft — with Warpline absent the surfaces degrade cleanly. - Rust-plugin dead-code reachability roots (ADR-054). The Rust language
plugin now emits reachability-root tags — visibility / entry-point / test /
handler roots, framework handlers, public-method rooting, and edition-2024
#[unsafe(no_mangle)]/#[unsafe(export_name)]FFI entry-points — the Rust analog of the Python public-surface roots, so Rust dead-code analysis no longer reports the whole public API as dead.
- LLM / embedding providers extracted into a new
loomweave-llmcrate. The provider traits and implementations moved out ofloomweave-core; a CI gate now assertsloomweave-corelinks no outbound HTTP client. No change to thesummaryAPI or provider configuration. - SEI git-rename consumer re-pointed to
legis's/git/rename-feed.LegisGitRenameSourcenow reads the committed leg oflegis's additive superset endpointGET /git/rename-feed?base=…&head=HEADinstead of the legacyGET /git/renames?rev_range=….legispins eachcommitted[]entry byte-identical to the old/git/renamesarray with a contract-lock test, so committed renames resolve unchanged; theworking_treeleg is not consumed (committed-window semantics preserved — the shell source remains the sole working-tree authority). Enrich-only and fail-soft as before; the wire-drift guard now warns on a legacy flat-array body or acommitted-less envelope. (Federation ledger B3.) - Filigree federation transport over newline JSON-RPC. The filigree-mcp
federation client now speaks newline-delimited JSON-RPC instead of
Content-Lengthframing (#78).
- Briefing-blocked entities keep their SEI on the read surface. Federation keying no longer nulls the Stable Entity Identity of briefing-blocked entities on the MCP read path, so Filigree/Wardline lookups keyed by SEI resolve (#79; PDR-0008).
- Same-locator collisions are disclosed on the entity read path. A duplicate
entity locator now surfaces as an entity-anchored
LMWV-DUPLICATE-LOCATORfinding anchored to the colliding (survivor) entity, so the shadowed declaration is queryable from the entity read path instead of silently resolving to a clean row (clarion-48af930f2a, #74). - Stale
containsedge pruned when a file-scope claim moves. The writer prunes a stale parent/containsedge when afile_scopeentity's claim moves, self-healing the module/package dual-claim mismatch on re-emit (clarion-abda98c869, #75). - Incremental re-analyze on a tag-schema move. A plugin's files are re-dispatched when its ontology tag schema changes between runs, so tag-driven surfaces don't go stale on an incremental walk (clarion-e12d424f1d, #71).
- Plugin findings can no longer forge the trusted anchor.
validate_plugin_findingstrips the host-reservedanchor_entity_idmetadata key, so a plugin-reported finding can no longer override the trusted file anchor — which previously could hard-fail the analyze run on the findings foreign key, or silently mis-associate the finding (#80).
- Cross-repo conformance oracles for the loomweave↔filigree and loomweave↔wardline seams (Filigree entity-associations, the Wardline taint-fact wire, and the Wardline trust-vocabulary descriptor), pinning the wire bytes each sibling produces or consumes so a silent drift reds in CI.
- Bumped
anyhow1.0.102→1.0.103to clear a RUSTSEC soundness advisory inanyhow'sdowncast_mut(dtolnay/anyhow#451). Lockfile only; no API change.
Patch release on top of 1.3.0. (Cargo SemVer 1.3.1; Python wheels 1.3.1.)
Operator-guidance docs plus a transitive-dependency security bump — no runtime
or API change.
- Stale-index refresh discipline. Rewrote the
loomweave-workflowskill's "Manual scanning" section and theStaleWorktree/Stalestaleness_notestrings (project_status_get) to stop agents under-refreshing a stale index on "it's just research / read-only" reasoning. The guidance now leads with the fact that a Loomweave answer is a claim about the source tree as of the last analyze — so read-only orientation is exactly where stale poisons the result — states the real refresh cost (analyze is incremental: unchanged files are skipped by whole-file content hash;analyze_startis non-blocking; the advisory lock makes a second runner a clean no-op), and carries a rationalization table plus red-flags. It permits exactly one observable valid-skip:index_diff_getshows the drift disjoint from the files/entities the task touches (it scopes drift, it does not overturn the verdict — both surfaces derive from one freshness oracle). TheFreshnote is unchanged.
- Bumped the transitive Python build/tooling dependency
msgpack1.1.2→1.2.1(viacachecontrol[filecache]) to clear GHSA-6v7p-g79w-8964. Lockfile only (plugins/python/uv.lock); no runtime or API change.
Feature release on top of 1.2.1. (Cargo SemVer 1.3.0; Python wheels 1.3.0.)
- Auto-refresh on session start. The
loomweave hook session-starthook now starts ONE detached, non-blockingloomweave analyzewhen it finds a stale index — stdio to/dev/null, in its own process group, never waited on, so it never blocks session start. The analyze advisory lock keeps it single-shot. A fresh index (or a spawn failure) falls back to the existing manual-analyze nudge. Theloomweave-workflowskill gains a clearer "Manual scanning" section describing theanalyze_*cycle and this auto-refresh.
- MCP write tools default on for the local agent loop.
serve.mcp.enable_write_toolsnow defaults totrue, so the on-demandanalyze_start/analyze_status_get/analyze_cancelandentity_summary_gettools register out of the box. Consult-mode read-only sessions opt back out withenable_write_tools: false.loomweave config checknow reports the effective MCP write-tools state.
- Deletion tombstones no longer wedge the index stale (clarion-23a44085f9).
The
entitiestable is cumulative and never-pruned by design (REQ-ANALYZE-04), so a deleted source file leaves its rows behind as a tombstone. The freshness oracle previously gated on missing indexed files, which meant any repo that ever deleted a file readstaleforever (re-analyze could never clear it). Missing files are now reported informationally inmissing_filesbut no longer drive the freshness verdict; commit mismatch, HEAD-newer, modified files, and staged changes still do. Supersedes clarion-e687941a8c.
1.2.1 — 2026-06-18
Maintenance patch for the 1.2.0 consult-surface release. (Cargo SemVer
1.2.1; Python wheels 1.2.1.)
- Briefing-block redaction consistency.
unresolved_candidatesno longer echoes parsed callee text from briefing-blocked owners, and custom subsystem member / relation-candidate projections now reuse the same high-entropy identity guard as the canonical blocked entity stub. - Dossier delegated-read honesty.
entity_orientation_pack_getnow treats delegated MCP envelopes as envelopes:ok:falsefromentity_wardline_getorentity_finding_listbecomes an explicit unavailable dossier section instead of a silentnull/ empty result. app_onlydead-code reachability.entity_dead_list app_only:trueremoves test-tagged and core-plugin entities from reachability roots and traversal edges before computing liveness, so test-only reachability no longer suppresses app dead-code candidates.- Inferred caller hint wording.
next_actionno longer claims unresolved name matches are absent fromcallers, which was false after inferred dispatch materialized a caller. - Release reproducibility and public version pointers. The standalone Rust plugin distribution lockfile is regenerated for the current package versions, and README / site release pointers now name the current release.
1.2.0 — 2026-06-18
A consult-surface increment from dogfooding the MCP tools against a live Weft
testbed: richer orientation, more honest traversal/availability signals, and
app-scoped queries. Every addition is backward compatible — omitting the new
params leaves responses byte-identical to 1.1.0. (Cargo SemVer 1.2.0; Python
wheels 1.2.0.)
- Entity dossier via
includeonentity_orientation_pack_get(clarion-2b87cd7a59). An optionalinclude: ["wardline","findings","issues"]param folds a composeddossier:{wardline,findings,issues,summary_available}into the consult-mode pack — pure read-path composition of existing surfaces, no re-analysis. Thefindingssection mirrorsentity_finding_list's result (afindingsarray pluspagepagination metadata, so truncation past the first page is visible);summary_availableistrueonly whenentity_summary_getwould serve from cache (full cache key present and unexpired). Finding fingerprints are normalized to one canonical form (stripping anywlfp2:prefix) across the dossier. Omittinginclude(or an empty array) leaves the packet byte-identical. - App-scoped roots +
app_onlyfilter on dead-code and coupling surfaces (clarion-663aca16aa).entity_dead_listgainsroots: "auto", deriving reachability roots from emitted tags and reportingroots_mode+roots_confidence(explicit mode remains the default and is unchanged). Bothentity_dead_listandentity_coupling_hotspot_listgain opt-inapp_only: true, a read-path filter that drops test-tagged and non-first-party (core-plugin) entities, removing excluded endpoints from both rows and neighbour counts. - Per-query caller honesty via
traversal_complete+unresolved_candidates(clarion-76c31b730a).entity_callers_listandentity_neighborhood_getno longer emit a blanketscope_excludesfooter:scope_excludesis populated ONLY when this traversal actually skipped a name-matched unresolved candidate, otherwise it is[]paired with the newtraversal_complete: true— so an emptycallerslist reads as a true negative. Skipped sites surface as the newunresolved_candidates[{path, line, callee_text, why}]in-tool grep-fallback. - Inline entity-row tags + arg aliases (clarion-057ff2b330). Entity rows
carry their tags inline, and
entity_resolve/entity_relation_listaccept argument aliases for friendlier consult-mode calls.
- Secret content — not entity identity — is redacted in
briefing_blockedrows (clarion-719e7320f5). A briefing-blocked entity now rides alongside its real, navigable identity (id/kind/name/source_file_path/line span/content_hash); only the secret-bearing file content stays withheld. A read-path entropy guard re-withholds an identity field only when a single path segment is itself a long, high-entropy blob (≥4.5 bits/byte) — so a secret embedded as a qualname segment is still redacted, while long descriptive Rust::paths, dotted qualnames, and verbosesnake_casenames stay navigable. summary_availablein the dossier now matches the full summary cache key. It previously matched oncontent_hashalone, reportingtruefor a summary whose template / model tier / guidance had since changed —entity_summary_getkeys on the full tuple and would miss it, so a consult caller could wrongly skip generating. It now mirrors the summary tool's exact gate (full key + expiry window).unresolved_candidatesis gated behindconfidence != Inferred(A1). On the inferred dispatch pathtraversal_completeis forcedtrue; surfacing skipped candidates there contradicted that completeness claim.
1.1.0 — 2026-06-15
First stable 1.1.0 release — the GA of the 1.1.0rc1–rc10 candidate
series, cut over from the rc line to main. The final candidate (rc10) added
a self-qualifying lead summary to find_dead_code (entity_dead_list) — the
reference implementation of an agent-first convention: any tool that returns
a number of things in various kinds states the breakdown up front. The
cumulative changes since 1.0.0 are catalogued in the 1.1.0rc1–rc10
sections below. (Cargo SemVer 1.1.0; Python wheels 1.1.0.)
- Lead summary on
entity_dead_list. The response now carries a top-levelsummaryblock —dead_candidates,reachable,not_analysed(plugins_without_roots/shielded_by_unresolved_calls/withheld_secret), and aconfidenceverdict — so an agent reads the shape of the result without counting rows or hunting for a caveat. When an implausibly large share of analysed entities is unreachable (>25%, the sign that reachability roots don't cover the corpus — e.g. a library exercised only by tests),confidencereadslowand anadvisoryrecruits the operator to configure entry-point roots, instead of letting a misleading raw candidate count stand (an external review docked trust on exactly this: 141 candidates read as alarming until the caveat was found).
Ninth 1.1 release candidate. Fixes a bare-qualname scope returning nothing for a
package name. No package is published for release candidates. (Cargo SemVer
1.1.0-rc9; Python wheels normalise to PEP 440 1.1.0rc9.)
scopeby package name now selects the whole namespace (lacuna-522ab56124). A bare dottedscopeis treated as a namespace: it selects every entity whose qualname is the scope or a descendantscope.*, via the newentity_ids_in_namespace. Previously it resolved the scope to a single exact entity and walkedcontainsedges, so a package name (specimen) reached only the package__init__'s own members and missed sibling submodules entirely — returning 0 on edge-derived tools (entity_coupling_hotspot_list,module_circular_import_list), which was a silent-empty that read as "nothing here". Module-qualname scoping is unchanged (the namespace match subsumes it), and a scope that matches no entity still falls back to a path glob. The qualname/namespace.boundary test is underscore-safe (noLIKEwildcard hazard) and rejects prefix-but-not-namespace look-alikes (specimentary).
Eighth 1.1 release candidate. Fixes a routine loomweave analyze (the default
incremental mode) 400'ing its Filigree emit on an unchanged tree, and adds an
explicit "default" opt-in for the codex sidecar model. No package is published
for release candidates. (Cargo SemVer 1.1.0-rc8; Python wheels normalise to PEP
440 1.1.0rc8.)
- Incremental
analyzeno longer 400s its Filigree emit.mark_unseen(which asks Filigree to sweep findings this scan did not report as gone) is now senttrueonly when the scan examined the whole corpus (skipped_files_total == 0— a--no-incrementalrun or a first run), not on every fresh run. An incremental run that skipped unchanged files has no authority to sweep their findings, and an incremental no-op would otherwise POST an empty batch withmark_unseen=true— which Filigree rejects withVALIDATION400 ("mark_unseen requires at least one finding or scanned path").--resumestill never sweeps.
codex_model = "default"opt-in. Settingllm_policy.codex_cli.model(or--codex-model) to"default"(any case) explicitly accepts the codex CLI's own default model — it acknowledges the floating-model cost instead of pinning one, behaves as unset (no--modelflag is passed), and silences the "model is unset" config-check warning.
Seventh 1.1 release candidate. Completes the loomweave→Filigree finding-emit work
from rc6: file-less findings now reach Filigree too. The
LMWV-DUPLICATE-LOCATOR finding now carries an anchor_file_path (its first-seen
declaration) so it anchors to a real file instead of the file-less project anchor
— previously such findings were skipped at emit (skipped_no_path), leaving the
duplicate-locator lacuna untrackable in Filigree (the residual half of the
dogfood's Friction A). No package is published for release candidates.
(Cargo SemVer 1.1.0-rc7; Python wheels normalise to PEP 440 1.1.0rc7.)
- Duplicate-locator findings reach Filigree.
LMWV-DUPLICATE-LOCATORnow setsanchor_file_path(its first-seen declaration), sohost_finding_anchor_idanchors it to a real file and the scan-results emit carries it instead of dropping it asskipped_no_pathunder the file-lesscore:project:*anchor. - File-less findings are skipped, not forced under a bogus path. A genuinely
project-level finding (e.g. the weak-modularity subsystem fact) has no real
file, and Filigree's intake rejects every synthetic stand-in — an absolute
project root, and the relative
"."(its_normalize_scan_pathcollapses"."to"", rejected as "path is empty after normalization"). The emit no longer attempts a synthetic project-anchor path (which 400'd the whole batch); such findings stay store-only and are countedskipped_no_path. A finding whose path equals the project root (relativizes to"") is likewise treated as path-less rather than emitted empty.
Sixth 1.1 release candidate. Makes the Loomweave→Filigree finding-emit seam work
end-to-end for the first time against a real multi-project Filigree server —
surfaced by the Lacuna dogfood, where emit was disabled by default and then,
once enabled, posted to an unscoped endpoint with absolute paths and
out-of-range line numbers, each rejected in turn. Also fixes the catalogue
scope qualname-resolution gap. No package is published for release candidates.
(Cargo SemVer 1.1.0-rc6; Python wheels normalise to PEP 440 1.1.0rc6.)
- Doctor stale-port health probing.
loomweave doctor --jsonnow probes/healthwhen HTTP config resolves from.weft/loomweave/ephemeral.portand reports stale persisted port metadata as an advisory warning. - Instruction last-writer marker. Installed instruction blocks now include
stable
loomweave:last-writer:loomweave installmetadata in the canonical drift body so installer provenance participates in idempotency checks. - Filigree EntityAssociation fixture coverage. Added a canonical
EntityAssociation reverse-lookup fixture and parser coverage for
loomweave_entity_id,content_hash_at_attach, and attach metadata. - MCP Wardline facet enrichment.
entity_wardline_listwithhas_findingsnow reconciles Filigree-provided Wardline findings for project-relative paths when the local findings table does not carry the anchor. - SEI oracle coverage guard. Added a reference-test guard that keeps the SEI oracle fixture scenarios and implemented conformance tests in sync.
- ADR-049 lockstep posture. Documented ADR-049 as the versioned Rust-feature dialect adopted by Loomweave and Wardline in lockstep, outside the clean-break core API freeze set.
- Storage coalescing flake stabilization. Stabilized the cold inferred-call coalescing test with a gated provider so follower requests wait behind the leader instead of racing a timing delay.
- Loomweave→Filigree finding emit against a multi-project server. The
scan-results emit now pins the configured project as
?project=<key>(integrations.filigree.project), so a shared Filigree server no longer rejects it as an ambiguous server-mode write; emits project-relative finding paths (stored absolute paths are stripped to the project root) instead of absolute paths Filigree rejects; and clears finding line numbers that fall past end-of-file before emit (mirroring Filigree's lenient single-finding line-attribution), so a syntax-error/degraded finding no longer 400s the whole batch. Together these let Loomweave findings (LMWV-*) reach Filigree's tracker for the first time end-to-end. - Catalogue
scopequalname resolution. A bare dottedscopeargument (specimen,specimen.dead_code) onentity_dead_list,module_circular_import_list,entity_coupling_hotspot_list, and the other scope-taking tools now resolves against entity qualnames (anchor + descendants) instead of being misclassified as a path glob that silently matched nothing. An unmatched token still falls back to a path glob.
Fifth 1.1 release candidate. This candidate adds agent-driveable LLM and
semantic-search configuration (MCP tools + CLI verbs), an LLM lookup
diagnostics log, and the Filigree minted-token auth rung, then remediates the
findings of the adversarial review of that work (weft-ac59e8e730). No package
is published for release candidates. (Cargo SemVer 1.1.0-rc5; Python wheels
normalise to PEP 440 1.1.0rc5.)
- Config MCP tools. Four new tools let an agent inspect and edit the
project's LLM and embedding posture:
llm_config_get/llm_config_set(provider, enabled, allow_live_provider, model pins, OpenRouter key env / endpoint, andserve.mcp.enable_write_tools) andsemantic_config_get/semantic_config_set(provider, model, dimensions, endpoint, key env, timeout, token ceiling). The two*_config_settools deliberately bypass the read-only write-tool gate (bootstrap exemption): the gate itself is one of the settings they edit, so from a read-only session they can persistently enable write tools and live (paid) LLM/embedding spend. This is by design and is stated in the MCP server instructions and theloomweave-workflowskill. loomweave config llm|semanticCLI verbs.config llm status|setandconfig semantic status|seteditloomweave.yamlin place with validation, andconfig example --provider <p>emits an annotated stub. Operator-facing provider aliases are accepted everywhere providers are parsed (openrouter_api/open_router,codex_sidecar/codex,claude_sidecar/claude_code, andopenai/local/openai_localfor the embedding providers).- LLM lookup traffic log. Every configured LLM lookup appends one JSONL
metadata record to
.weft/loomweave/diagnostics/llm-traffic.jsonl(inside Loomweave's member store dir;store_diroverrides move it too). The log is metadata-only by guarantee — provider, purpose, prompt template id, model, outcome, token usage, cost; never prompt text or model output — and is capped at 10 MiB with rotation tollm-traffic.jsonl.1. - Semantic-search configuration with honest degrade. The
semantic_search:block (hostedapior loopback-onlylocal_openaiprovider) feedsentity_semantic_search_list; when it is enabled but the provider cannot be constructed (missing live opt-in or API key),servewarns about the inert embedding provider and the search degrades tonot_enabledinstead of failing startup.
- Filigree auth: minted federation token as the final resolution rung
(dogfood-4 A5, weft-c7db813d9a). Token resolution was env-only, so the MCP
serve path — launched with an empty env in
.mcp.json— 401'd on every weft-gated read. The daemon's auto-minted<root>/.weft/filigree/federation_tokenis now read after theWEFT_FEDERATION_TOKEN/ legacyFILIGREE_API_TOKENenv rungs across serve, scan-results emit, clean-stale, and SARIF import. - Review remediation (weft-ac59e8e730). The adversarial review of the
config/diagnostics work above confirmed nine findings, fixed in this
candidate: the semantic loopback-trust gate no longer runs when
semantic_search.enabled: false(a disabled block with a stale non-loopback endpoint had hard-failedserve/config statusand blockedconfig semantic set --disableitself); IPv6 loopback (http://[::1]:…) endpoints are recognised; a diagnostics write failure no longer converts a successful (paid-for) LLM call into an error; concurrent traffic-log appends are serialized (no interleaved partial JSON lines) and colliding rotations no longer fail calls; the traffic log moved from the legacy.loomweave/root into.weft/loomweave/(C-9) with the installed store.gitignorecoveringdiagnostics/; thellm_config_set/semantic_config_setinputSchemas declare real types and provider enums instead of bare{}; a committed agent-harness debug log (error.log) was removed and guarded; and the README MCP surface claim was corrected to 46 tools.
Fourth 1.1 release candidate. This candidate makes the Rust language plugin a
first-party 1.x capability, expands the MCP read surface, finishes the Weft store
cutover, and hardens plugin/analyze failure handling. No package is published for
release candidates. (Cargo SemVer 1.1.0-rc4; Python wheels normalise to PEP
440 1.1.0rc4.)
- First-party Rust language plugin. The 1.1 line now includes
loomweave-plugin-rustalongside the Python plugin. The Rust plugin extracts modules, structs, enums, traits, type aliases, consts, statics, macros, impls, and functions, and emitscontains,imports,implements,calls,derives, andreferencesedges. The distribution wheel installs a discovery-glob-namedloomweave-plugin-rustexecutable and its manifest undershare/loomweave/plugins/rust/, so colocated installs discover it automatically. - Rust-plugin hardening envelope (ADR-050). The host now bounds plugin
lifecycle phases with handshake, per-file, and shutdown deadlines, and the
Rust plugin degrades hostile parse shapes instead of crashing the run:
excessive nesting emits
LMWV-RUST-DEPTH-LIMIT, oversized files emitLMWV-RUST-FILE-TOO-LARGE, and watchdog kills are no longer mislabeled as OOM. The Rust plugin's address-space envelope is raised to the empirically validated 512 MiB line for large real corpora. - Relation-edge MCP read surface.
entity_relation_listexposesinherits_from,decorates,implements, andderivesedges directly, andentity_neighborhood_get/entity_orientation_pack_getnow include direction-tagged relation buckets. - Entity resolution and findings surfaces.
entity_resolveresolves all entity kinds, SEI entries, Rust::paths, and plugin hints; the MCP surface also gained whole-project finding browsing,has_findingsfiltering, stricter finding-filter validation, and better unknown-kind hints. - Duplicate-locator alarm.
loomweave analyzenow emitsLMWV-DUPLICATE-LOCATORat ERROR severity when two declarations collide on one entity id, surfacing data-loss risks that SQLite upserts previously absorbed silently. - Python relation edges. The Python plugin now emits
inherits_fromanddecoratesedges under ontology 0.8.0, including pyright-backed tests for the new relation kinds. - Product ownership workspace.
docs/product/now records the current state, roadmap, metrics, and first product decisions for the 1.1 release line.
-
Project store moved
.loomweave/→.weft/loomweave/(Weft store consolidation, clean break; ADR-046). All machine-written state — the index DB,config.json,.gitignore,embeddings.db,ephemeral.port,instance_id, locks, and per-run dirs — now lives under the shared.weft/<member>/dotdir, routed through a singleloomweave_core::storehelper. There is no fallback read of the old location: existing projects must re-init (loomweave installthenloomweave analyze) and may delete the orphaned.loomweave/. An operator may relocate the store with a member-private[loomweave].store_dirkey in a project-rootweft.toml(read-only to Loomweave; a missing or malformed file falls back silently to the default). Sibling resolution reads the consolidated.weft/<sibling>/location only — Filigree's live port at.weft/filigree/ephemeral.port, Wardline's trust-vocabulary descriptor at.weft/wardline/vocabulary.yaml— with no fallback to the pre-consolidation.<sibling>/path. A sibling found only on the legacy path folds to the fail-soft default (source = "config"for Filigree, an absent descriptor for Wardline), making a mis-sequenced cutover visible rather than a silent stale resolve. Cutover ordering: Filigree migrates to.weft/filigree/→ this build installs → downstream re-init. -
cargo nextest run --workspacenow always completes instead of hanging. Aslow-timeoutcap in.config/nextest.tomlterminates any test that runs past the bound and reports it as a timeout failure, so the literal CI test command runs clean to a verdict even while the pre-existing emission tests (clarion-1d405be546) hang. The cap does not fix that bug — it makes the suite honestly red and fast rather than green-via-family-exclusion. -
Filigree federation token env var renamed to
WEFT_FEDERATION_TOKEN. Theintegrations.filigree.token_envdefault (and the name stamped intoloomweave.yamlbyloomweave install) is nowWEFT_FEDERATION_TOKEN— Weft-suite federation plumbing is named by the suite, not by the sibling member. The legacyFILIGREE_API_TOKENname is still honoured as a deprecated fallback at token-resolution time, so an existing global export keeps working during the transition. This does not affectserve.http.token_env(inbound HTTP read-API bearer auth, defaultWEFT_TOKEN). -
MCP instructions now use the registered tool dialect. The generated
loomweave-workflowskill, MCPinitializeinstructions, and CI drift guard now name the registeredentity_*tools rather than legacy aliases; the server also trims its tools/list context footprint while keeping instructions truncation-proof. -
Dormant
wardline.yamlmanifest ingest retired. The unused CLI ingest path was removed in favour of the durable Wardline descriptor and taint-fact paths already documented in the Weft contracts. -
Rust qualname canonicalization amended. ADR-049 now covers cfg-twin methods, concrete generic arguments, impl self-type and trait paths,
#[path]module mounts, and unnamedconst _skip-emission; the Rust plugin applies the same rules and updates the conformance fixture. -
Release and install packaging moved toward colocated Python installs. The
loomweavePython package scaffold depends on both language plugins, and the Rust plugin has a separate maturin distribution shim so its discovery binary can be shipped without polluting normal workspace builds.
- Rust plugin collision families closed. The Sprint-4 residual collisions
from self-type paths, trait paths,
#[path]module mounts, and unnamedconst _items were fixed and re-swept to zero on the pinned QA corpora. - Out-of-line Rust module trees now agree on parent/contains edges. Host and plugin behaviour now align for mounted module trees and cfg-twin module shapes.
- Python hostile nesting now degrades cleanly. Deep-nesting bombs in the
Python plugin produce a
too_complexoutcome instead of escapingRecursionError. - Duplicate Python qualnames are pinned to first-wins semantics. ADR-052 and dogfood/audit tests freeze the expected handling of repeated Python qualnames.
- Install no longer fails on symlinked instruction files. Symlinked
AGENTS.md/CLAUDE.mdcases degrade to warnings so install can complete. - E2E scripts no longer mutate global Codex config. The smoke harnesses now
force hermetic config paths instead of editing
~/.codex/config.toml. - Untrusted repository git config is no longer executed. Source inspection and rename-window logic use hardened git invocations that do not execute repo-local config or attribute helpers.
- Added the Rust analysis known-limitations page, Sprint-3 scale QA report, Sprint-4 gold QA report, gold-v2 addendum, Rust qualname federation handoff letters, and MCP/command-surface audit memo.
- Refreshed the design ladder, operator getting-started flow, operator guidance docs, ADR index, public static site, and Weft federation contracts for the 1.1 release-candidate surface.
Third 1.1 release candidate. Hardens the Python plugin's pyright spawn path
against transient resource pressure and corrects the plugin process-limit
sandbox. No package is published for release candidates. (Cargo SemVer
1.1.0-rc3; Python wheels normalise to PEP 440 1.1.0rc3.)
-
loomweave doctornow gates on tracked-index DB health (check.weft/loomweave.schema). The check previously only tested for file existence; it now classifies four states: absent (warning — a legitimate install-before-analyze intermediate, does not fail the gate); present but unreadable / corrupt / wrong format (problem — fails the gate); present and opens butPRAGMA user_versionexceeds this build's schema version (problem — reports the version numbers and names the newer-build cause); and healthy (ok). Both the JSON and text paths report consistently so CI gates driven by either surface see the same verdict. The check resolves the DB path vialoomweave_core::store::db_pathso aweft.toml[loomweave].store_diroverride is honoured, and opens read-only so the health check never creates or mutates the file. -
Transient pyright spawn failures no longer disable analysis for the whole run. A
subprocess.Popenfailure with a transient errno (EAGAIN/ENOMEM/EMFILE/ENFILE) now skips only the current file and retries a fresh spawn on the next one, instead of being treated as a permanent install failure. A newLMWV-PY-PYRIGHT-SPAWN-DEFERREDfinding is emitted once per pressure episode, and a resettable soft-cap emitsLMWV-PY-PYRIGHT-RESOURCE-EXHAUSTED(giving up only under sustained pressure); genuine defects (ENOENT/EACCES) still disable as before. Closes the[Errno 11] Resource temporarily unavailable→LMWV-PY-PYRIGHT-INSTALL-FAILUREfailure seen analysing large projects.
RLIMIT_NPROCis no longer applied to language-server plugins. BecauseRLIMIT_NPROCis enforced per real UID system-wide — not per plugin subtree — any fixed ceiling is tripped by the operator's unrelated processes and intermittently failspyright-langserver'sfork(2)withEAGAIN. The host now leavesRLIMIT_NPROCuncapped for plugins declaring thepyrightruntime capability (relying onRLIMIT_AS+ crash-loop supervision) and retires thePYRIGHT_MAX_NPROC = 4096constant. cgroup v2pids.maxis documented as the future tool for true per-plugin process bounds (ADR-021, ADR-035).
Second 1.1 release candidate, rolling up dogfood-friction fixes and deferred
v1.1 engineering items on top of rc1. No package is published for release
candidates. (Cargo SemVer 1.1.0-rc2; Python wheels normalise to PEP 440
1.1.0rc2.)
- Worktree-aware staleness (ADR-045).
project_status_get, theloomweave://contextresource, and the session-start banner now surfaceindexed_at_commit+worktree_dirty, and a newStaleness::StaleWorktreeverdict fires when an otherwise-fresh index has untracked source on disk. Detection uses a hardened, hash-freegit ls-files --othersscoped to ingested source extensions (false-positive guard), proven filter-safe by test — closes the "fresh lies about uncommitted code" friction (clarion-26c7e52027, clarion-d9cf8bcfa9).
.loomweave/.gitignore(ADR-005) now also excludesinstance_idand*.lock, sogit add -Ano longer stages the per-project serve fingerprint or the analyze advisory lock; ADR-005 documents the live-index commit hazard and points atloomweave db backup(clarion-7381e6382d).- WAL hygiene. The storage writer-actor runs
PRAGMA wal_checkpoint(TRUNCATE)after each committed run, so the on-diskloomweave.dbreflects committed state whileserveis alive instead of lagging behind a multi-MB WAL sidecar (clarion-cdee445ed8). - Release CI parity.
release.ymlgains a macOS aarch64verify-macosgate (mirroringci.yml) wired into the build/publishneedschain, closing the gap where a macOS-only lint/test regression could reach the build jobs (clarion-47d395e03c).
- Dead
entity_fts.content_textcolumn dropped via migration 0009 — it was never populated and never read (content search is served by the ADR-040 embeddings sidecar).CURRENT_SCHEMA_VERSIONis now 9 (clarion-716449c371).
- macOS Gatekeeper quarantine workaround added to
getting-started.mdTroubleshooting (clarion-03dfa1f94d). - ADR-024 in-place migration-retirement guard activated:
published_build.txtbackfilled tov1.0.0(first published build; 0001 byte-identical since), so later schema changes must be additive migrations (clarion-b20448b3ac).
First 1.1 release candidate. No package is published for release candidates —
the 1.1.0 package ships only at the final tag. (Cargo SemVer 1.1.0-rc1;
the Python wheels normalise to PEP 440 1.1.0rc1.)
- Read-API ephemeral port publication (ADR-044).
loomweave servebinds a per-project deterministic read-API port (blake3 over the canonical project path, band9400–10399, disjoint from Filigree's8400–9399) with an OS-assigned ephemeral fallback when that port is taken, and publishes the actually bound port to.loomweave/ephemeral.port— a normative cross-product file contract (port-only ASCII + optional trailing newline, atomic temp+rename, loopback-only, removed on clean shutdown). This resolves the cross-project127.0.0.1:9111bind collision so multiple projects canserveconcurrently without mis-targeting one another. New consume-time resolverresolve_loomweave_url(precedence: explicit target > published file > configured URL > none) is the reference reader;doctorandproject_status_getreport the live published endpoint. The published file is git-ignored. - No-index degraded MCP mode.
serveon a project with no index no longer exits 1 — it serves a degraded MCP stdio session that answersinitializeand chirps to runloomweave install+loomweave analyzefrom every tool call, so the MCP client connects and is told how to recover.
serve.http.bindis now optional (Option<SocketAddr>). Unset — the new default — auto-selects and publishes the per-project deterministic port; an explicit value is honoured verbatim (no fallback). The installer no longer stampsserve.http.bind: 127.0.0.1:9111, the integration bindings write the per-project deterministic loomweave URL, andinstall/doctor --fixself-heal the stale hard-coded9111stamp on existing projects.- Version bumped to
1.1.0rc1across the Rust workspace and the Python plugin.
1.0.0 — Loomweave — 2026-06-05
This release renames the product and re-baselines its version. What shipped
as Clarion 1.3.0 is now Loomweave 1.0.0. The entries below this header
([1.3.0] and earlier) are the pre-rename Clarion lineage, preserved verbatim
as history; they describe the same software under its former name.
This is a clean break with no users yet — there are no migration shims,
on-disk path auto-detection, dual-magic fallbacks, binary symlinks, plugin-prefix
fallbacks, or MCP server-name aliases. Existing local state (a .clarion/ index)
is not migrated; re-run loomweave analyze to rebuild under the new paths.
- Product
Clarion→Loomweaveand framework/suiteLoom→Weft. Hierarchy: the Weft framework comprises Loomweave (this product, the flagship code-archaeology tool), Filigree, Wardline, and Legis (+ Shuttle planned). - Binary
clarion→loomweave; workspace cratesclarion-{core,cli,mcp, storage,analysis,federation,scanner,plugin-fixture}→loomweave-*. - Python plugin package
clarion-plugin-python→loomweave-plugin-python, moduleclarion_plugin_python→loomweave_plugin_python, shared-data pathshare/clarion/plugins/→share/loomweave/plugins/. - Persisted identity:
.clarion/→.loomweave/,clarion.db→loomweave.db,clarion.yaml→loomweave.yaml; the SQLiteapplication_idmagic0x434C524E("CLRN") →0x4C4D5756("LMWV"). - MCP server identity
clarion→loomweave; theclarion-workflowprompt/ skill →loomweave-workflow. - Environment variables
CLARION_*→LOOMWEAVE_*; the federation/suite variablesCLARION_LOOM_*(e.g.CLARION_LOOM_TOKEN) →WEFT_*(e.g.WEFT_TOKEN) — they name the framework, not the product. - Error / diagnostic codes prefix
CLA-→LMWV-(e.g.CLA-INFRA-STORAGE-FOREIGN-DB→LMWV-INFRA-STORAGE-FOREIGN-DB); the ADR-022 pluginrule_id_prefixgrammar core prefixCLA-→LMWV-. - Documentation/site repository
github.com/tachyon-beep/clarion→github.com/foundryside-dev/loomweave; docs domainclarion.foundryside.dev→loomweave.foundryside.dev.
These touch the wire contract shared with sibling products and require the peers to be updated in step (the peer pins/clients are being renamed together):
- Federation HTTP read API routes
/api/loom/...→/api/weft/...; identity headersX-Loom-Component/X-Loom-Nonce/X-Loom-Timestamp→X-Weft-*; theX-Loom-Componentidentity valueclarion:<hmac>→loomweave:<hmac>.api_versionstays1(a rename is not a wire-incompatible change). - Federation JSON field names
loom_*(e.g.loom_files,loom_findings,loom_component) →weft_*. - The Filigree entity-association field
clarion_entity_id→loomweave_entity_id. - The Stable Entity Identifier (SEI) prefix
clarion:eid:→loomweave:eid:(ADR-038 / the Weft SEI conformance standard).
- Recut
1.3.0→1.0.0across the workspaceCargo.toml, everypyproject.toml/plugin.toml, and the Python plugin__version__.
- Python plugin consumes Wardline's NG-25 trust-vocabulary descriptor
(ADR-018 Revision 3). The Python plugin now reads Wardline's descriptor from
.wardline/vocabulary.yamlor the installedwardline/core/vocabulary.yamldata file without importing Wardline. Functions and classes decorated with Wardline trust decorators (external_boundary/trust_boundary/trusted) receivewardlineentity metadata andwardline:*tags when the descriptor is available; a missing, invalid, or version-skewed descriptor degrades honestly to normal structural extraction. This fully retires the Loomweave-sidewardline.core.registrystartup coupling (federation asterisk 2, registered at~/loom/asterisk-register.md): plugin startup performs zero in-process Wardline import, so the plugin no longer requires a co-installed Wardline and is robust to Wardline's upcoming native core. Plugin-only change (no Rust-core / protocol / ontology change); tracked atclarion-881e9834bc.
- Filigree issue lookups key by Stable Entity Identity (SEI). The MCP
entity_issue_listpath and the federation Filigree client resolve issues by SEI rather than source locator, aligning issue enrichment with Loomweave's stable identity (one key per entity — SEI xor locator, no per-row fallback). - Refreshed release-facing README / index documentation for the 1.3.0 release line, including the 39-tool MCP surface, current install artifact names, fixed ADR/docset links, current web/operator quick starts, and the full end-to-end verification list.
- Archived tracked architecture-analysis working notes out of live
temp/directories underdocs/archive/working-notes/.
- Release-governance gate script (
scripts/check-github-release-governance.py). Release-governance enforcement is handed off to Legis;release.ymlno longer invokes the script and the standalone check is removed from the tree. - In-repo agent-instruction files (
CLAUDE.md,AGENTS.md). Agent conventions now derive from the~/loomfederation hub plus local untracked copies; both files are removed from the tracked tree and gitignored. - Bundled Filigree-workflow skill (
.agents/skills/filigree-workflow/SKILL.md). Removed from the tracked tree alongside the agent-instruction files.
loomweave doctorreports enrich-only integration bindings as a warning, not a gate failure (federation-axiom compliance). A missing or stale Loomweave+Filigree+Wardline binding previously mapped toproblem(exit 1), which made an enrich-only sibling effectively required — contradictingweft.md§5. Both the JSON and text doctor paths now reportwarningfor missing/stale bindings; unparseable bindings and--fixrepair failures remainproblem. A bareloomweave doctoron a no-bindings (Loomweave-solo or Loomweave+Filigree-only) project now exits 0 with the warning surfaced.
- Closed a config-driven command-execution path from untrusted repository
contents (
clarion-4b5a8aff54).loomweave analyze(the SEI git-rename signal) andloomweave serve(theindex_diff_getfreshness/drift report) shelledgitinside the analyzed repository with repo-local configuration and Git attributes enabled, so a malicious repository could execute arbitrary commands as the local user during an ordinary analyze/serve — viacore.fsmonitor, an external diff/textconv driver, or afilter.<name>.cleanselected by afilterattribute. All corpus-facinggitcalls now route through a single hardened helper (loomweave_core::hardened_git_command) that ignores operator/global/system config, strips config/exec-injecting environment variables, overrides the program-naming repo-local keys via highest-precedence-cflags (includingcore.fsmonitor=falseandcore.attributesFile=), and neutralizes the attribute sources it can — the in-tree.gitattributesvia--attr-source=<empty-tree>and the system file viaGIT_ATTR_NOSYSTEM. The one source no config flag can disable,$GIT_DIR/info/attributes, only triggers a filter when Git hashes working-tree content, so the call sites no longer do that on an untrusted corpus: the rename signal usesgit diff --cached(index-vs-HEAD; still catches stagedgit mvrenames) and the freshness probe replacesgit statuswithgit diff --cachedplus the existing stat-based per-file drift check. Behavior change:index_diff'sdirty_filesnow lists staged changes only — unstaged working-tree modifications and untracked files are no longer enumerated there (unstaged edits to indexed files still surface inmodified_since_analyze). Signals remain best-effort and enrich-only. The--attr-sourcebelt-and-suspenders is applied only when a one-time probe confirms Git >= 2.40; older Git omits it and stays both safe (the--cachedcall sites carry the actual protection) and fully functional, so no minimum-Git floor is introduced. Reported externally and re-verified with working PoCs across all attribute sources; relates to the untrusted-corpus posture of ADR-021.
- Guidance maturity — WS6 (REQ-GUIDANCE-03/-05/-06; ADR-007, ADR-024). The
guidance system moves from schema baseline to operator-usable.
loomweave guidanceCLI —create/edit($EDITOR) /show/list/delete/export/import. Match-rule syntax (path:/tag:/kind:/subsystem:/entity:), scope-levels (project→function), and--expiresnormalisation to a full ISO-8601 instant. Sheets are written via a new non-run-scopedloomweave-storageguidance API, and the rule-matcher is lifted intoloomweave-storageas the single source of truth shared by the CLI,analyze, and the MCP read path.- Staleness findings (
analyze).LMWV-FACT-GUIDANCE-ORPHAN(WARN) now also fires for amatch_rules {entity:…}rule pointing at a deleted entity (wasguides-edge only); newLMWV-FACT-GUIDANCE-EXPIRED(INFO) andLMWV-FACT-GUIDANCE-CHURN-STALE(WARN, confidence 0.7 heuristic, asymmetric threshold 50 / 20-pinned). Surfaced vialoomweave guidance list --stale(review-cadence age) /--expired. CHURN-STALE is honest-empty untilgit_churn_countpopulation lands. - Team import/export.
export --to <dir>/import <dir>— deterministic one-file-per-sheet sorted-key JSON, additive idempotent import, loud-fail on malformed input. - Cache invalidation. Authoring (create / edit / delete / import) eagerly invalidates the summary cache of matched entities (ADR-007 churn-eager invalidation).
- Deferred with tracking issues: the agent-mediated propose→promote lifecycle (no observation-write transport), Wardline-derived generation, the in-browser staleness-review UI, and guidance composition into summary generation.
- Git-rename provider seam now operative — WS9 / SEI §6 (REQ-C-05).
analyzedrives the committed rename window so thelegisGitRenameSourceis actually consulted, closing the window gap previously surfaced indocs/federation/contracts.md. Each run records the gitHEADit analyzed on the run row (migration0007, new nullableruns.analyzed_at_commit; schema version 6 → 7) and reads the prior run's commit to query renames over<prior_commit>..HEAD. The SEI mint pass now unions two complementary windows (gather_git_renames): the working tree (uncommitted renames, shellgit diff -M HEAD, always) and the committed range (committed renames vialegiswhen--legis-urlis set and reachable, else a shell fallback). Enrich-only and never a regression — withoutlegis, or with no prior commit, only the working-tree window runs (byte-identical to pre-WS9, no HTTP). The prior-commit read excludes the current run (whichCommitRunmarkscompletedbefore the mint pass), so the committed window never collapses to<HEAD>..HEAD.analyzealso applies any pending migrations on startup (under the analyze lock) so a binary upgrade does not hard-fail on a DB thatinstallhas not re-touched. - Stable Entity Identity (SEI) — Wave 1 / WS1 (ADR-038). Loomweave is now the
suite's identity authority: it mints a durable, opaque SEI
(
loomweave:eid:<blake3(locator ++ 0x00 ++ mint_run_id)[:32]>) for every entity and demotes the{plugin}:{kind}:{qualname}id to a mutable locator, so cross-tool bindings survive rename and move.- Migration
0005addssei_bindings(durable identity store, keyed by SEI, decoupled from the cumulativeentitiestable) +sei_lineage(append-only event log) + a plainentities.signature TEXT. Schema version 4 → 5. - A deterministic, fail-closed re-binding matcher (
sei.rs) carries an SEI on an unchanged locator, a git-detected rename with an identical body (locator_changed), or an identical body+signature at a new locator (moved); it mints a new SEI and orphans the old binding whenever sameness cannot be proven. A back-to-back unchanged re-run carries (never re-mints) every SEI. The git-rename signal is consumed behind a typedGitRenameSourceseam (REQ-C-05); v1 shipsShellGitRenameSource. - The analyze pipeline runs an SEI mint pass after each successful run;
--no-seiskips it. The Python plugin emits a versionedsignatureobject per function/class (plugin.toml [signature]). - HTTP read API:
POST /api/v1/identity/resolve(+:batch),GET /api/v1/identity/sei/{sei},GET /api/v1/identity/lineage/{sei}.resolvefail-closed-rejects an SEI-shaped input by the reservedloomweave:eid:prefix (REQ-F-02)._capabilitiesadvertisessei: { supported: true, version: 1 }. - The MCP tool surface carries the
seialongside every entity id (no MCP locator exception — REQ-C-04), via a read-timesei_bindingsjoin. - The shared SEI conformance oracle (SEI standard §8) is authored and
passes; the cross-tool hard-cutover backfill is documented in
docs/federation/sei-migration-playbook.mdand surfaced for owner-gated scheduling.
- Migration
- Incremental analysis — Wave 2 / T3.1.
loomweave analyzenow skips files whose whole-file hash matches the prior run, reusing their entities (the entity graph is cumulative and edges are insert-or-ignore, so the skip is speed-only).skipped_filesis reported instats.jsonand askipped_unchangedprogress event is emitted;--no-incrementalforces a full re-index. The skip is guarded against the SEI matcher: the current-locator set is the union of re-analysed and skipped-file entities, so an unchanged file's identities are never falsely orphaned, and skipped entries are re-fed into the prior-index rebuild so the snapshot does not decay. Files carrying a secret finding are never skipped (their finding anchor must stay stable). - Dossier participation surface — Wave 2 / WS4. The exact Loomweave HTTP slices
the cross-tool dossier assembler (Wardline) reads are pinned in
docs/federation/contracts.mdand specified indocs/superpowers/specs/2026-06-02-loomweave-dossier-participation.md: identity (resolve→ SEI + content-axis freshness;resolve_sei/lineage→ identity-axis freshness), structural linkages (callers/callees), and file context. Loomweave contributes slices and the SEI join key; it does not proxy Filigree associations (read directly from Filigree's own ADR-029 endpoint) or assemble the envelope. Proven end-to-end against a renamed-function fixture (serve_http_dossier_participation_surface_serves_a_renamed_function). legisgovernance consumption — Wave 3 / WS9 (governed paradise).legisconsumes Loomweave's stable identity as an opt-in governance layer a solo project never sees; core paradise (Wave 2) does not depend on it.- Git-rename provider seam (REQ-C-05). A second
GitRenameSource,LegisGitRenameSource, readslegis'sGET /git/renamesover HTTP and feeds the same file→locator translation asShellGitRenameSource—legissupplies the git signal with no matcher change (SEI spec §6). Selection (select_git_rename_source,--legis-url) is enrich-only and capability-aware: the shell source remains the default and fallback; an unset/unreachablelegisissues no HTTP and is byte-identical to before. The two suppliers observe different rename windows (Loomweave'sanalyzedepends on the working-tree window;legisserves only committed rev-ranges), so the seam is built/tested/ready but inert in the default pipeline untillegisadds a working-tree surface or Loomweave drives a committed re-index — a gap surfaced (not papered) indocs/federation/contracts.md. The matcher is fail-closed regardless, so neither window can cause a false carry. Proven byselector_keeps_working_tree_rename_even_when_a_reachable_legis_sees_nothing. - Audit-spine consumption.
legisreads Loomweave's existingresolve/resolve_sei/lineageroutes as its governance audit spine; the consumption contract is pinned indocs/federation/contracts.md. Per REQ-L-01 (Option 3)legisowns integrity at its own boundary (snapshot-hash over polled lineage) — Loomweave ships no lineage hash-chain or signature. - No trust adjudication. Loomweave carries the trust vocabulary verbatim and
adds no policy/attestation engine — Wardline analyses,
legisgoverns, attestations key on Loomweave's SEI.
- Git-rename provider seam (REQ-C-05). A second
guidance_forno longer drops expiry-bearing sheets in production. The MCP read path compared a sheet's ISOexpireslexically against the server clock, whose production default is aunix:<seconds>string — so every sheet carrying anyexpiressorted as "expired" and was silently excluded from composition. The comparison now parses both forms to seconds (fail-open on unparseable input), guarded by a regression test that runs under the production clock (clarion-3153e74f0b).
1.1.0 — 2026-05-31
-
Wardline taint-fact store (ADR-036). Loomweave now serves as the persistent read+write store for Wardline's taint facts over HTTP, keyed to Loomweave entity qualnames. New migration
0003adds thewardline_taint_factstable; facts are written through the storage writer-actor (WriterCmd::UpsertWardlineTaintFact) and resolved/fetched via the newwardline_taintstorage module. Routes:POST /api/wardline/resolve— exact-tier qualname → entity resolution.POST /api/wardline/taint-facts— exact-only batch write; the Wardline payload is stored byte-verbatim (serde_json::value::RawValue) so Loomweave never reshapes Wardline's JSON.GET /api/wardline/taint-factsand…:batch-get— reads carry a live freshness hash so a consumer can detect drift against the entity's current content.
The write path is opt-in via
serve.http.wardline_taint_writeconfig plus an optional writer-actor, and disabled by default. -
Flow B — read-time Wardline finding reconciliation (enrich-only).
issues_forandorientation_packnow attach awardline_findingssection reconciled against Wardline findings stored in Filigree. A pure qualname-reconciliation module matchesmetadata.wardline.qualnamebyte-exact against entity-ID segment-3; a two-hop Filigree read (GET /api/weft/files→GET /api/weft/findings) resolves a path to its findings. Per the enrich-only axiom, any unreachable hop degrades the section toresult_kind: "unavailable"rather than failing the tool. -
loomweave doctor [--fix]. A new subcommand that verifies — and with--fixrepairs in place — the installed agent-orientation surfaces: theloomweave-workflowskill pack, theSessionStarthook in.claude/settings.json, and theloomweaveentry in.mcp.json(whichloomweave installdoes not register automatically). It prints a per-surface ✓/✗ report plus the index snapshot and exits non-zero when any problem remains, so it is usable as a CI / pre-commit gate. Repairs reuse the same idempotent installers asloomweave install, and the.mcp.jsonmerge is never-clobber: sibling servers and a deliberately customisedcommandare preserved (only the--pathargs are corrected).
- Federation contracts pinned/clarified: the Wardline taint-store routes +
freshness contract, the two consumed weft routes for Flow B, Loomweave→Filigree
ephemeral-port endpoint discovery, and the
scan_run_idcontract (stale Phase-0 handshake references removed). docs/suite/weft.md: added a written retirement condition to the §5 asterisk-2 (Wardline→Filigree pipeline coupling), and refreshed the §9 status table to the post-1.0 state.- ADR-036 accepted (Loomweave as Wardline taint-fact store), documenting the in-process two-writer concurrency posture.
- The Python round-trip self-test now hard-fails (instead of silently skipping)
when the installed
loomweave-plugin-pythonentry point is missing, so a broken editable install cannot pass CI green. - Shared error vocabulary (ADR-037). New
loomweave-core::errorsmodule is now the single typed source of truth for both wire error-code vocabularies:HttpErrorCode(federation HTTP read API,SCREAMING_SNAKE_CASE, moved out ofhttp_read.rs) and a newMcpErrorCode(MCP tool envelope, kebab-case) that replaces ~47 bare string literals with compiler-checked variants. The two surfaces keep their established wire spellings — co-located, not merged, since they have disjoint vocabularies and independent consumers — and drift tests pin every wire string at the definition site. Wire output is byte-identical on both surfaces; no consumer change. Closes the MCP/HTTP error-code drift smell (V11-ARCH-01).
wardline_findings_for_pathno longer silently undercounts: a truncated findings page (has_more) now fails closed tounavailablerather than returning a partial result, mirroring the existing hop-1 truncation handling.- Wardline metadata block is now surfaced in finding output, with truncation-safe
no_matcheshandling and a corrected tool description. - De-duplicated the Filigree HTTP client GET paths:
associations_forandissue_detailnow route through a sharedget_json/get_json_or_none, preserving the404→ enrich-only-degrade semantics.
1.0.1 — 2026-05-30
1.0.0 was tagged but its release failed to publish (the macOS build broke at tag-cut), so no 1.0.0 artifacts exist. 1.0.1 is the first published build and carries the full post-1.0.0 scope below plus the build fix.
loomweave db backup <output>— a consistent, WAL-safe online backup of.loomweave/loomweave.dbviarusqlite::backup::Backup. Safe to run during a liveloomweave analyze(captures outstanding WAL frames into a standalone single-file copy, unlikecp), writes atomically (temp sibling + rename), refuses to clobber without--force, and verifies the copy withPRAGMA integrity_checkbefore promoting it. Closes gap-register STO-04 (clarion-6d433b61ba).source_for_entity(id, context_lines=10)MCP tool — returns an entity's exact indexed source span (decorators/signature/docstring included as captured) plus a bounded window of line-numbered context, each line flaggedin_entity. No LLM call. Reports an explicitsource_status(missing/no_range/binary/drifted) rather than a misleading stale snippet when the on-disk source no longer matches the indexedcontent_hash. The MCP surface now exposes twelve tools (clarion-6077738f1c).call_sites(id, role=caller|callee, kind?, confidence?, path?)MCP tool — shows the actual source sites behindcalls/referencesedges (file, line, byte column, line text, edge kind, confidence) so an agent can see why Loomweave believes an edge exists. Statically-unbindable calls are returned in a separateunresolved_siteslist, never mixed with resolved evidence. Filterable by edge kind and a documented best-effort production/test path heuristic. No LLM call. The MCP surface now exposes thirteen tools (clarion-9392f74881).- Filigree finding emission (WP9-B core, REQ-FINDING-03).
loomweave analyzePhase 8 POSTs the run's persisted findings to Filigree'sPOST /api/v1/scan-resultsintake, with Loomweave's richer fields nested undermetadata.loomweave.*(wire contract pinned indocs/federation/contracts.md). Emission is enrich-only — gated behindintegrations.filigree.{enabled,emit_findings}(now both defaultfalse, so enabling Filigree forissues_forreads never silently starts outbound emission — clarion-a26de2f368), and any Filigree-side failure is recorded instats.json(LMWV-INFRA-FILIGREE-UNREACHABLE) instead of failing the run. Findings anchored to abriefing_blockedentity are excluded, matching the fail-closed read posture (clarion-8b32ba0d02). Resolves the 1.0 "finding emission deferred" limitation below. loomweave analyze --resume RUN_ID(WP9-B, REQ-FINDING-05). Reopens a prior run'srunsrow (a newWriterCmd::ResumeRunUPDATEs it back torunninginstead ofINSERTing, which conflicted on the existing run PK), re-walks the tree, and emits findings to Filigree withmark_unseen=falseso the re-emit does not flip the prior run's findings tounseen_in_latest. The re-walk is idempotent: entities and run-scoped findings now both UPSERT onid(previously only entities did), so a resumed run reproduces the same durable graph as the original. The emittedmark_unseenvalue is recorded instats.json. Tracked under clarion-dd29e69e0e.loomweave analyze --prune-unseen(WP9-B, REQ-FINDING-06). After emission (Phase 8b), POSTs Filigree'sPOST /api/weft/findings/clean-staleretention route, scoped toscan_source=loomweave, asking it to soft-archive its ownunseen_in_latestLoomweave findings older thanintegrations.filigree.prune_unseen_days(default 30). Soft-archive, not delete: Filigree moves them tofixedand auto-reopens on reappearance (Filigree ADR-015). Enrich-only — a Filigree outage or the integration being disabled is recorded instats.json(filigree_prune) and never fails the run; thescan_sourcescoping is enforced server-side so the sweep can only touch Loomweave's findings. (Closes the REQ-FINDING-06 piece of clarion-dd29e69e0e; the route was found to already exist in Filigree, so the earlier "file a request" memo is superseded — see its withdrawal banner.) The remaining Phase-0 scan-run-create handshake is an open contract question with Filigree (Loomweave relies on the peer tolerating an unknownscan_run_id), tracked separately underrelease:1.1.
entitiesgains abriefing_blockedVIRTUAL generated column (json_extract(properties, '$.briefing_blocked')) plus a partial index (ix_entities_briefing_blocked WHERE briefing_blocked IS NOT NULL), so the federation read-API hot path can filter entities withheld from briefings in SQL instead of parsing every row's properties JSON.project_statusnow reports acounts.briefing_blockeddiagnostic (how many entities are withheld), served by the new index. Edit-in-place in migration0001per ADR-024 (no published build). Closes gap-register STO-04 / V11-STO-04 (clarion-bdabfd6bca).- The writer actor now opens its batch transactions with
BEGIN IMMEDIATE(via a newloomweave_storage::retry::begin_immediatehelper with boundedSQLITE_BUSY/SQLITE_LOCKEDretry + exponential backoff) instead of a deferredBEGIN. Taking the write lock up front resolves cross-process write contention at lock-acquire — wherebusy_timeoutis honored — rather than failing mid-statement on a deferred-lock upgrade the busy handler cannot serve. Closes gap-register STO-05 (clarion-bbb3365920).
- macOS release build under
-D warnings. The Linux-onlyprlimithelpers imported/defined inloomweave-core::plugin::host(and two Linux-only test sites inloomweave-mcpandloomweave-cli) were unused on*-apple-darwin, so the release build failed with unused-import / dead-code errors. They are nowcfg-gated totarget_os = "linux"(plustestwhere unit tests reference them). CI gained a native macOS (aarch64) build + clippy leg so the gap can't recur; the x86_64 (macos-13) leg is temporarily parked while those runners are offline (clarion-12667da9f5, clarion-ec389a8e72).
1.0.0 — 2026-05-19
First publishable release. Loomweave ships as a Rust core (loomweave binary, five
workspace crates) plus an editable-install Python language plugin
(loomweave-plugin-python). Released under the MIT License.
Targets the v1.0.0 tag (cut by the operator once all release blockers are
green); supersedes the pre-release v0.1-sprint-1 and v0.1-sprint-2
working tags, which remain in the repo as historical anchors.
loomweave install --pathinitialises a project's.loomweave/directory (instance ID, SQLite DB, migrations).loomweave analyzewalks a Python corpus and persists the structural graph (entities +contains,calls,references,importsedges) to a local SQLite store via the writer-actor pattern (ADR-011).loomweave serveexposes the MCP stdio surface for consult-mode agents:entity_at,find_entity,callers_of,execution_paths_from,summary,issues_for,neighborhood,subsystem_members.
- Pyright-backed entity extraction for functions, classes, and modules; resolved / ambiguous / inferred call edges per ADR-022.
wardlineruntime probe with version-range pinning (>=1.0.0,<2.0.0).- Module-level
importscandidate edges (Phase 3 Task 3). - Strict-typed L4 JSON-RPC handshake with declared
entity_kinds,edge_kinds,ontology_version, andrule_id_prefix(ADR-022).
The publisher-side of Loomweave's federation contract with Filigree's
LoomweaveRegistry. Pinned in docs/federation/contracts.md;
fixtures under docs/federation/fixtures/ are
normative.
GET /api/v1/_capabilities— registry-backend probe, returnsinstance_id,api_version: 1, and feature flags. Always unauthenticated so siblings can discover the surface pre-auth.GET /api/v1/files?path=&language=— single-file identity resolution. Closed error envelope{error, code}with codesINVALID_PATH,PATH_OUTSIDE_PROJECT,NOT_FOUND,BRIEFING_BLOCKED,UNAUTHENTICATED,BATCH_TOO_LARGE,STORAGE_ERROR,INTERNAL. ETag /If-None-Matchsupported.POST /api/v1/files/batch— bulk resolution, up to 256 queries per request, single pooledReaderPoolcheckout per batch. Four-way partitioning:resolved/not_found/briefing_blocked/errors.- Bearer authentication.
serve.http.token_env(defaultWEFT_TOKEN) names the env var holding the inbound bearer token. Loopback-without-token stays unauthenticated for the v0.1 trust model; non-loopback-without-token is refused at startup withLMWV-CONFIG-HTTP-NO-AUTH. - Briefing-blocked propagation. Files flagged by the pre-ingest secret
scanner return
403 BRIEFING_BLOCKEDon the single-file endpoint and surface in thebriefing_blocked[]partition on the batch endpoint. Identity fields (entity_id,content_hash,canonical_path,language) are deliberately omitted from blocked responses so siblings cannot infer file identity from a refusal.
- Pre-ingest scan annotates entities with
briefing_blockedwhen a file contains high-entropy or pattern-matched secrets; ingest proceeds, but every federation read path refuses to surface the entity.
- Storage-side queries for subsystem membership and inverse lookup.
- Analyze-time clustering writes subsystem entities and
in_subsystemedges. subsystem_members(id)MCP tool surfaces cluster members to consult agents.
- OpenRouter (default, requires
OPENROUTER_API_KEY). - Codex CLI and Claude CLI as local-login providers — no API key surface, the user's OS-level auth carries.
recordingprovider for deterministic test fixtures.
- ADR-023 tooling baseline:
cargo fmt --check,cargo clippy -D warnings,cargo nextest,cargo doc -D warnings,cargo deny,ruff,ruff format --check,mypy --strict,pytest, end-to-end walking-skeleton script — all enforced in CI. - Pre-commit hooks wire the Python gates.
.envloaded from CWD or ancestor before tracing setup.
- Python only. Other-language plugins (
NG-15) are v2.0+ scope. - Filigree finding emission deferred to a future release (tracked under
release:v1.1). Cross-product POSTing of Loomweave-generated findings into Filigree's intake (WP9-B) is deferred per the Sprint 2 scope amendment.issues_for(id)(the WP9-A binding for reading from Filigree) ships in 1.0. (WP9-B core shipped post-1.0 — see the Filigree-finding-emission entry under Unreleased; only the REQ-FINDING-05/-06 lifecycle tail remains deferred.) - HTTP file language inference uses persisted plugin manifest language when available, with a narrow core-extension fallback for files that predate manifest capture.
- Cooperative HMAC inbound auth ships for the HTTP read API via
serve.http.identity_token_envandX-Weft-Component: loomweave:<hmac>. The older bearer-token path remains available for compatibility. - Python plugin imports
wardline.core.registry.REGISTRYat startup (weft.md §5 asterisk 2). Initialization coupling scoped to the Wardline-aware plugin only; Loomweave core and non-Wardline-aware plugins are unaffected. Retirement condition: Wardline ships a stable runtime probe API. - Wardline state-file ingest deferred to a future release (tracked under
release:v1.1). Only thewardline.core.registry.REGISTRYversion-pin probe ships in v1.0; the state-file readers forwardline.yaml+ overlays,wardline.fingerprint.json,wardline.exceptions.json, thewardline.sarif.baseline.jsontranslator baseline, and the three-scheme identity-reconciliation oracle (REQ-INTEG-WARDLINE-02 through -06) all land with WP9-B / WP10. - Pre-WP5 catalogue upgrade requirement. Briefing-blocked annotations
are stored as a JSON property on file entities at v1.0 (v1.1 promotes
the field to a typed column). A v1.0 binary opening a
.loomweave/loomweave.dbproduced by a pre-WP5 binary finds nobriefing_blockedproperties — pre-WP5 analyzers never wrote them — and will serve the entire catalogue without refusal. Operators upgrading from a pre-WP5 install MUST runloomweave analyze(scanner active by default) against the project root before exposing the HTTP read API or calling thesummaryMCP tool. Seedocs/operator/secret-scanning.md.
- Design ladder under
docs/loomweave/1.0/—requirements.md,system-design.md,detailed-design.md. - ADRs under
docs/loomweave/adr/— 28 Accepted at 1.0 (ADR-001…ADR-034 with the documented Backlog/Superseded subset excluded). ADR-012 is superseded by ADR-014, whose Security Posture and Error Envelope are in turn partially extended by ADR-034 for the Sprint 3 federation hardening. Four ADRs (ADR-009, ADR-010, ADR-019, ADR-020) remain Backlog and are tracked insidesystem-design.md§12 /detailed-design.md§11 until promoted. - Weft-suite doctrine at
docs/suite/weft.md. - Federation contract surface at
docs/federation/contracts.md. - Operator guides under
docs/operator/— getting-started, OpenRouter setup, HTTP read API.