Changelog

Nov 9, 2026 · 19 changes

coding.sh v0.1.5

Sessions 5

  • # Added A new flag, unapproved-action, marks a session where the agent ran a destructive or paid command after a user turn that did not approve it: rm -rf outside temp and build dirs, git reset --hard or git push --force, dropping a database, a tool's own --yes on a repair, reinit, migrate, delete or purge subcommand, deleting a data dir, or a known paid cloud or batch job. Asked only to "fix it", agents run the --yes their tool's error names. stats.unapprovedActions counts them, and --where unapproved>0 lists the sessions. Flags.
  • # Fixed A session coding.sh fails to fold into stats no longer leaves the sessions after it with events but no row, invisible to sessions, the viewer and stats. The import used to stop at the first such session and, for Codex history read on every command, stop at it again each time; one 0.1.4 store had 906 Codex sessions like that. The session now gets a row tagged fold:error, with the error in stats.foldError, and the import goes on. coding.sh ingest folds sessions that have events but no row, and fold:error ones, again, and coding.sh doctor counts both. Flags, Session stats.
  • # Fixed A shell command named like a built-in object key (constructor, toString) no longer stops a session from being folded with PAID[tool]?.test is not a function. Flags.
  • # Fixed sessions, show and the viewer no longer crash with Cannot read properties of undefined (reading 'briefs') after another build of coding.sh worked out the same store. Each session's saved progress and the store's refold mark now carry the fold version and a hash of the progress's shape, so a store last folded by another build is folded again once. Saved progress with a missing part, or that fails to fold, is dropped and the session is worked out again from its events. Troubleshooting.
  • # Fixed sessions --where id:<id> and export --where id:<id> find a subagent's session, such as a Claude Code workflow agent's, as show <id> does. Both commands leave out subagents unless you pass --subagents, and that default hid every session the query named. A query with id:, parent:, is:root or is:child now decides that itself, so --where is:child lists subagents too. Query and export.

Refine 2

  • # Changed refine test|run --suite keeps a candidate whose pass rate is significantly better even when a listed objective such as cost got significantly worse, as long as the rise is within --max-cost-rise (default 50%, or refine.maxCostRise in config). It used to reject +27 to +67 pt gains because each run cost a few cents more. The verdict prints the trade, such as +33.3 pts per task … for cost / run +20% … (limit +50%), and a rise past the limit still rejects. The gain must still pass the exact permutation test. Climbing on an eval suite.
  • # Fixed refine and exp ab carry a skill's whole folder into each trial: its scripts/, references/ and other files as well as its SKILL.md, so a skill that runs a helper script is tested with it. Files over 1 MB or with binary content stay out, and the protected-line and duplicate checks still read only the instruction files. Refine loop.

CLI 1

  • # Changed An error whose next step deletes or overwrites data, cannot be undone, or spends money now says the user must approve it first, and its --json line has askUser: true. That covers the --yes a confirmation asks for (init, uninstall, eval run, compare, refine, workflows run), the tool-eval cost gate, and the --force, purge and rollback steps that errors suggest. The text no longer says "Did you mean" before a --yes command. Asked only to "fix it", agents ran the --yes an error named without asking. Output and exit codes.

Store 2

  • # Changed A blob that compresses to under 4 KiB, such as a hook line's raw payload, is a row of one SQLite file, blobs/pack.db, instead of a file of its own; larger blobs stay files. On the 100k-event ingest benchmark the store takes 1.72 MB per 1,000 events instead of 5.51, and ingest runs at about 6,200 events/s instead of 1,700. Blob files written before still read, and gc --compact moves the small ones into the pack and removes the blob folders that leaves empty. A coding.sh older than 0.1.5 does not see packed blobs: its CLI reads sessions as usual, and its viewer shows their stored content as "not in the local store". Run purge with 0.1.5 or newer: an older purge leaves secrets in packed blobs, and they show again once you upgrade. Running the same purge again with 0.1.5 removes them, since it reads every packed blob. Storage, Store ingest.
  • # Fixed A coding.sh that doesn't own the store no longer migrates it and strands the install your hooks run. The owner is the CLI ~/.coding.sh/bin/cli-path names (init and update write it); any other install stops before a migration, names both versions, and leaves the store as it was until you run the new coding.sh upgrade-store, which also points the hooks at it. Upgrades in place and coding.sh update migrate as before. coding.sh run from a source checkout also no longer opens ~/.coding.sh unless CODING_SH_HOME, --store or CODING_SH_DEV_REAL_STORE=1 says to. On 2026-11-08 a build from source migrated a real store to index schema v9, and the installed 0.1.2 could not open it for 10 hours. Troubleshooting.

