./devel/sem, Semantic version control

[ Image CVSweb ] [ Image Homepage ] [ Image RSS ] [ Image Required by ]


Branch: CURRENT, Version: 0.22.1, Package name: sem-0.22.1, Maintainer: pkgsrc-users

sem is a semantic version control tool that works on top of Git.
It parses your code with tree-sitter, extracts every function,
class, and method as an entity, and diffs at the entity level
instead of lines. This means you see "function blahh was modified"
instead of "lines x-y changed."

It works in any Git repo with no setup.


Master sites:

Filesize: 1792.801 KB

Version history: (Expand)


CVS history: (Expand)


   2026-08-17 09:14:26 by pin | Files touched by this commit (3) | Package updated
Log message:
devel/sem: update to 0.22.1

[0.22.1] - 2026-08-16
Added

    sem find / sem callers / sem refs: new query verbs that answer directly from \ 
the mmap index.sem — entity definitions, direct callers (reverse edges), and \ 
direct refs (forward edges) — without touching cache.db.
    sem grep <pattern>: trigram-accelerated text search over the mmap \ 
index. A required-trigram query against the index's TRIGRAM section narrows the \ 
candidate file set, each candidate is then verified with the real regex matcher \ 
against its current bytes (never stale stored content), and output is \ 
rg-compatible file:line:text. Beats rg 11-26x on giant repos (measured on the \ 
TypeScript monster and home-assistant-core corpora: 25-53ms vs. rg's 283-980ms \ 
for the same pattern). Falls back to a full scan for patterns no trigram query \ 
can be derived from.
    sem review listen <diff-id-or-url> [--dry-run]: one-command agent \ 
attach to a hosted sem-cloud review. Resolves credentials, validates the diff \ 
exists, locates the review-listener plugin, and execs claude with the documented \ 
flags/env. --dry-run prints the assembled command with secrets masked, without \ 
launching or requiring claude to be installed.
    Three new sem-cloud MCP tools (join_review, wait_for_branch, \ 
reply_to_branch) let an agent join a hosted code review as a live listener: \ 
long-poll for reviewer questions anchored to lines of a diff, investigate them \ 
in the repo, and stream answers back. Ships with a Claude Code plugin \ 
(integrations/claude-review-listener/) that wires the tools up and adds a \ 
read-only Stop-hook backstop for headless sessions.
    sem diff's hosted upload no longer blocks on the local caller/callee \ 
relations pass. With cloud consent on, the diff snapshot uploads immediately \ 
with empty relations; the server queues enrichment and replies \ 
"enrichmentQueued" (or, against an older server, the CLI runs the \ 
existing local pass and PUTs the result afterward). SEM_RELATIONS_LOCAL=1 \ 
restores the old blocking single-upload behavior; the local relations pass's own \ 
budget is now adaptive to repo size.

Performance

    Cold graph builds are 11-30% faster and peak RSS is down 17-40% on giant \ 
corpora, versus 0.21. Measured end-to-end on the shipped release binary: \ 
home-assistant-core 5.9s, TypeScript monster 11.2s, dotnet-runtime 46.7s, \ 
llvm-project 34.7s, linux 35.2s cold full-CLI (warm rebuilds: 0.2-1.3s). Every \ 
corpus improved on both the engine-only and full-CLI metrics; full methodology \ 
and per-corpus numbers are in RESOLUTION-PROFILE.md's FINALE section.
    C#/C++ builds now skip re-parsing files whose facts are already known, \ 
closing the last gap in precomputed-facts reuse (JS/TS/Python/Go/Java/Rust \ 
already had it). A per-file gate proves a corpus-wide invariant — no entity's \ 
parent lives in a different file — before trusting precomputed facts \ 
wholesale, so this needed no facts-schema change. Measured on dotnet-runtime: \ 
reparse time drops from 10.6s to 65ms.
    Parsed file facts now persist to disk as a content-addressed corpus, so a \ 
build that has seen a file's exact content before warm-starts it instead of \ 
re-parsing from scratch, even in a fresh process. Fixed a regression where \ 
checking a shared corpus against a large number of prior contributors got slower \ 
as the corpus grew (one repo's known-content rebuild was measured 332% slower \ 
against a 7.9GB shared corpus than a 556MB one); it now costs the same \ 
regardless of corpus size.
    sem context regained a fast tier it had lost, by reading each entity's body \ 
from its own file at an indexed byte span instead of walking and hydrating the \ 
whole corpus. A prior cascade of cache removals deleted the old fast path along \ 
with a correctness bug it had, but left sem context always doing a full corpus \ 
load — measured on the TypeScript monster 1.11s down to 48ms, on a mid-size \ 
repo 0.16-0.28s down to 4.6ms. Verified byte-identical against the \ 
always-correct full-load path across both entity- and file-scoped lookups; still \ 
declines (never approximates) on a stale cache, an ambiguous name, or any entity \ 
missing a span.

Changed

    sem mcp --resident's standing sidecar process is gone. With index-backed \ 
queries answering in single-digit milliseconds from a cold process, the \ 
resident's whole reason for existing (avoiding a ~800ms SQLite hydrate) no \ 
longer applies — it measured 0% availability at scale, a 300ms tax, and 2.6GB \ 
of idle RSS. SEM_NO_SIDECAR and SEM_NO_AUTOWARM are gone with it; the --resident \ 
flag itself stays as a no-op for compatibility.

Fixed

    sem --version now reports the correct version. The v0.21.1 tag only bumped \ 
