Skip to content

Releases: tanlnm512/cairn

0.22.0

Choose a tag to compare

@github-actions github-actions released this 09 Oct 17:39

[0.22.0] - 2026-10-10

Added

  • Parser conformance matrix in docs/indexing.md: one row per golden-fixtured language (Rust joins as the 15th), rendered by scripts/gen_conformance_table.py between markers and kept fresh by a staleness test; every row is green or carries an explicit tier mark (no import/hierarchy edges).
  • Pyright upgrade pass is now budgeted and on by default: cairn build upgrades ambiguous Python call edges when pyright is available, capped by a wall-clock budget (60 s default) and a per-build edge budget (2,000 default), both configurable via cairn.json (lsp.budget_seconds, lsp.edge_budget); --lsp forces an unbounded pass, --no-lsp skips. Upgrades persist, so a budget-stopped pass resumes from the remainder on the next build, and the report carries probed/budget_hit for observability.
  • Comment sweep: the comment-style baseline fell from 1213 to 226 grandfathered violations (81% removed) across telemetry, memory, graph, mcp_server, cli, dashboard, parsers, knowledge, and agent_install, with 321 migration ledger rows landing 317 durable rationales in tribal memory (Why/How bodies, ledgered before deletion) and executable ASTs proven identical per area; python -m cairn.cli.system.audit_status|comment_style no longer emits the runpy double-import warning (deferred collector imports in report.py), and scripts/regen_scip_pb2.sh now emits the trimmed _scip_pb2.py header so regeneration cannot reintroduce debt.
  • Quality ratchet: make audit-status prints remaining-vs-total audit findings by priority from docs/audits/2026-10-02.md plus a strict .status.json fix sidecar, and make comment-style enforces the AGENTS.md comment contract over src/ through a machine-generated shrink-only baseline (comment-style-shrink re-derives it after fixes; growth fails). Both gates run as the check-comment-lengths pre-commit hook and the quality-ratchet CI job, expose ARGS=--json, and surface as a count-only quality_gates section in cairn report. The legacy root architecture.html and audit report moved to docs/diagrams/ and docs/audits/.
  • Rationale indexing: cairn build captures comments whose text begins
    NOTE:, WHY:, or HACK: in every language with a mapped comment node
    type and persists them in an additive rationale table, each record
    attributed to the innermost enclosing callable or type whose span
    contains the comment line (file-level otherwise; one record per comment
    with continuation lines folded into the text; docstrings never produce
    records, and TODO:/FIXME: markers are out of scope). The new
    cairn rationale command (--symbol/--file targets, --db, --json)
    prints records ordered by line with kind tags (note/why/hack); MCP
    explore output adds a gated Rationale section when any matched symbol
    has records and omits it otherwise, with the MCP tool count unchanged;
    incremental reindex and cairn update delete and re-derive each affected
    file's rationale rows together with its symbols, so removed markers never
    linger.
  • Freshness hooks: cairn update --diff-ref A..B scopes changed-file
    detection to a git ref range (range diff only — the untracked pass and
    stat fallback are skipped, and both endpoints are pre-validated so a bad
    ref is a clean error); cairn hooks install/uninstall manage a
    post-commit hook (backgrounds a ranged update after every commit — the
    previous commit resolves from the reflog, with an empty-tree range
    fallback on a repo's first commit — plus cairn validate-paths --mark,
    output discarded so the commit never waits) and a post-checkout hook
    (branch switches only; file checkouts no-op); cairn init --with-hooks
    installs both hooks opt-in and non-interactively. Hooks are never
    overwritten when foreign and removed only when cairn-marked; in a
    non-git workspace hooks install prints guidance and exits 1 while
    init --with-hooks warns and init still succeeds — no partial hooks
    either way.
  • cairn communities command: deterministic Louvain community detection over
    structural edges, persisted to the communities/symbol_communities
    derived tables with global and per-community hub symbols (--top-k,
    default 10); a store with no structural edges reports "no communities
    found". Requires the new [graph-analytics] extra (pip install 'cairn[graph-analytics]') — without it the command exits with the install
    hint and leaves the store untouched.
  • Dashboard /communities view: renders the partition with community sizes,
    hub symbols, and member drill-down (nav under Explore, after Graph).
  • HTTP serving: cairn serve --transport http exposes the full MCP tool
    registry over Streamable HTTP with bearer-key auth (CAIRN_MCP_API_KEY
    env or --api-key, flag wins), loopback-default binding with keyless
    operation restricted to loopback binds (a non-loopback bind without a key
    refuses to start), Host-header transport security per bind class, an
    unauthenticated /healthz probe, an optional --stateless mode for
    load-balanced deployments, and a read-only default; ships with a slim
    non-root Dockerfile (CAIRN_HOME=/data volume, HTTP entrypoint) and
    deployment docs. Local stdio and SSE transports are unchanged.
  • Memory stance overlay: memories carry an optional stance (preferred /
    tentative / contested, orthogonal to the lifecycle tiers);
    cairn memory record --stance preferred|tentative|contested declares a
    prior at record time, and the new cairn memory reflect recomputes
    stances across the store from supersession and citation-verification
    evidence — a memory superseded by a peer when the pair shares a symbol
    ref that still verifies is contested and names that peer, a memory whose
    refs-verified fraction dropped below its recorded baseline downgrades to
    tentative, a memory whose every cited ref verifies is preferred, and the
    evidence verdict overrides a declared prior on conflict while the prior
    survives when evidence yields no verdict. Reflect touches stance
    metadata only — never bodies, titles, tiers, or scores — and is
    idempotent and deterministic on an unchanged store; stance renders
    inline in cairn memory search / list output and MCP
    recall_memory / explore output.
  • cairn prs: one read-only PR-triage command fusing GitHub state with the
    local graph — a six-column open-PR list (number, title, branch, author,
    CI state conservatively classified pass/fail/pending/none from
    statusCheckRollup, review decision) sourced from the gh CLI over the
    workspace's remote; --impact PR|branch resolves the PR's diff (fetched
    via gh pr diff, never local git) against its base ref to changed
    symbols with dependents (depth + resolution), listing unindexed and
    deleted changed files explicitly and stating the local index's build age
    (Store: local index (built <age>|never)) so impact against a stale
    store is visible; --conflicts ranks open-PR pairs by shared-community
    overlap of their touched symbols (largest overlap first, PR-number
    tie-break), consuming the communities/symbol_communities tables
    (never building them) and printing a run cairn communities hint
    instead of failing when the tables are absent or empty; --json emits
    the full report payload (store/prs/impact/conflicts) for agents.
    Strictly read-only on both sides: the store opens read-only with no
    freshness refresh, and gh runs only as a subprocess with pinned
    list/view/diff argv (30 s timeout, no tokens read, logged, or passed) —
    gh missing, unauthenticated, timing out, or erroring surfaces as one
    actionable error with no partial table.