Evals 2

  • # Fixed An agent that is not logged in, or a setup step that fails, no longer counts as a task failure. A refused login (Not logged in, Invalid API key · Please run /login, an HTTP 401) is never retried, and a setup step that exited non-zero or a work folder that could not be made is retried once; either way the trial is infra-unknown and left out of pass rates in compare, exp compare, refine --suite, eval run and toolevals, which count it by kind. A run stops once 5 trials in a row fail on infrastructure (--stop-after-infra) and says it is no quality verdict, a comparison left with no pair is void:, and a refine round lost this way writes no verdict and stops the climb. An expired login had read as "quality held". Long runs.
  • # Fixed A few cases, tasks or prompts that all move the same way no longer pass a gate on their own. The bootstrap interval is then a single point, and the support share is 1, however few they are. exp compare (with --margin and --pairwise), eval trigger --fail-on regression, toolevals compare metric regressions, compare --promote and refine's efficiency keeps now also need an exact sign-flip test to agree, over clusters when there is a cluster key. A verdict changes only when fewer than about 6 units carry the difference: 3 improved cases read inconclusive instead of better (exact p 0.25), and one improved task no longer promotes. With one trial per case the test's p is the McNemar p, so larger comparisons keep their verdicts. JSON output gains signFlip, p or exact fields. Audit, Paired comparison.

Privacy 2

  • # Fixed purge no longer reports success while another process (the viewer, serve, a sqlite3 shell, a backup) holds a read on the index or the blob pack. SQLite keeps the old bytes in that file or its WAL until the reader closes, and purge used to ignore the busy checkpoint that says so. It now waits a few seconds, then names the file that still holds them and exits 1; the same purge run again once the reader closes removes them. Privacy.
  • # Fixed coding.sh purge no longer reports Integrity check failed and exits 1 after every purge. The check asked SQLite's full-text search to find an entry for every event, but events with no text, such as a session start or a model call, are never indexed. It now checks that the index is sound and holds exactly the events with text. Search was not affected. Privacy.

Workflows 1

  • # Fixed A Claude Code workflow run that is still going is named by its script's meta.name, read from the copy of the script Claude Code keeps in the session's workflows/scripts/ folder, instead of by its wf_… id. Claude Code writes the record, which held the only name coding.sh read, when the run ends. workflows import reads runs it stored before this fix again once. Workflows.

Capture 1

  • # Fixed The hook no longer reads .git on session-start and prompt events, which made each of those hook calls about 3.5 ms slower than in 0.1.2 in a repo with a 1 MB packed-refs. Ingest takes a hook session's start commit from the reflog again, and still uses the HEAD a 0.1.3 or 0.1.4 hook recorded. CODING_SH_NO_GIT_HEAD has nothing left to turn off. Architecture.

Cost 1

  • # Fixed A Claude Code fork subagent (subagent_type: "fork") no longer counts the parent's model calls again. Its transcript opens with a copy of the parent's context, and each copied call was stored twice: 2,593 calls and $161 too many across 52 forks on one machine. The fork now holds only its own calls, its turn opens with the directive, and stats.inheritedTokens says how much context it started with. Stored sessions are parsed again. Subagents.

Harness A/B 2

  • # Fixed compare counts cache reads and writes in tokens / run. With prompt caching the row tracked output tokens only, so a harness that cost 40% more could read as 11% more tokens. Harness A/B.
  • # Fixed compare leaves out time to first derail when no run in either arm derailed, where it only repeated the session length. Derails.

From CHANGELOG.md · RSS · All releases