sem-core, leaving sem-cli, sem-mcp, sem-plugin, and sem-cloud-client at 0.21.0, \ 
so the binary still reported 0.21.0. Bumped those crates (and their internal \ 
path dependencies) to 0.21.1 to match the tag. Thanks @chenrui333 (#480).
    Building a graph over Svelte components no longer crashes (SIGSEGV) on \ 
Linux/glibc. sem graph/context/orient over .svelte files deterministically \ 
exited 139 from an invalid free in the tree-sitter-htmlx-svelte 0.1.8 grammar's \ 
scanner, hit during parallel graph construction (macOS's allocator tolerated the \ 
bad free, so it only showed on Linux). Bumped the grammar to 0.1.16, which \ 
carries the scanner fixes; the existing version constraint already permitted it, \ 
so this is a lock-only dependency update. Added a parallel-Svelte-graph \ 
regression test. Thanks @XF-FW for the exhaustive isolation and the verified fix \ 
(#471).
   2026-08-16 15:22:18 by Thomas Klausner | Files touched by this commit (3) | Package updated
Log message:
sem: update to 0.21.1.

### Fixed

- **Building a graph over Svelte components no longer crashes
(SIGSEGV) on Linux/glibc.** `sem graph`/`context`/`orient` over
`.svelte` files deterministically exited 139 from an invalid free
in the `tree-sitter-htmlx-svelte` 0.1.8 grammar's scanner, hit
during parallel graph construction (macOS's allocator tolerated
the bad free, so it only showed on Linux). Bumped the grammar to
0.1.16, which carries the scanner fixes; the existing version
constraint already permitted it, so this is a lock-only dependency
update. Added a parallel-Svelte-graph regression test. Thanks @XF-FW
for the exhaustive isolation and the verified fix (#471).
   2026-07-13 12:12:06 by Thomas Klausner | Files touched by this commit (6) | Package updated
Log message:
sem: update to 0.21.0.

## [0.21.0] - 2026-07-10

### Added

- **Cloud-enabled `sem diff` now creates an immutable, owner-private hosted \ 
review URL.** Snapshot uploads include changed-entity caller/callee relations \ 
and truthful Git provenance: branch, scope, base/head refs, and available SHAs. \ 
Working-tree reviews explicitly report `HEAD → WORKTREE` rather than implying \ 
that uncommitted changes exist on GitHub.
- **GitHub login can now be exchanged for a revocable CLI session.** Raw GitHub \ 
credentials are not persisted as sem credentials, and the CLI session resolves \ 
to the same stable principal used by web reviews.

### Fixed

- **Hosted-review upload failures are visible without breaking the local diff.** \ 
`sem diff` still exits successfully with its complete local result, while stderr \ 
explains that the private review could not be uploaded.
- **Transitional cloud repository states refresh immediately.** `sem whoami` no \ 
longer leaves a repository stuck at a cached `pending` state after cloud \ 
indexing has completed.
- **`sem diff` now collapses contiguous line chunks on unsupported files into \ 
one summary line.** When a file has no grammar, sem falls back to fixed 20-line \ 
chunks, so deleting or adding one previously printed a wall of `⊖ chunk lines \ 
1-20 [deleted]` / `21-40` / `41-60` … lines that ate context for no \ 
information. Contiguous chunks of the same change type now consolidate to a \ 
single line, e.g. `⊖ 13 chunks  lines 1-246  [deleted]`. Verbose mode (`-v`) \ 
is unchanged, since it still prints per-chunk content. Thanks @graipher for the \ 
report (#466).

### Performance

- **`sem context` now answers from an indexed point query instead of loading the \ 
whole graph, so it scales to millions of entities.** It previously hydrated \ 
every entity (plus decompressed bodies) just to answer about one, so on a \ 
2.3M-entity repo each call took ~15s. The SQLite cache is already normalized and \ 
indexed, so when the git oracle proves the cache fresh (no filesystem walk) `sem \ 
context` now builds only the k-hop neighbourhood around the target straight from \ 
the store: batched `IN (...)` edge queries, bodies fetched per hop, stopping \ 
once there is enough content to cover the token budget so a hub entity's fan-out \ 
does not explode the fetch. It reuses the existing packer on that subgraph, so \ 
output is byte-for-byte identical to the full-graph path, and falls back to the \ 
full load whenever the oracle declines. On the Linux kernel (2.31M entities) \ 
`sem context` drops from ~15s to 0.44s per call; on Kubernetes (520k) from ~5s \ 
to ~1.2s.
- **Default (`All`-mode) `sem impact` now answers from the indexed cache too, \ 
instead of hydrating the whole graph.** A full cache stored entities and edges \ 
but not test flags, so All/Tests-mode impact (which includes the "covered \ 
by N tests" answer) fell through to a full-graph load — ~3.5s on \ 
Kubernetes, ~10.7s for an unbounded `--depth 0`, even for a tiny blast radius. \ 
The full save now records test flags (shared with the topology save) behind a \ 
metadata marker, so the existing point-query path can serve All-mode impact \ 
straight from indexed edge queries. Output is identical to the full-load path \ 
— verified byte-for-byte against it, including the tests field. On Kubernetes \ 
(520k entities) default `sem impact` drops from **~3.5s to 0.04s**, and `--depth \ 
0` from **~10.7s to 0.04s**. Caches built before the marker still take the full \ 
path, so nothing regresses.
- **The resident MCP server no longer holds the whole graph in RAM by default, \ 
cutting idle memory dramatically.** It used to proactively build and keep the \ 
entire deserialized graph in memory on startup so the first query would be warm \ 
— ~671MB on Kubernetes, ~5GB on the Linux kernel. But `context` and `impact` \ 
now answer from the indexed cache directly, and the CLI's fast paths bypass the \ 
resident entirely, so that proactive hold is mostly wasted memory. Prewarm is \ 
now opt-in (`SEM_PREWARM`); by default the resident stays light and builds the \ 
full graph lazily, only when a query that genuinely needs it (graph/diff/text) \ 
runs. On Kubernetes an idle resident drops from **671MB to 10MB**.

## [0.20.0] - 2026-07-05

### Changed

- **Indexing now shows a staged loader with a real, whole-build progress bar, \ 
not a single "Building entity graph" spinner.** A cold graph build \ 
renders each phase sem-core reports as a persistent `◆` line — `Scanning \ 
files — N found`, `Parsing code — done` — and a **single filling bar with \ 
a live percentage spans the entire build**: the build is two passes over the \ 
file set (parse, then resolve), so the bar's length is 2×files and its position \ 
is (files parsed + files resolved). It tops out at ~50% when parsing finishes \ 
and only reaches 100% when resolution actually completes — so 100% means \ 
genuinely done, not "parsing done." Fed by two lock-free per-file \ 
counters (`graph_parse_done`, `graph_resolve_done`) via phase hooks. Ends with \ 
the existing `✓ N entities · M files in …ms` summary. Warm cache fires \ 
nothing and stays instant; TTY-only, so agents, pipes, the MCP server, and CI \ 
see nothing (the bar's poll thread never even spawns off a terminal).
- **`sem setup` now shows a staged progress loader instead of a flat list of \ 
check lines.** Setup runs as a small tree of steps — `git diff → sem diff`, \ 
`Claude Code hooks`, `pre-commit hook` — each with a live braille spinner that \ 
resolves to a green `◆` (did something), a dim `·` (nothing to do / not \ 
applicable, e.g. not in a git repo), or a yellow `⚠` (left a file untouched on \ 
purpose, e.g. an unparseable `settings.json`). It ends with a one-line summary \ 
and the `sem unsetup` revert hint. Same idempotent behaviour, just legible at a \ 
glance.

### Added

- **sem-core: `set_build_phase_hook` / `clear_build_phase_hook` / `BuildPhase` + \ 
`graph_parse_done` + `graph_resolve_done`** — an optional per-thread callback \ 
at graph-build phase boundaries (parsing, resolving) plus a lock-free counter of \ 
files parsed, so a front-end can render staged progress and a live parse bar. \ 
No-op for every caller that doesn't read them.

## [0.19.0] - 2026-07-05

### Removed

- **Removed `sem orient` and all fuzzy/ranked retrieval.** The `orient` command \ 
and its `--pack` briefing, the sem-core ranking (lexical scoring, IDF, recall \ 
net, structural priming), the `sem_entities query=` intent-search mode, and the \ 
resident server's `orient` socket op are all gone. Ranking a natural-language \ 
task to the right entity proved unreliable — a 45-task validation showed the \ 
ranker's hit-rate (~47%) could not be lifted by heuristics without causing \ 
regressions — and it was the only non-deterministic thing in sem. sem is now \ 
purely deterministic: `context` (read an entity plus its callers/callees), \ 
`impact` (blast radius), `diff`, `entities` (list by path, or `text=` for \ 
exact-substring search), `blame`, `log`. To find code whose name you don't know, \ 
use a plain text search to get a candidate name, then hand it to `sem context` \ 
for the structure grep can't give. The prompt-submit hook keeps its \ 
deterministic exact-name prefetch and no longer shells out to th
e ranker.

### Fixed

- **Dot-chain extraction is now linear, not quadratic, in file size.** \ 
`extract_dot_chains_with_positions` computed each match's line number by \ 
counting newlines from the start of the file every time, so on a large file \ 
dense with `a.b` chains the cost was O(matches times filelen). Since the regex \ 
yields matches in increasing byte order, it now tracks the line number \ 
incrementally and counts only the newlines since the previous match, which is \ 
linear overall and produces identical one-based line numbers. Verified \ 
byte-for-byte identical graph output on React (34,251 entities, 73,702 edges). \ 
No change for typical files; it removes a cliff on very large generated or \ 
minified sources.

- **Structural hashing no longer allocates a Vec per AST node.** The two \ 
structural-hash walkers (`hash_structural_tokens` and its name-excluding \ 
variant) collected every internal node's children into a fresh heap `Vec` (plus \ 
a fresh tree-sitter cursor) just to push them in reverse, despite a comment \ 
claiming zero allocations. They now reuse a single cursor and push children in \ 
place, reversing the appended slice, which is byte-for-byte identical output. On \ 
a cold graph build this removes roughly 300k allocations (structural hashing \ 
alone dropped from about 319k allocations to 13.5k, measured with dhat on deno). \ 
Peak RSS is unchanged and wall time is within noise under mimalloc, but the \ 
churn reduction helps memory-constrained and non-mimalloc builds. Hashes are \ 
verified identical across 3,337 entities, so rename detection and existing \ 
caches are unaffected.

### Added

- **`sem setup` now makes sem a Claude Code session default (macOS/Linux).** \ 
Beyond the `git diff` alias, it installs two session hooks into \ 
`~/.claude/settings.json`: a warm resident graph (SessionStart runs `sem mcp \ 
--resident` detached, so structural queries answer in single-digit ms instead of \ 
rebuilding) and prompt-time context injection (`sem hook prompt-submit`). The \ 
JSON edit is idempotent, backs up `settings.json` first, refuses to touch a file \ 
it can't parse, and preserves every existing user hook and key; `sem unsetup` \ 
removes exactly the sem hooks and cleans up empty arrays. Local warmth is free \ 
and login-free — cloud (`sem login`) is repositioned in the README as the \ 
scale/team/CI upgrade, not the way to get warmth.

### Documentation

- **Benchmarks page rebuilt on the July 2026 paired-run data.** The docs site's \ 
benchmarks page now reports the real agent A/B numbers (grep+read agent vs sem \ 
agent on SWE-bench Verified bugs, hidden-test graded): 50-65% faster code \ 
understanding, verify loop 2.90s to 0.59s per iteration when call-graph edges \ 
resolve (bimodal, 1.2x floor disclosed), token parity stated plainly, and an \ 
explicit "what sem does not do" section including the unchanged solve \ 
rate. Retired the stale "75% fewer tokens" and "2.3x agent \ 
accuracy" hero claims. Changelog page gains entries for v0.17-v0.18 work \ 
with the lessons that produced them.

## [0.18.0] - 2026-07-03

### Fixed

- **sem now works on repos using git's reftable ref storage** (`git init \ 
--ref-format=reftable`, git 2.45+). Previously every command died with libgit2's \ 
cryptic `unsupported extension name extensions.refstorage`. libgit2 can't read \ 
reftable refs, but the object database and index are unchanged, so GitBridge now \ 
tolerates the extension and routes just the ref resolutions (`HEAD`, refspecs, \ 
revwalk starts) through the git CLI while libgit2 keeps doing everything else by \ 
OID. Verified end to end on a real reftable repo: working/staged/commit/range \ 
diffs, blame, and per-file history all produce identical results to a \ 
files-backend repo. One residual gap: the cache freshness oracle's direct \ 
`git2::Repository::open` is `.ok()`-guarded, so on reftable repos it just skips \ 
the acceleration (correctness unaffected). Requires `git` on PATH for the ref \ 
lookups. Thanks @bengry for the report and clean repro (#451).

### Added

- **Unique-method-name call edges (dynamic languages).** Attribute calls on \ 
receivers of unknown type (`index.keep_levels(...)`) previously produced no \ 
graph edge, hiding real dependents and blinding `--tests`. In Python/Ruby — \ 
where receiver types are statically unknowable — a method name with exactly \ 
one definition repo-wide now resolves to it: one candidate, one edge; any \ 
ambiguity, no edge. Static languages keep precision-first resolution (an \ 
unresolved receiver there is deliberate: shadowed import, instance property).
- **`Parent::child` entity qualifiers.** `sem impact \ 
"Dataset::set_index"` and friends now work everywhere `Parent.child` \ 
does (graph and cached lookups).

- **`sem impact --tests` lexical fallback + fast-path fallthrough.** Graph edges \ 
miss tests that call a target through a module namespace (`xr.where(...)` \ 
resolves to no entity), so `--tests` could answer "No tests found" for \ 
a function with dozens of tests. Now: an empty tests answer from the sidecar or \ 
disk cache is treated as non-authoritative and falls through to the full path, \ 
which backstops zero graph edges with lexical reachability — test entities \ 
naming the target as a whole word — clearly labeled as weaker evidence. Found \ 
live: an agent's graph-selected verify loop (run only the tests that reach your \ 
change) went from 0 selected tests to a 56-test net on `xr.where`, versus the \ 
1,900+ tests of whole-file runs.
- **Sharper `--pack` briefings.** Term ranking is now IDF-weighted (a term \ 
appearing in half the repo is worth almost nothing), `<details>` \ 
environment dumps in issue text are stripped before extraction, attribute \ 
accesses glued to receivers ("d2.loc") also emit their `.attr` \ 
suffixes as terms, and one of the three briefing slots goes to the top name-echo \ 
orient hit — for bugs where the issue names a surface API the culprit's body \ 
never mentions.

- **`sem orient --pack <tokens>`: turn-zero briefings from task text.** \ 
Feed orient a whole issue or task description and it returns a packed briefing \ 
— the top matching functions' bodies plus their immediate callers/callees — \ 
sized to the token budget. Ranking is body-term convergence: code-ish terms are \ 
extracted from the task text (flags, dotted names, identifiers) and entities are \ 
ranked by how many distinct terms their bodies contain, since issue vocabulary \ 
lives in bodies, not names. Built for prompt-time injection (the agent-side \ 
analog of the prompt-submit prefetch hook): the code an agent would spend its \ 
first turns foraging for arrives at turn zero. Honest calibration: on three \ 
ground-truth issues it put the exact target function first on two; issues that \ 
quote the tool's own output can still poison term extraction.

- **sem is published to the official MCP registry** as \ 
`io.github.Ataraxy-Labs/sem`, so MCP clients that browse the registry (VS Code, \ 
Cursor, Claude Code, and others) can discover and install the server directly. \ 
The release workflow now publishes each release to the registry via \ 
`mcp-publisher` (authenticated with GitHub OIDC, no extra secrets), backed by a \ 
`server.json` manifest and an `mcpName` field in the npm wrapper.

### Performance

- **Delta-fills: changed entities answer with a diff against the version your \ 
session saw.** The attention ledger now stores fill contents, so when a session \ 
re-asks about an entity that changed since its last look, the answer is an \ 
entity-level delta (`∆ alpha · changed since you read it … - x = 1 / + x = \ 
42`) instead of the whole packed body. Measured end to end: a post-edit re-ask \ 
that previously re-sent the body now costs 2 diff lines. Completes the ledger's \ 
answer set — new entity: full fill; unchanged: one line; changed: delta; \ 
`SEM_FRESH=1` / `fresh: true` always forces the full re-pack. Deltas larger than \ 
120 lines fall back to a full fill.

- **Attention ledger covers the MCP path.** `sem_context` (the tool agent \ 
sessions actually call) now runs through the same per-session fill ledger: an \ 
MCP server process serves exactly one session, so re-asks for unchanged entities \ 
collapse to one `≡ unchanged since you read it` line automatically — no \ 
environment variable needed. New optional `fresh: true` param forces a full \ 
re-send (for when context compaction dropped the earlier fill).

- **Attention ledger v1: repeated context fills collapse to one line.** The \ 
resident server now keeps a per-session ledger of every `context` fill it has \ 
emitted (entity id + content fingerprint). When the same session re-asks for an \ 
unchanged entity, the answer is a single `≡ unchanged since you read it` line \ 
instead of the full packed body — the body is already sitting in the asking \ 
model's context window, so re-sending it is pure token waste. Measured through \ 
the CLI socket path: 8,586 bytes first fill, 139 bytes on repeat (98.4% \ 
suppressed). Opt-in via `SEM_SESSION=<id>` in the environment; \ 
`SEM_FRESH=1` bypasses; anonymous calls are never suppressed. Any change to the \ 
target entity misses the fingerprint and re-sends in full. This is the first \ 
piece of the attention architecture (docs/attention-architecture.md): space \ 
(graph), time (commit index), attention (ledger).

- **`sem entities --text`**: entity-addressed text search from the CLI (the MCP \ 
tool already had it) — one line per hit (file, innermost entity, line, matched \ 
text) instead of whole bodies, served from the resident server's warm graph in \ 
milliseconds with a local-graph fallback. This is the token-cheap way for an \ 
agent to verify a call site or find a string: a body-level `sem context` costs \ 
hundreds of tokens where a text hit costs ~15.

- **Auto-resident server: every sem CLI query after the first answers in \ 
milliseconds, on any repo.** A socket miss now spawns `sem mcp --resident` \ 
(hidden plumbing) detached in the background: a server that holds the repo's \ 
graph warm and serves ONLY the per-repo unix socket, exiting on its own when \ 
idle for 30 minutes or when it loses the bind race to a live session. `sem \ 
context` and `sem orient` gain sidecar fast paths (impact already had one), so \ 
the full structural read loop runs against the warm graph: measured on a 30K-LOC \ 
repo, first `sem context` 0.68s cold (spawning the resident), then \ 
context/orient/impact all under 10ms. In a controlled agent benchmark (6 \ 
verified code-understanding questions, classic grep/read agent vs sem agent, \ 
identical prompts and batching guidance), the sem agent answered in 13s vs 37s \ 
with equal 6/6 correctness — 65% faster. `SEM_NO_AUTOWARM=1` disables the \ 
auto-spawn, `SEM_NO_SIDECAR=1` the fast path.

- **Token-efficient tool output**: the same answers at a fraction of the tokens \ 
the consuming model has to read (and pay for). (1) The context packer stops \ 
enumerating noise: related test entities are folded into per-role counts instead \ 
of packed as one-line "#[test]" stubs (unless the target itself is a \ 
test, when its test neighborhood is the question), bare attribute/comment \ 
signatures are skipped, and transitive tiers are capped at 25 entries per role \ 
with the remainder counted. What was dropped is stated explicitly in one line \ 
("not packed: +64 direct dependents (64 tests) · sem_impact lists \ 
them"), so the signal survives at a fraction of the cost. Measured: `sem \ 
context` on a hot sem-core entity 7,272 to 4,113 tokens (-43%, 119 to 48 \ 
entries); on a hot weave entity 5,216 to 3,498 (-33%, 146 to 27 entries, the 119 \ 
test stubs now one line). (2) The `sem_entities` MCP tool renders compact \ 
per-line trees (name · type · lines, children indented, files as group \ 
headers) ins
tead of pretty-printed JSON: measured 3.7x fewer tokens on a 115-entity file \ 
(5,028 to 1,361). Applies to the MCP path and query modes; CLI `--json` output \ 
is unchanged for scripts.

- **Semantic commit index (storage engine layer 2)**: history is now stored as \ 
entity deltas. Each commit is semantic-diffed against its first parent exactly \ 
once and persisted as entity-change rows in the cache (`commits` + \ 
`entity_changes` tables, sha-keyed and branch-agnostic); every later history \ 
query is a SQLite lookup plus a diff of only the commits git gained since. \ 
Measured on the sem repo: `sem log` over 500 commits drops from 4.46s to \ 
**0.03s** on the second query (~150x), with the first query as the one-time \ 
indexing pass and each new commit costing one incremental diff. Applies to `sem \ 
log` repo analytics (hotspots + co-change pairs) and the MCP `sem_log` tool; \ 
per-entity traces are unchanged. Aggregation is shared code between the live git \ 
walk and the store (`aggregate_history_analytics`), tested to produce identical \ 
hotspot/co-change output, so the two paths cannot drift. Merge-heavy history \ 
gets better semantics: each commit is attributed its own first-parent
 diff instead of a diff against its arbitrary revwalk neighbor, and merge \ 
commits contribute no changes of their own (their first-parent diff restates the \ 
merged-in commits, which index individually). File-filtered queries index \ 
full-repo diffs once and filter at aggregation, so the first filtered query \ 
costs more than the old pathspec-scoped walk but every later query on any filter \ 
is instant. Cache schema v9; existing caches rebuild automatically on first use.

- **CLI sidecar fast path**: `sem impact` now answers from the resident `sem \ 
mcp` server's warm graph via its unix socket before doing any local work — \ 
measured **4.5ms** end-to-end on a 158K-LOC repo, versus 22.4ms for the local \ 
cold path and 7.7ms for a ripgrep scan of the same repo: the full blast radius \ 
(callers, dependencies, depth-bounded transitive impact, affected tests) is now \ 
cheaper than a raw text match. Output is byte-identical to the local path (the \ 
sidecar ships serialized `EntityInfo`s that the CLI feeds to its existing \ 
printers; verified across all modes and `--json`). The fast path is an \ 
accelerator, never a requirement: bounded socket timeouts and silent fallback \ 
mean no resident server (or `SEM_NO_SIDECAR=1`, `--no-cache`, custom scopes, \ 
`.semignore`, `--entity-id`) just runs the normal local path. Server-side, the \ 
new sidecar `impact` op classifies affected tests only among the entities the \ 
impact BFS actually reached, instead of walking the whole corpu
s per call (6.8ms → 0.1ms on a 4.7K-entity graph).

### Fixed

- Internal: rustfmt line-wrap missed in the #445 sidecar change; no behavior change.

- The context packer's token estimator was undercounting real tokens 2-3x on \ 
dense code (words x 1.3 vs the ~4 chars/token reality: a context reported as 661 \ 
tokens measured ~2,400 real tokens), silently overshooting every budget. It now \ 
takes the max of the word- and character-based estimates, so nominal budgets \ 
match what the consuming model actually pays.

- The context packer's "not packed" summary line pluralizes roles \ 
correctly ("transitive dependencies", not "dependencys").

- Workspace version bumped to 0.16.0: `ContextResult` gained the public \ 
`omitted` field (a breaking change for struct-literal constructors, flagged by \ 
cargo-semver-checks), and 0.x semantics put breaking changes in the minor \ 
version.

- The docs site deploys through workflow-based GitHub Pages \ 
(`.github/workflows/docs-pages.yml`: upload `/docs` verbatim, deploy) instead of \ 
the legacy branch-based Jekyll builder, which began failing repo-wide with \ 
zero-duration "Page build failed" errors on commits that didn't touch \ 
docs — including on direct build requests via the Pages API. The site is pure \ 
static HTML, so the legacy builder added nothing but a failure mode; deploys now \ 
also skip entirely on commits that don't change `docs/`.

### Changed

- The GitHub Action's PR-comment footer now tells the reader what to do next — \ 
"add it to your repo in 2 minutes", linking to the action's install \ 
snippet — instead of only naming the tool. Every entity-diff comment is seen \ 
by all of a repo's collaborators; the footer is the loop that turns viewers into \ 
installs.

### Added

- **`sem repos`** — where your code is stored, in one command. Two inventories \ 
side by side: the **cloud account** (authoritative `GET /v1/repos`: every \ 
indexed repo with status, entity/file counts, last-indexed time, indexed commit, \ 
and any indexing error rendered inline) and **local storage** (every entity \ 
cache under the sem cache root with size on disk, entity count, cache kind, and \ 
the repo it was built from). `--json` for scripts. Listing the account also \ 
reconciles this machine's `~/.sem/repos.json` mirror with server truth — stale \ 
entries (a repo registered mid-index stays "pending, 0 entities" \ 
forever otherwise) were silently mis-routing the local-vs-cloud decision for \ 
impact/context queries. Caches are now stamped with their repo root at save time \ 
(`repo_root` in `cache_metadata`); caches built before this show as unlabeled \ 
and self-label on their next rebuild.

- Fish shell support, via the `tree-sitter-fish` grammar (gated behind the \ 
`lang-fish` feature in `grammar-all`). Extracts functions — including the \ 
config.fish pattern of definitions inside a top-level `if status is-interactive` \ 
block — and resolves fish call edges (a `command`'s name against repo \ 
functions, builtins excluded), so `sem impact` sees which fish functions call \ 
which. A `function` defined inside another function stays part of the outer \ 
entity's content, matching fish's runtime semantics (inner definitions become \ 
global, not lexical children). Previously `.fish` files fell back to generic \ 
line-based chunking with an unsupported-language warning. Thanks @thalys for the \ 
request (#433).

### Documentation

- **First-principles page on the docs site** (`docs/first-principles.html`, \ 
linked from every page's nav): four charts explaining why the recent latency \ 
work changes what an agent can afford to do, not just how fast it runs — the \ 
scan-vs-index crossover (a text scan pays per byte; residency removes the \ 
index's ~800ms hydrate floor, so the constant-time line wins at every repo \ 
size), the ~100ms human-perception threshold every new path now sits under, \ 
model turns as the real cost unit (3 → 2 → 1 inference turns per structural \ 
answer via one-call lookup, then prompt-time prefetch), and tokens per answer \ 
(the measured ~15% entity-tree-vs-JSON ratio). Measured numbers come from this \ 
changelog; model curves and turn timings are labeled illustrative on the page. \ 
Charts are dependency-free inline SVG with hover tooltips and a table view each.

### Performance

- **Content-store cache (storage engine layer 1)**: the entity cache no longer \ 
duplicates source text per entity. Each file's text is stored once (zstd) in a \ 
`file_contents` table, and any entity whose body is provably a byte slice of it \ 
(`content == file[start_byte..end_byte]`, verified at save time) stores NULL \ 
content and is re-sliced on load; unprovable entities (no spans, normalized \ 
endings) keep content inline. On a 139K-entity corpus (fresh cache both sides) \ 
this cut the cache 20% (269MB to 216MB; the content layer itself −58%, 80MB to \ 
24MB inline + 10MB zstd), engaged for 77% of entities. Honest costs: warm \ 
full-content loads pay ~0.13s extra for decompress+slice on that corpus (0.38s \ 
to 0.51s); topology loads and the MCP server's in-memory hot path are \ 
unaffected, and cold build time is unchanged within noise (peak RSS ~−5%). \ 
Correctness gates: byte-identical graph vs the previous binary on the full \ 
corpus, byte-identical entity content round-trip (including mult
i-byte unicode and nested entities), and incremental saves keep the file store \ 
in sync with entity deletes. Cache schema v8 — existing caches rebuild \ 
automatically on first use.

### Added

- **Entity-addressed text search**: `sem_entities` takes a `text` parameter — \ 
an exact substring searched across entity bodies in the warm in-memory graph (no \ 
file reads). Hits come back addressed by the innermost enclosing entity (`file: \ 
entity (Lline): matched text`), ready to chain into `sem_context`/`sem_impact`, \ 
in ~20-30ms warm on an 85K-LOC repo. This retires the main remaining reason \ 
agents fell back to grep (strings, error messages, config keys); misses say \ 
honestly that comments between entities and non-code files are not covered.

### Performance

- Graph build: the scope resolver no longer allocates its debug resolution log \ 
(several owned strings per reference, discarded by every production path — \ 
only a bench consumed it), and edge dedup is index-based instead of cloning both \ 
entity IDs per edge into a hash set. Output is byte-identical (proven \ 
edge-for-edge on a 139K-entity build); ~1-3% fewer instructions retired. \ 
Groundwork toward #320/#322 — the remaining peak-memory work (entity content \ 
sharing, ID interning) is tracked there.

### Added

- **`sem hook prompt-submit`** (hidden plumbing): the prompt-time prefetch, \ 
compiled. Reads a Claude Code UserPromptSubmit event, extracts identifier-shaped \ 
tokens from the prompt (backticked, snake_case, CamelCase, qualified — never \ 
plain words), resolves them against the resident server's socket sidecar, and \ 
prints packed entity context for injection. **10ms end-to-end** (was ~40ms as a \ 
Python hook — interpreter startup and a git subprocess, both eliminated: repo \ 
root is found by walking to `.git` in-process). Silent on conversational \ 
prompts, slash commands, unknown names, or when no server is resident.

### Added

- The socket sidecar is unix-only (`cfg(unix)`): Windows builds skip it with a \ 
no-op and the prefetch hook falls back silently — the sidecar is an \ 
accelerator, never a requirement. (Fixes the Windows build break the sidecar \ 
introduced.)
- **Socket sidecar**: `sem mcp` now exposes the warm in-memory graph on a \ 
per-repo unix socket (`~/.sem/sock/<repo-hash>.sock`, one JSON line in, \ 
one out). Short-lived local callers — the prompt-prefetch hook, future CLI \ 
fast paths — get one-call entity context in single-digit milliseconds instead \ 
of paying a fresh process plus SQLite hydrate (~800ms). Stale sockets from dead \ 
servers are detected and taken over; the sidecar is a silent accelerator, never \ 
a requirement.

### Added

- **One-call lookup**: `sem_context`'s `file_path` is now optional. With only an \ 
`entity_name`, the entity is resolved across the whole repo (unique match \ 
proceeds; ambiguity returns a compact candidate list with the files; no match \ 
returns near-name suggestions) and the body plus callers/callees comes back in a \ 
single round-trip — one agent call where grep needs two (search, then read). \ 
Measured 26ms wall on a prewarmed server, name-only, unfamiliar repo.

### Performance

- The sem MCP server is now **local-first and prewarmed**. Cloud-first routing \ 
on `sem_impact`/`sem_context` cost a network round-trip on every call before the \ 
local answer (and carried the same wrong-entity risk gated in the CLI); it is \ 
now behind `SEM_MCP_CLOUD=1` until the server resolves name+file strictly. The \ 
server also builds the CWD repo's graph in the background at startup, so the \ 
agent's first structural query answers from memory. Measured on an 85K-LOC repo: \ 
warm `sem_context` runs in under 1ms wall (faster than a ripgrep scan of the \ 
same repo), and the first call dropped from 129ms cold to ~0 with prewarm.

### Removed

- Team presence was pulled from the `--badge` package before it shipped as a \ 
feature (product call: not a feature for now). The statusline no longer shows \ 
teammates and the hook sends nothing anywhere; the dormant server endpoints \ 
remain unadvertised.

### Added

- The `--badge` statusline is now **live at trigger time**: a PreToolUse hook \ 
flips the badge to an animated spinner with the entity name the moment the agent \ 
calls sem (`⊕ sem ⠹ impact validateToken…`), and the completed state \ 
(count, latency, savings) lands when the call finishes. The render hot path \ 
never touches the network (renders measured at ~20ms).

### Fixed

- The `sem context` / `sem_context` budget packer no longer starves the target \ 
while neighbors feast. Previously a target too big for the budget collapsed to \ 
its first line (2 tokens) while a single large dependency could consume the \ 
entire budget with its full body. The target now degrades gracefully — full \ 
body → head-truncated body (docstring, fields, leading code, with an explicit \ 
`… truncated: N more lines` marker) using up to ~70% of the budget → bare \ 
signature — and no neighbor may cost more tokens than the target itself did \ 
(budget/10 floor), oversized neighbors degrading to signatures. On the same \ 
query (a large class, budget 2000) the target went from 2 tokens to 1,398 and \ 
the answer-relevant attributes are now in the payload.

### Added

- **Entity-level history analytics**: `sem log` with no entity now analyzes \ 
recent repo history in one pass and reports **hotspots** (the most-changed code \ 
entities, with commit counts, distinct authors, and the last commit that touched \ 
each) and **co-change pairs** (entities that repeatedly change in the same \ 
commits, with a confidence score — "these two never change apart"). \ 
Counts are per commit, code entities only (doc headings, config properties, and \ 
lockfile chunks are excluded so the signal is about code), and bulk commits \ 
touching >50 entities are excluded from pair-counting to keep quadratic noise \ 
out. Same via MCP: `sem_log` without `entity_name`. `--file` scopes to one file; \ 
`--json` returns everything. This is the time axis a snapshot dependency graph \ 
cannot see: which code churns, and which code moves together.

### Changed

- `sem_impact` MCP results now render as a **blast-radius tree** (`◉` header, \ 
one `├─▶` branch per file, real callers first, all-test files sunk to the \ 
bottom, nothing elided) — expanding the tool widget is the live graph, no \ 
separate viewer process needed. The bundled skill also instructs agents to draw \ 
the blast radius as a small ASCII tree directly in their reply when an impact \ 
result drives the answer.

- `sem_impact` and `sem_context` MCP results now render as a compact entity tree \ 
instead of pretty-printed JSON: dependents/dependencies/transitive impact \ 
grouped one line per file, every entity name preserved, with the elapsed time \ 
and source in a footer. The same information lands in about 15% of the tokens, \ 
and the expanded tool widget in agent UIs reads at a glance (`⊕ entity · \ 
file`, `← 29 dependents · 10 files`, `⚡ 70 transitively affected`). Context \ 
entries keep their verbatim content under a per-entry header.

## [0.15.1] - 2026-07-01

### Added

- `npx @ataraxy-labs/sem-skill --badge` (opt-in) installs a live sem badge in \ 
the Claude Code statusline: it shows how many structural queries ran this \ 
session, the last command **and the entity it analyzed**, its latency, a \ 
sparkline of recent latencies, and a rotating stat (distinct entities analyzed, \ 
top command) (`⊕ sem ×12  impact validateToken 9ms  ▁▂▃▅▂  · 7 \ 
entities analyzed`). It is fed by a PostToolUse hook that catches sem via \ 
**both** the MCP tools and the `sem` CLI (Bash), and falls back to recent \ 
activity so the badge never stalls on "idle". Non-destructive: it \ 
backs up settings and never overwrites an existing statusline (it prints how to \ 
add the badge yourself instead).
- **GitHub Action** (`Ataraxy-Labs/sem/action`): entity-level semantic diff \ 
comments on pull requests. One sticky comment per PR showing which \ 
functions/classes/methods were added, modified, or deleted, updated in place on \ 
every push; cosmetic-only PRs (formatting/comments) are called out explicitly. \ 
Installs the prebuilt binary (~2s), needs no config or API keys, and never fails \ 
the build. sem's own PRs now dogfood it via \ 
`.github/workflows/pr-entity-diff.yml`.
- The savings meter now lives in the **statusline itself** — no extra process. \ 
The `--badge` badge always shows the live estimated time + tokens this session's \ 
sem calls saved vs grep+read (`⊕ sem ×5 diff · ≈ 4m · ≈ 25k tokens \ 
saved`), and when idle it shows the lifetime total (`⊕ sem idle · ≈ 3h · \ 
≈ 190k tokens saved`). The PostToolUse hook is the single writer of the \ 
persisted lifetime tally (`~/.claude/sem-savings.json`), so the counter grows \ 
from real usage whether or not the live viewer is open. Estimates stay anchored \ 
to the measured benchmark and labelled `≈`.
- Live viewer for the `--badge` install: `~/.claude/sem-live.py` (run it in a \ 
spare terminal pane). It redraws an ASCII blast-radius graph each time sem runs \ 
— the analyzed entity, its direct callers (real ones surfaced, test fan-out \ 
collapsed), and the transitive count — plus a **savings meter**: a running, \ 
honestly-estimated tally of the grep+read round-trips, time, and tokens sem \ 
saved this session, and a lifetime counter persisted across sessions \ 
(`~/.claude/sem-savings.json`). Estimates are anchored to a measured benchmark \ 
and labelled `≈`. The badge hook now also records `--file` and cwd so the \ 
graph can be reconstructed.

### Fixed

- Repository discovery now tolerates Git worktrees that use the \ 
`extensions.relativeworktrees` config key, avoiding libgit2's \ 
unsupported-extension error when plain `git` can open the checkout.
- Cloud-backed `sem impact` / `sem context` no longer answer queries they can't \ 
answer correctly. Two gates added: `--no-cache` now always computes fresh \ 
locally (previously the cloud snapshot was served anyway), and **file-hinted \ 
queries (`--file`) stay local** — the cloud resolves entities by name with a \ 
silent name-only fallback, so for same-named entities (e.g. ten `fn run` command \ 
handlers) it could return the *wrong entity's* graph, and a stale cloud index \ 
could drop dependents that exist locally. Local resolution disambiguates \ 
exactly; the cloud path returns once the server resolves name+file strictly and \ 
exposes its indexed commit for a freshness check.
- Impact/dependency resolution now follows type-qualified associated calls \ 
(`Type::method()`) when the receiver is a known repo type, so a caller reached \ 
only through a static/associated path is no longer dropped from `sem impact`. \ 
Previously, e.g., a test helper calling `SemPlugin::detect_changes()` was \ 
invisible to the reverse-dependency graph, and its transitive callers were \ 
missing from the blast radius. Resolution stays precise: a bare module path \ 
(`foo::bar::baz()`) still does not bind to a same-name local function, and \ 
common associated names (`Type::new`, `::default`) are not guessed.

### Performance

- Faster graph hydrate on large repos. The public `EntityGraph` maps now use \ 
`rustc-hash` (FxHashMap) instead of std SipHash, matching the build's internal \ 
maps, and the SQLite cache sets read pragmas (`mmap_size`, `cache_size`, \ 
`temp_store=MEMORY`) on every connection. On a 200K-entity / 800K-edge graph \ 
this is about 9% faster to hydrate (0.42s to 0.39s, no overlap across repeats); \ 
negligible on small repos. Output is byte-identical.

## [0.15.0] - 2026-06-30

### Changed

- Whole-repo commands (`sem graph`) now skip the file-discovery walk when git \ 
proves the cache is fresh (HEAD unchanged and the working tree clean), serving \ 
the cached topology directly. On a 200K-file repo this is about 9x faster with \ 
git fsmonitor and about 4.5x faster without it; small repos and non-git repos \ 
are unchanged. The oracle only ever declines to accelerate, never serves stale \ 
results, and the `git status` check is time-bounded (`SEM_FRESHNESS_TIMEOUT_MS`) \ 
with `SEM_FRESHNESS=scan|git|auto` to override.

### Added

- `sem xref` lists cross-repo dependencies across your indexed repos: entities \ 
in one repo that depend on entities in another. A single-repo local graph can't \ 
see this, so it's a cloud feature (requires `sem login`) and is gated to the \ 
team/enterprise tier. Adds `cross_deps()` to the shared cloud client.
- `sem diff` now prints a one-line hint, when run interactively and logged out, \ 
that `sem login` reveals what your changes break across repos (a cross-repo \ 
question a local single-repo diff can't answer). It is heavily throttled (at \ 
most once a week), shown only on a terminal with real entity changes, and stays \ 
completely silent in CI, pipes, `--json`/non-terminal output, and for logged-in \ 
users.

### Performance

- Cache freshness checks now run the per-file `stat` + content-hash scan in \ 
parallel (rayon) instead of sequentially (#351). On touched-file cache hits over \ 
large repos, the freshness scan was the dominant remaining cost (~42ms of \ 
sequential filesystem/hash work on a 5K-file touched scenario); it now scales \ 
across cores. SQLite reads stay serial (the connection isn't shared across \ 
threads) and fingerprint-refresh writes remain serial and best-effort — only \ 
the pure filesystem+hash work is parallelized, so cache-hit validity is \ 
unchanged.

### Documentation

- The bundled `/sem` agent skill no longer hardcodes a language count. It said \ 
"31 languages", which went stale as grammars were added and disagreed \ 
with the README ("32") and the crate description ("28"); it \ 
now says "30+ languages" so it can't drift, and an en-dash was \ 
replaced with a hyphen.
- README: documented the optional cloud acceleration flow (`sem login` serves \ 
`impact`/`context`/`entities` from a warm pre-built graph for large repos; local \ 
is unchanged and `SEM_LOCAL=1` forces local), and added Lua to the \ 
supported-languages table.

### Added

- Lua support, via the `tree-sitter-lua` grammar (gated behind the `lang-lua` \ 
feature in `grammar-all`). Extracts global, `local`, table (`t.f`), and method \ 
(`t:f`) functions. Thanks @mmgeorge for the request (#393).
- `SemanticEntity` now carries optional `start_byte`/`end_byte` offsets, \ 
populated from the underlying tree-sitter node during code extraction. A \ 
consumer can slice the exact original bytes of an entity out of a file given \ 
only its `file_path` and span, without re-parsing. Persisted through the entity \ 
cache and surfaced in `sem entities --json`. Thanks to Thomas J. for the \ 
request.

### Added

- `npx @ataraxy-labs/sem-skill`: one-command setup of sem for coding agents. \ 
Installs the sem skill into `~/.claude/skills/` and registers the `sem mcp` \ 
server, so an agent uses sem (impact / context / orient / diff) over grep for \ 
structural questions without manual setup. Builds on the skill contributed in \ 
#376.

### Added

- An agent skill (`skills/sem/SKILL.md`) documenting sem's semantic diff, \ 
impact, blame, history, context, and graph workflows for coding agents. Thanks \ 
@linhlban150612 for the contribution (#376).
- `self-update` Cargo feature (on by default) gates the built-in `sem update` \ 
and the background update-available check. Distro and package-manager builds \ 
that own the binary's lifecycle can opt out with `cargo build \ 
--no-default-features`; `sem update` then prints a "update through your \ 
package manager" message instead of replacing the binary. Thanks @0323pin \ 
(pkgsrc/NetBSD) for the request (#390).

### Added

- `sem context --hops N` bounds the related entities to N graph hops from the \ 
target (instead of filling to the token budget), so you can ask for "the \ 
entity and just its immediate neighborhood." The `sem_context` MCP tool \ 
gains the same `hops` parameter. 0 (the default) keeps the existing unbounded, \ 
budget-driven behavior.

### Changed

- The `sem mcp` instructions now tell agents to read code with `sem_context` \ 
(which returns an entity's full source plus its callers/callees, addressed by \ 
name) rather than opening the file, reserving direct file reads for editing and \ 
non-code. Reading by entity is robust to line drift and arrives with the \ 
dependency context.
   2026-06-25 14:50:40 by pin | Files touched by this commit (5) | Package updated
Log message:
devel/sem: disable self-update

While here also install shell completions.
   2026-06-24 09:27:56 by pin | Files touched by this commit (3) | Package updated
Log message:
devel/sem: update to 0.14.1

Fixes the Intel macOS cross-build (vendored-openssl) so the release actually
ships binaries for every platform. 0.14.0's build failed on openssl-sys when
cross-compiling x86_64 on Apple Silicon; 0.14.1 is the first release to publish
Intel macOS binaries (#374).
   2026-06-23 11:03:37 by pin | Files touched by this commit (6)
Log message:
devel/sem: import package

Packaged in wip mostly by wiz@ with some mods from myself.

sem is a semantic version control tool that works on top of Git.
It parses your code with tree-sitter, extracts every function, class, and
method as an entity, and diffs at the entity level instead of lines.
This means you see "function blahh was modified" instead of \ 
"lines x-y changed."

It works in any Git repo with no setup.