Fixed

  • A4 retro of the post-audit admin-merged PRs: cairn build --repo no longer
    crashes with an IntegrityError on files containing NOTE:/WHY:/HACK:
    comments and no longer strands a permanent building marker (the repo-scoped
    rebuild now clears rationale rows before their foreign-key parents); the
    dashboard Communities page renders an empty panel on stores created before
    community indexing instead of erroring.
  • Full-codebase audit wave (2026-10-02): 141 findings and 3 systemic clusters
    triaged; every P0, P1, and P3 finding is now closed (59 fixed, including 2
    added by the A4 retro; the remaining 87 P2 polish findings are tracked in
    the audit sidecar) across the graph, parsers, memory/LLM, MCP server,
    dashboard, wiki, knowledge, CLI, install/uninstall and scripts surfaces.
  • Hooks no longer silently no-op in source checkouts: python -m cairn.cli.main
    runs the CLI (missing __main__ guard), the hook fallback sites work, and the
    impact guard tolerates empty tool output.
  • Graph reads converge when a parser wheel is missing: unavailable-language
    files are skipped by the drift and build scans (recorded as parser-unavailable
    skips), dropped on reindex even when never indexed, and counted so strict
    refresh settles instead of raising on every read.
  • Incremental updates no longer drop cross-repo imports edges; delete-only
    diffs contribute blast-radius seeds; git octal escapes and quoted renames
    resolve to real paths; trace_flow visits each id once on diamond graphs;
    taint finds source→sink paths through the entry symbol.
  • Memory lifecycle on the declared Python 3.10 floor: Z-suffixed timestamps
    parse (purge actually purges), aware/naive timestamp mixes degrade instead of
    crashing decay and batch-critic, memory_refs delete the id form writers
    persist, task complete/drop races are locked with the claimer enforced, and
    refusals no longer report as drops.
  • Parsers: Swift properties and initializers emit symbols (goldens
    regenerated), Kotlin primary-constructor default call edges and TypeScript
    generic implements edges are restored, decorators land on their own
    declaration, and external SCIP indexers run inside the target repo.
  • Dashboard: chains span no longer errors on NULL tim...
Read more

0.21.2

Choose a tag to compare

@github-actions github-actions released this 29 Sep 03:36

[0.21.2] - 2026-09-29

Added

  • Dashboard Memory detail pages: /memory/{tier}/{slug} renders a memory's
    body, identity, promotion history, signals and supersedes/superseded-by
    links, and the Memory list's titles link them.
  • Dashboard knowledge graph covers the whole knowledge layer: memory items
    join the docs as nodes (diamonds, tier as family) and their frontmatter
    supersede pairs draw as directed edges; the node-click inspect panel
    resolves memory ids and links the memory detail pages.

