All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- A skills-only Codex package for
refine-gate, exposed through a repository marketplace at.agents/plugins/marketplace.json. - Gemini CLI installation through the existing portable Agent Skill.
- OpenSSF Scorecard, CodeQL, Dependabot, and a hash-locked development dependency set.
- Security, contribution, conduct, governance, architecture, assurance-case, Scorecard, and twelve-month roadmap documentation.
- A release workflow that tests and self-verifies a source bundle, publishes SHA-256 checksums, an executable manifest and CycloneDX SBOM, and creates Sigstore build-provenance attestations.
- Regression tests for context-guard hooks, prompt-refinement measurement, statusline transcript handling, and release integrity.
- The
refineskill now uses the portable Agent Skills frontmatter and host-neutral wording. Claude'sUserPromptSubmithook and plugin manifests are unchanged. - CI actions are pinned to full commit SHAs, workflow permissions are read-only by default, ShellCheck is checksum-verified, and Python dependencies are installed from the hashed lock file.
- CI measures the shipped Python surface with coverage.py's subprocess support and enforces an 80% floor; the initial complete measurement is 94%.
- The repository introduction now leads with its portable Codex, Gemini CLI, Claude, and Agent Skills surface while preserving explicit labels on Claude-only integrations.
- The statusline transcript scanner now recognizes valid compaction records whose JSON contains insignificant whitespace before confirming the parsed marker values.
Statusline only. No change to context-guard or refine-gate.
- The line-width budget is now the host's actual reserve, not a 15% haircut.
FIT_RATIO=85held every line to 85% of the terminal, a figure inherited from an unrelated plugin and never verified here. The reserve Claude Code takes is additive, and it is now read from the host itself (2.1.220): 4 columns of container padding (<Box paddingLeft={2} paddingRight={2}>) plusstatusLine.paddingon both sides. On a 200-column terminal a line may now use 196 columns instead of 170; narrow terminals reserve less than before. - Preset selection no longer contradicts the budget. The verbosity preset is
chosen on the fitted budget rather than the raw width. Previously
lwas selected from 90 columns up but could not render untrimmed below 104, so between those widths it was selected and then trimmed on every refresh. $COLUMNSis consulted before the controlling tty. The host sets it to the width it renders into, which is the authority; the tty probe stays as the fallback for hand-run invocations. Under the host the tty probe answers nothing at all — there is no controlling terminal in the hook environment.
- The claim that an over-wide first line drops the second status line is false
for 2.1.220: each line is rendered
<Text wrap="truncate">independently.
test_perf_heat_rgb_20run_avgwas flaky (~4 runs in 10) and asserted nothing: it compared one sample ofheat_rgbagainst the mean of twenty more of the same call, so the delta was noise around zero, and per-sampledate +%s%Nforks vary by ~19 ms on the measurement host — four times the 5 ms budget being asserted. It now times a block of 2000 calls against an equally-sized no-op control, amortizing the fork:heat_rgbmeasures 0.13 ms above the control against the same 5 ms budget.
Statusline only. No change to context-guard or refine-gate.
statusline-costs.pyis removed. Every dollar figure now comes from one ledger,costs.shover~/.claude/statusline-costs.jsonl. The Python aggregator summed every assistant line of every transcript and over-counted ~2.2x, because Claude Code re-logs one API response 2-3 times (streaming / tool continuation); a correct total must deduplicate onmessage.id:requestIdbefore pricing. Measured over 172 local transcripts: $3438.84 deduped vs $7645.04 raw.costs.shalso prices the full recursive<transcript>/subagents/subtree, so Task, worktree-isolated and workflow agents are all billed — none of them appear in Claude Code's own.cost.total_cost_usd. Installs carrying a stale~/.claude/statusline-costs.pyshould delete it; the SessionStart hook now does so.- The renderer ships as a directory.
statusline-command.shis a composition root that sourcesstatusline-lib/*.sh, which must be installed next to it. A missing module is a hard failure that names the file rather than a partial statusline.$STATUSLINE_LIBoverrides the location.
costs.sh+pricing.jsonas bundled assets (the ledger and its prices).- Terminal-width fitting: each line is held to 85% of the probed width, and
fit_linedrops whole trailing segments — lowest priority first — rather than letting the host truncate mid-word and cost the block a row. Width is probed from the controlling tty,$COLUMNS, thentput cols(only when stdout is a terminal);$STATUSLINE_COLSoverrides. - Verbosity preset now falls back to
sbelow 90 columns. The config's"size"is a preference capped by width;$STATUSLINE_SIZEremains a hard pin honoured at any width. - Pace on both rate-limit windows: used% over the share of the window
elapsed, which is the linear projection of usage at reset (
1.0xlands exactly on the cap). The percentage carries the worse of the absolute and pace severities; the pace figure carries its own. Nothing is printed below 10% of the window elapsed, where the extrapolation is not informative. - Tests:
tests/statusline/test_fit_and_pace.sh(46 tests — fitting, pace, severity, the width probe, preset resolution, the module loader's failure path, and the §4.1 size cap),tests/statusline/measure_widths.sh(per-preset width measurement). - CI now shellchecks
tests/statusline/*.shas well as the assets. A checker that skips the suites lets the code guarding the renderer rot unwatched.
- The identity line renders
model | dir | effort | thinking. Segment order is priority order under width fitting, and the previous order putdirlast, which made the working directory the first thing dropped on a narrow terminal. - The renderer is split into ten modules, one concern per file, none over 500
lines (
rules/coding-standards.md§4.1; the single file had reached 1022). Behaviour-preserving: verified byte-identical across a 34-configuration preset x width golden render. - Docs: both READMEs described an emoji-based layout that the word-based design-system rendering had already replaced.
stat -fis BSD-only; every mtime read now goes throughfile_mtime, which tries the BSD and GNU spellings. On Linux the bare call silently read 0, forcing a cache refresh on every invocation.- A non-numeric
used_percentage("n/a") rendered as a healthy 0%: awk reads an unquoted non-numeric token as an uninitialised variable. Values are now validated before awk sees them. tput colsreturns terminfo's blind 80 when stdout is a pipe, which is how the host captures the renderer — it is now consulted only when stdout is a terminal, so IDE and web sessions no longer silently downgrade.- A non-numeric
$STATUSLINE_COLSwas printed straight through, breaking every arithmetic width comparison downstream. The override is an escape hatch, not an exemption fromprobe_cols's postcondition: an invalid value now falls through to the probes. - The terminal-size probe leaked
Device not configuredon every refresh with no controlling tty: the failing redirection is reported by the shell itself, so the whole group is now redirected, not just the command.
- The monolithic
session-optimizerplugin is split into three independently installable plugins, shipped from the same marketplace:- context-guard —
Stop-hook context budget with a per-model checkpoint protocol, budgetedmemory-writercheckpoint subagent, and aSubagentStopspend tracker. - refine-gate —
UserPromptSubmitprompt-binding gate +/refineskill. - statusline — multi-line status bar with RGB-gradient context bars, cost tracking, telemetry, and rate-limit gauges.
- context-guard —
- The root
session-optimizerplugin remains only as a deprecation shim: it registers no functional hooks and just announces the migration at session start.
- Runtime Cortex detection: the checkpoint protocol uses a generic, vanilla-Claude-Code wording by default and switches to the scoped memory layer only when it is detected as installed.
- Statusline install skill (
/plugin install statusline@..., then ask Claude to "install the statusline") plus an auto-update hook that keeps the installed copy in sync with the plugin's bundled assets. - CI (
.github/workflows/ci.yml): runs all three test suites, shellchecks the statusline renderer, and validates every plugin/hook/marketplace JSON. - Privacy policy (
PRIVACY.md), as required by the plugin Directory Policy.
- Hook registration is single-sourced in each plugin's
hooks/hooks.json(no duplicate definitions inplugin.json). - Statusline documentation translated to English.
- Statusline renderer is shellcheck-clean at full severity; remaining suppressions are justified inline.
- Install the plugins you actually use (any subset):
context-guard,refine-gate,statusline. - Uninstall the old plugin:
/plugin uninstall session-optimizer. - Your
~/.claude/ctxguard-thresholds.json, checkpoint files, and statusline config are untouched — the new plugins read the same paths. - If you had installed the
memory-writeragent manually into~/.claude/agents/, you can remove it; context-guard ships its own copy (context-guard:memory-writer).
Releases up to v1.4.3 shipped the monolithic session-optimizer plugin.
See the git tags (v1.0.0 … v1.4.3) for their history.