Changed

  • Test-suite audit: ~200 tests removed or trimmed under the "one owner test
    per contract / no implementation mirrors" policy — source-text mirror tests
    (CSS/JS greps, import allowlists, DRY lints), near-duplicates of owner
    tests, private-constant pins, and trivially-true smoke asserts. Distinct
    edge coverage was folded into the owning tests; test-only seams
    (MemoryStore/OKFMemoryStore/InMemoryMemoryStore, try_generate_index,
    reset_probe_cache, reset_tokenizer_mode) moved into the test suite or
    were deleted.
  • Documentation audit refresh: current CLI/MCP surfaces, 15-language parser
    set, optional extras, architecture diagrams, and benchmark methodology now
    match the code; the historical roadmap proposal is labeled as a snapshot.
  • Configuration docs cover CAIRN_NO_REFRESH and CAIRN_LLM_BACKEND.
  • Benchmark docs carry the current reference-local perf and 1,000-file
    scaling measurements.

Fixed

  • Generated Claude/Cursor hook commands shell-quote the interpreter path
    (pipx's Application Support location no longer exits 127), and
    reinstalling agent hooks replaces stale Cairn commands instead of treating
    any matching entrypoint as current.
  • Dashboard /health no longer returns 500 when the embed backend is a
    server family with no resolvable CAIRN_EMBED_BASE_URL: the failing probe
    degrades to None and the page renders it as unknown.
  • Dashboard history pagination no longer loops on the same page when the
    oldest row of an all-time page has a NULL invoked_at (legacy-shape
    tool_metrics tables): the next cursor is omitted instead of being
    unparseable.
  • cairn doctor markup-escapes the dynamic freshness hint, so a
    workspace-derived repo id containing [ cannot corrupt rich's markup.
  • C4 architecture diagrams now agree with the boot guard everywhere (25 MCP
    tools, groups 12/5/2/6; previously 22/24/9 across labels).
  • Agent-integration package data now ships only template/script file types,
    keeping generated __pycache__ bytecode out of sdists and wheels.
  • The dashboard first-render budget test judges the 200ms SC-1 budget on the
    best of 5 fresh-app trials, so full-suite scheduler noise no longer fails it.
  • Agent-suite benchmark docs report the modal est_tokens median (1,479 /
    99.7%) and scope the determinism claim to tool calls; estimated tokens vary
    by at most about 2% run-to-run.
  • The AGENTS.md template cairn install-agents writes carries the current
    tool-layer names, matching the repository copy (parity test added).
  • The oversized reserved-block pack test pins heuristic token costs, keeping
    it independent of the process-wide exact-tokenizer mode.
  • cairn build --repo no longer crashes with an integrity error on any repo
    embedded with the default multivector pass: _clear_repo deletes the
    repo's embeddings_mv rows before deleting its symbols.
  • cairn doctor no longer spawn-executes command/args/env read
    verbatim from workspace-owned registration config files: only an entry
    exactly in the shape cairn install-agents writes is probed, and any
    other shape degrades to a WARN naming the file.
  • The doctor memory-staleness check degrades to a WARN when its
    memory_refs read fails, restoring the diagnostic's never-raises
    contract.
  • CAIRN_ANN_BACKEND resolution lives in one shared helper, so the ANN
    index, doctor, dashboard, and MCP server agree on the empty-string
    opt-out.
  • C4 containers-level diagram says tree-sitter ×15, matching the parser
    registry and the context level (was ×14).

0.21.1

Choose a tag to compare

@github-actions github-actions released this 21 Sep 08:11

[0.21.1] - 2026-09-21

Added

  • SCIP compiler-index support, redesigned as an opt-in edges-only overlay:
    a configured (or once auto-generated) .scip index contributes exact
    call/reference edges over the unchanged tree-sitter symbol graph —
    per-file authoritative, position-joined, per-document repo attribution,
    with a join-anomaly guard that retains tree-sitter edges observably.
    Seven-language run-once auto-generation registry (swift, java, kotlin via
    scip-java, typescript, python, go, rust) with scip_gen_* degradation
    records; cairn import-scip CLI and the scip config key; [scip]
    extra restoring the vendored protobuf stub; stats gains edge_sources
    and exact_share_by_language, build summary renders scip: n edges (d disagreements); cairn update re-applies the configured overlay after
    reindexing (import-only, never a generation); docs/scip.md toolchain
    guide.

Changed

  • Transitive closure rebuilt as an in-memory level loop with a single write
    pass (byte-identical row sets, ~2× faster on cairn's own repo) and now
    enforced by a CI budget gate — ≤60 s wall / ≤512 MB peak at the 1000-file
    scaling point with 5× structural edges (measured 6.0 s / 228 MB), plus a
    ≤2 s budget for one incremental maintain_transitive_closure call at
    the same point, whose reads are scoped to the affected subgraph.
  • edges table gains an additive source provenance column (NULL reads as
    tree-sitter); local commit gate's staged-files ruff honors
    extend-exclude via --force-exclude.

Fixed

  • Agent hook stdout stays protocol-clean: post_edit and session_end
    emit cairn/prose diagnostics to stderr instead of stdout (the calling
    agent parses Stop/PostToolUse hook stdout as JSON), and session_start
    routes digest subprocess failures to stderr so no error prose reaches
    the agent's context.
  • The SCIP import's write phase is atomic: every fallible read completes
    before the first delete, and the deletes/inserts run inside a savepoint
    that rolls back on failure — a mid-import error can no longer commit
    orphaned per-file deletes that permanently stripped tree-sitter
    calls/references edges from already-processed files.
  • SCIP local symbols resolve only against same-document definition sites
    (they are document-scoped by spec), instead of joining a same-named
    definition from an unrelated file.
  • _apply_scip_overlay logs a failed config read like every other
    degradation instead of returning silently.
  • cairn import-scip exits non-zero when no index document matches the
    graph (the workspace/db mismatch case that printed a normal-looking
    "0 edges" line), and the success line reports matched/skipped document
    counts.
  • scripts/regen_scip_pb2.sh splices the generated stub at the detected
    header end instead of a hardcoded line number that could disagree with
    the accepted header range.

0.21.0

Choose a tag to compare

@github-actions github-actions released this 18 Sep 04:15
1a95264

[0.21.0] - 2026-09-17

Added

  • Bi-temporal memory: every memory carries valid_from/valid_until
    (additive memory_validity projection + concept extensions, one-time
    backfill); recall_memory/cairn memory search accept as-of dates;
    cairn validate-paths --mark expires stale-reference memories at build
    time with unique-successor links instead of deleting; cairn memory timeline <symbol> renders a symbol's memory history.
  • Multi-agent memory coordination: cairn memory share --agent <id> --symbols a,b,c publishes a learning to other agents' recall; cairn memory check warns on other agents' recent symbol activity (7-day
    window); search --agent / recall_memory(agent=...) merge shared
    entries with attribution; sharing unused keeps single-agent behavior
    byte-identical.
  • Security-aware blast radius: configurable taint sources/sinks (generic
    call-name defaults, cairn.json taint overrides), inter-procedural
    propagation over precise call edges (--fuzzy opt-in, depth-capped),
    cairn taint --from --to path tracing, and taint-path warnings in
    explore and cairn blast output.
  • Closed review loop: cairn review --base <ref> emits a structured
    review-context pack (blast radius + memories + compass + wiki);
    --pre-submit [--gate] warns on mistake/pattern memories keyed to the
    diff; --capture-event records resolved review comments as draft-tier
    symbol-keyed memories; advisory .github/workflows/review.yml posts
    findings as PR comments from a committed seed bundle.
  • cairn pack --task <text> --budget <tokens>: one-shot token-budgeted
    context block — semantic+lexical seed union, one-hop precise expansion,
    closure-gated centrality ranking, greedy budget fitting with per-class
    drop reporting, and per-symbol source/blast/compass/memory enrichment;
    deterministic, offline, no LLM. Bench pack-fit-rate arm: fit 1.00 at
    99.7% token reduction vs the grep baseline.
  • Cross-repo federation: federated_search MCP tool (inventory is now 25
    tools) and cairn federated-search merge per-store results with
    per-repo attribution and rank-level RRF fusion (lexical fallback for
    embedding-less stores, named dropped-store states); cairn ask --all-repos composes per-repo answers; opt-in --shared-embed serves
    stamp-compatible stores from one embedding backend.
  • cairn bench --suite swe-bench: deterministic (no-LLM) two-arm
    efficiency measurement over a pinned 50-instance SWE-bench_Lite subset
    (frozen manifest at a recorded HF revision; datasets rides the new
    bench extra); byte-identical reruns, hermetic -m core CI smoke;
    published medians: 84.6% tool-call / 99.0% token reduction vs the
    grep/read control, fresh-clone reproducible (resolve-rate intentionally
    out of scope for the deterministic arm).
  • VS Code extension (extensions/vscode/, vsix package): zero-config
    adopt-or-spawn of the local dashboard server, status item with graceful
    degradation (unindexed/stopped-server states), hover blast radius,
    caller/callee code-lens counts, and a compass/memory panel — over frozen
    editor JSON routes (/editor/symbol|file|status) on the dashboard app;
    tag-triggered extension-release.yml builds the vsix and validates
    install + activation on a headless clean machine.
  • Query-time freshness: every graph MCP tool and CLI query command probes
    (size, mtime) drift and reindexes changed files before answering;
    CAIRN_NO_REFRESH=1 / --no-refresh and read-only stores answer from the
    stored graph with a probe-derived staleness banner (no [watch] extra
    required).
  • cairn blast computes the reverse-edge blast radius of a git diff
    (working tree vs HEAD, or --base <ref> vs merge base) with
    text/markdown/mermaid/json renderers, precise edges by default (--fuzzy
    opt-in), innermost-symbol seeding by stored spans, and id-based traversal.
  • cairn map (CLI + MCP repo_map): deterministic repo orientation —
    per-repo directory clusters with counts, in-degree hubs, global hotspots,
    explicit dropped counts; zero LLM.
  • MCP file_api: signature-only symbol surface per file (kind, qualified
    name, synthesized signature, span; never bodies) with repo disambiguation.
  • cairn grep: regex search over indexed files grouped by innermost
    enclosing symbol, ranked by in-edge coupling, with -i/--fixed/--in
    and explicit truncation counts.
  • Wiki/compass pages preserve human-authored ## Notes sections
    byte-identically across regeneration; the critic does not evaluate Notes
    content.
  • cairn viz --export FILE.html writes a single self-contained HTML graph
    view (inline vis-network, no network assets).
  • cairn build --lsp: opt-in pyright stdio pass upgrades uniquely resolvable
    ambiguous Python edges to exact; missing/failing server is a no-op with a
    notice; existing exact edges are never downgraded.
  • Rust (.rs) indexing via a generic tree-sitter tier (pinned
    tree-sitter-rust); call edges stay unresolved (never exact).
  • discover_repos optionally includes initialized submodules and nested
    repos (include_nested_repos, default off, prefixed repo ids); linked git
    worktrees seed an independent store from the main checkout then refresh
    drift.
  • cairn dataflow build --max-symbols N caps the public symbols indexed per
    run; CAIRN_DATAFLOW_MAX_SYMBOLS sets the cap for every builder entry point
    (cairn build, cairn sync, cairn dataflow build). The partial-index
    warning names the env var and flag.

Changed

  • The [ingest] extra pins onnxruntime<1.24 on Python 3.10 so
    pymupdf-layout resolves to an installable wheel set.
  • Dataflow builds upsert rows in batches and compute the repo-keyed
    cross_repo_deps payload once per repo per run instead of once per symbol.
  • CI test legs run the suite under pytest-xdist (-n auto --durations=25);
    PR legs run the Python 3.14 ceiling only — the full 3.10-3.14 matrix still
    gates every push to main. Eval-path tests pin the dep-free hash embedder,
    keeping the semantic model out of the retrieval loop.
  • CI installs every job from the committed uv.lock via uv sync (the
    lockfile is the tested dependency set, not a fresh pip resolution), runs
    the full 3.10-3.14 matrix on merge-group entries as well as main pushes
    (merge-queue-ready), and sets per-job timeout-minutes.

0.20.2

Choose a tag to compare

@github-actions github-actions released this 13 Sep 16:04

[0.20.2] - 2026-09-13

Added

  • cairn stats reports edge resolution shares (exact / ambiguous /
    unresolved) over the calls/references candidate pool.
  • cairn update embeds changed files' symbols when a semantic backend is
    reachable, and reports deferred embeds when none is available.
  • cairn.json committed at the repo root excludes vendored dashboard static
    chunks and benchmark datasource corpora from indexing.

Changed

  • cairn embed builds the multivector kinds (name, docstring) by
    default; --no-multivector restores single-vector builds.
  • reindex_paths settles embed_symbols' buffered-batch degradation, keeping
    an open transaction from failing subsequent file legs or losing rows.
  • Shared graph helpers (_select_stale_symbols, _purge_embedding_rows,
    _repo_relative_path) replace duplicated logic across the embedding and
    incremental paths.

0.20.1

Choose a tag to compare

@github-actions github-actions released this 11 Sep 09:58

[0.20.1] - 2026-09-11

Removed

  • The SCIP compiler-index ingestion path: cairn import-scip, the
    cairn.json scip key, the [scip] extra (protobuf runtime), the
    vendored protobuf stub with its regeneration script, and the external
    indexer auto-generation orchestrator. Indexing is tree-sitter-only for
    every language; a stale scip key in cairn.json is ignored like any
    other unknown key.

Added

  • Parser-emitted binding signals for all fourteen languages: import
    aliases (imports.local_alias), definition arity (symbols.arity),
    call arity, and receiver types for the nine parsers that previously
    emitted none (python, c/cpp, csharp, dart, js/ts, objc, swift). The
    resolver consumes them: a bare call through a local import alias
    resolves exact, and same-named overloads split by argument count when
    exactly one arity matches. Receiver-typed lookups that collide across
    same-named types now narrow by same-file and fall through the tier walk
    instead of degrading to ambiguous. Intra-workspace exact share rises on
    the measured corpora (self 0.2248 → 0.2429; ds2/attrs 0.6546 → 0.6781)
    with retrieval ground truth unchanged (558/558 + 234/234).

0.20.0

Choose a tag to compare

@github-actions github-actions released this 10 Sep 08:00
dc9882b

[0.20.0] - 2026-09-10

Added

  • The dashboard graph tab draws the whole picture instead of an empty
    canvas whenever a scope's filter is blank:
    • symbol and impact scopes with no focal name render the
      workspace overview — the most-connected symbols on one canvas,
      ranked by degree (fan-in + fan-out), capped at 50 symbols and 100
      edges, tests excluded by default with the Include-tests toggle
      opting back in, vendored/minified assets never candidates, and
      edges deduplicated on (source, target, kind). Metadata reports
      tests_included, truncated, and vendored_excluded so a
      count at the cap is visibly truncated. A focal name still draws
      that symbol's neighborhood; a name that matches nothing still
      renders the empty state.
    • The repo scope with no repo id buckets every repo in the store,
      capped at 30 buckets with an honest truncated flag in metadata.
  • The MCP visualize_graph tool rides the same viz layer: module
    diagrams include their real internal edges, and format="json"
    output for the repo scope carries the truncated field.
  • The dashboard sidebar's Database item has an icon (hard-drive glyph)
    like every other nav view; a source-pinned test fails if a future
    nav view ships without a glyph.

Fixed

  • The dashboard's workspace selector names the launch workspace (e.g.
    polaris (launch)). The selector's no-selection option serves the
    launch store — the dashboard process's own db — so the label shows
    which workspace every view queries by default. The generic
    Launch workspace label applies only to custom --db paths outside
    the store registry.
  • Module- and symbol-scope edge queries apply the kept-node target
    predicate in SQL before the 100-edge cap, so the cap lands on real
    internal edges and the rendered edge set is stable across scans.

0.19.1

Choose a tag to compare

@github-actions github-actions released this 10 Sep 02:01
e7e76bd

[0.19.1] - 2026-09-10

Added

  • Relationship-kind enrichment across extraction and display. The graph's
    canonical edge-kind vocabulary is now calls, extends, implements,
    embeds, with, references, decorates, imports, contains.
    • Python base classes emit extends (was implements); decorators emit
      decorates; signature type annotations emit references. Swift splits
      a class's first inheritance target to extends (the superclass) from
      protocol conformances (implements). Go struct/interface embedding
      emits embeds. Kotlin type annotations emit references.
    • Every build synthesizes one module symbol per file (dotted
      repo-relative qualified name), derives contains edges for nesting
      (module → top-level, parent → nested), gives module-level code an edge
      owner, and materializes imports module-to-module edges from the
      imports table by longest-suffix path matching (ambiguous and external
      imports are skipped). Incremental syncs refresh the affected repo's
      imports edges.
    • The dashboard graph canvas colors and dash-patterns edges by kind from
      new --edge-* theme tokens, renders an edge-kind legend whose chips
      filter whole kinds, and the symbol/neighbors/inspect views pass the
      stored edge kind through verbatim (previously every edge rendered and
      labeled as calls).
    • Resolution semantics preserved: module symbols are excluded from the
      resolver's candidate indexes (a file named after its single class
      would otherwise make same-name references ambiguous), embeds joins
      extends/implements in the receiver-dispatch ancestor index, and
      the new kinds stay outside STRUCTURAL_EDGE_KINDS so impact/trace
      radius is unchanged. Requires a rebuild (cairn build) to take
      effect. The DS-v2 ground-truth seal's recorded per-corpus build
      facts are re-pinned to the new deterministic counts (558/558
      expectations and tree_hash pins unchanged).

Fixed

  • The doc-link completion gate now confines proposed edges to the
    completing task's island members: a result naming an existing doc
    outside facts.members is rejected with no writes (the task stays
    in-progress and re-completable), instead of writing kind: inferred
    edges between arbitrary knowledge docs.

0.19.0

Choose a tag to compare

@github-actions github-actions released this 09 Sep 14:53

[0.19.0] - 2026-09-09

Added

  • The dashboard gained a /knowledge catalog over the ingested
    knowledge docs: every stored doc lists exactly once with its family
    (decision / spec / workflow / business-rule), status, related-doc
    count (from the derived knowledge_edges index), tags, and last
    update. Family/status/tag filters morph-swap the results region as
    htmx fragments (no page reload), rows link wholesale to
    /knowledge/{family}/{slug} — a detail page rendering the doc's
    title, badges, and markdown body (relationship panel follows in the
    next knowledge view) — an empty workspace renders an explicit
    empty state naming cairn knowledge ingest, and a store predating
    the relationship index still catalogs with zero link counts. The
    sidebar's Knowledge section leads with the catalog entry, the landing
    grid carries a Knowledge card, and the command palette offers both
    the catalog and a palette-only Knowledge Graph destination.
  • The /knowledge/{family}/{slug} detail page gained the relationship
    surfaces: a supersede chain widget (ordered oldest -> newest, each
    member linking its detail page, the hop labeled with its relation and
    a direction arrow, the viewed doc highlighted), a relationship panel
    grouping every stored neighbor row under its relation with a kind
    badge (extracted / inferred / derived — the same tuples
    cairn knowledge related prints; inferred wears a dashed badge), an
    explicit empty state for docs with no relationships, linked code refs
    with their kind and per-ref resolution status (symbols deep-link into
    the graph), and ingest provenance — source repo/path and the doc's row
    in the workspace's staged .cairn/ingest-outbox/manifest.json, or an
    explicit note when a doc was added directly to the store. A store
    predating the relationship index renders empty panels, never an error.
  • The dashboard gained the /knowledge/graph relationship canvas (the
    palette's Knowledge Graph destination, linked from the catalog):
    every stored doc is a node and every indexed relationship a directed
    edge drawn exactly as stored — a supersede pair reads as the two-way
    link ("supersedes" on the newer doc, "superseded-by" on the older)
    the related CLI and the detail panels report, with edges carrying
    their relation + kind so inferred links render dashed and
    extracted/derived links solid. The legend doubles as the filter:
    kind/relation chips toggle whole edge groups client-side (no reload,
    no refetch), the counts line tracks the visible share, and a node
    click fetches the doc's inspect fragment (/knowledge/graph/inspect)
    into the side panel — identity, relationships with kind badges, and
    the full-detail link. The canvas re-themes live via the shell's
    cairn:theme-changed broadcast and drops physics under
    prefers-reduced-motion: reduce (the /graph machinery's conventions).
  • Vendored Mermaid 11.17.2 (mermaid.min.js, MIT) as the dashboard's last
    external asset: the wiki detail view now loads it from /static/ via a
    lazy dynamic import() that ships only on pages holding a mermaid fence
    (replacing the jsDelivr CDN import), so fence-free wiki pages make no
    mermaid request and the dashboard is fully offline at runtime. Fences
    render explicitly via mermaid.run() after the late import (startOnLoad
    off), with the code block kept as the no-JS/unavailable fallback.
  • The dashboard serves its own icon: the shell head links the vendored
    favicon.svg, and the conventional /favicon.ico path serves the same
    file, so the browser's automatic icon probe is a 200 instead of a 404
    on every page load.
  • The /graph symbol inspect panel loads as an htmx fragment: the
    node-click fetch rides htmx.ajax (the HX-Request header keys the
    route's fragment branch) and swaps the server-rendered panel —
    identity, callers, callees, impact with affected tests, neighbor rows
    deep-linking into the symbol-focused view — into #graph-panel with
    no page navigation (sidebar/topbar persist by node identity). A stale
    response from an earlier selection is cancelled at htmx:beforeSwap;
    requests without the header keep the JSON payload. The
    /knowledge/graph inspect fetch rides the same htmx.ajax seam.

Changed

  • The graph and database canvases re-theme live through CSS variables.
    The per-kind node palette moved from hardcoded JS color tables into the
    theme blocks as --kind-* tokens, and the shell broadcasts a single
    cairn:theme-changed event on a theme flip (one data-theme observer
    app-wide, in shell.js); both canvas scripts re-read every color through
    the getComputedStyle token proxy on that event, so toggling the theme
    re-colors the live canvas in place — no reload, no new graph requests.
  • The /graph physics simulation is disabled under
    prefers-reduced-motion: reduce — JS-driven motion the CSS media
    query cannot reach. The graph then lays out on the deterministic
    spiral (a static constellation, no stabilization animation), and the
    canvas zoom/fit controls skip their eased animation.
  • The dashboard's list views filter and live-refresh through htmx
    fragments. Filter forms on /history, /tasks, and /wiki are htmx
    triggers (input changed delay:300ms; the tasks select on change)
    that morph-swap only the results region — no page navigation, the URL
    and in-progress filter input are untouched, and the form lives outside
    the swapped region so a swap can never destroy a field. The
    #refresh-region live refresh on /history, /tokens, and /chains
    is now an htmx poll (hx-trigger="every 5s"): each cycle re-fetches
    the view's HX-Request branch as a cheap region fragment and
    alpine-morphs it over the region in place, replacing the old
    full-page re-fetch/DOMParse swap; the live chrome (state word, pause
    toggle, disconnect banner) is driven from the htmx event lifecycle —
    pause refuses the poll's request via htmx:beforeRequest while the
    timer keeps its schedule, and window scroll is re-anchored around each
    swap. The same routes serve full page or fragment from one handler
    via the HX-Request header. The command palette is a native
    <dialog> element driven by an Alpine
    component: showModal() provides the focus trap and Esc-to-close, and
    focus returns to the launching element on every close path. Rows come
    from the same two sources as before — the server-rendered seed JSON
    draws the initial list, and typing fetches filtered rows as an htmx
    fragment from the new /palette/results route (the same view/workspace
    seed composition plus the /graph/suggest symbol data function, with
    the selected store riding the request). Keyboard behavior is
    unchanged: Ctrl/Cmd+K toggles, arrows move the active row, Enter
    navigates.
  • Accessibility pass over the dashboard shell and views. Keyboard focus
    is always visible: the global :focus-visible ring (2px accent
    outline) stands everywhere, the shared filter-bar inputs keep the ring
    alongside their focus tint, the palette search input carries an inset
    ring (the card clips an outward one) plus an aria-label, and no
    stylesheet rule removes the focus outline. Every icon-only button
    exposes a non-empty accessible name (theme toggle and sidebar collapse
    already flip their labels with state), pinned by a hermetic sweep over
    all fourteen main views. prefers-reduced-motion: reduce collapses
    motion to ~zero — transitions/animations run at 0s, smooth scrolling
    stops, the live-refresh pulse stops outright — while toggles, palette,
    and htmx swaps behave as before. The shared table macro's real table
    semantics (thead/tbody, <th scope="col">) are pinned by test.

Added

  • Vendored the dashboard's interaction stack as static assets (zero CDN,
    zero build step): htmx 2.0.10 (htmx.min.js, 0BSD), Alpine.js 3.17.1
    (alpine.min.js, deferred, MIT), its morph plugin (alpinejs-morph.min.js,
    MIT), and the alpine-morph htmx extension (alpine-morph.js). The shell
    loads all four from /static/ with the ?v= cache-buster, runs htmx with
    allowEval disabled via the htmx-config meta, and ships the
    [x-cloak] { display: none } rule so Alpine-managed DOM never flashes
    pre-init. Route handlers gain the is_hx_request seam (the HX-Request
    header) for serving full pages vs fragments from one route.

Added

  • cairn knowledge list --json emits one machine-readable row per
    document — concept_id (bare bundle-relative id), title, doc_type,
    doc_status — so callers and validators can pin document ids without
    search --json or sqlite. Human output and the --type/--status/
    --tag filters are unchanged.
  • Dangling relationship pointers are surfaced instead of silently
    skipped: a declared relates_to pointer matching neither a knowledge
    concept id nor a recorded resource path warns by name — in the ingest
    dry-run output (before any write, checked against the store plus the
    staged run), in knowledge ingest --ingest output (from its post-write
    index rebuild), and in cairn knowledge rebuild output. The pointer
    stays in the frontmatter (the durable record) and still never reaches
    knowledge_edges; relationship-free documents ingest and embed exactly
    as before, and the knowledge ingest flag set and the 22-tool MCP
    surface are unchanged.
  • Island detection behind the LLM task queue: connected components over the
    knowledge_edges doc graph surface pair-units detached from the corpus —
    two-doc components and id-ordered singleton pairs — and queue one
    doc-link task per pair via knowledge ingest --ingest and cairn knowledge rebuild; task facts carry the member concept_ids and titles,
    and queueing is deduped per member set so re-runs never duplicate tasks.
    Completing a doc-link task through cairn task claim/task complete --result-file is gated by a deterministic critic that verifies every
    pro...
Read more

0.18.0

Choose a tag to compare

@github-actions github-actions released this 02 Sep 16:16
b7585d9

[0.18.0] - 2026-09-02

Added

  • Dashboard database view (/database, System section): the store's
    schema rendered as an interactive relationship graph on the same
    vis-network canvas as the Graph view — tables are nodes sized by row
    count, solid edges are declared foreign keys, dashed edges are
    *_id references implied by column naming (a column already covered
    by a declared FK is never re-inferred), internal sqlite_%/FTS shadow
    tables are excluded, and selecting a node opens a side panel with the
    table's columns, types, and incoming/outgoing references. Theme flips
    re-color the live network.
  • Dashboard Memory view categorization: a Type filter pill row
    (all · decision · pattern · mistake · workaround) above the table,
    mirroring the Wiki catalog's state filter — ?type= narrows the list
    server-side before the newest-first limit applies, an
    out-of-vocabulary value silently falls back to the unfiltered page,
    the active pill renders highlighted, and the empty state names the
    category when a filtered type has no records.

Fixed

  • Dashboard alignment: every .graph-controls row (graph filter bar,
    settings embedding config, history/tasks/wiki filters) now renders on
    one baseline — selects, text/password/number inputs, and submit buttons
    share a fixed control height (their differing intrinsic widget heights
    previously sat raggedly under the rows' bottom alignment), checkbox
    toggles render as one centered line instead of stacking the checkbox
    above its caption, and inline status chips (env-pin markers, the API-key
    state) meet the same bottom line as the controls they annotate. Data
    tables no longer collapse under width pressure: timestamp cells hold
    one line instead of wrapping mid-string at their hyphens, and long-ID
    code chips (memory IDs, history sessions, task IDs/resources) cap to
    one ellipsized line with the full value on the title tooltip instead
    of being squeezed to a one-glyph sliver by the auto table layout.

Changed

  • Dashboard sidebar: the collapse control and theme toggle are icon-only
    square buttons — a chevron that flips with the collapse state, and a
    sun/moon glyph showing the theme the button switches to (sun while
    dark, moon while light). The visible text is gone; the accessible
    name and tooltip state the action ("Switch to light theme" /
    "Collapse sidebar") and stay in sync in both states.