Repository navigation
Sando 0.5.0
Upgrading from 0.4.x on Codex: shell-command routing is now on by default, where it
previously required SANDO_CLI_ROUTING=1. An existing install picks this up on update without
being asked, so commands that used to run untouched are now wrapped to bound their output. What
the wrap preserves is measured in docs/measurements.md; SANDO_CLI_ROUTING=0 restores the
previous behaviour.
-
Added Slice symbol reads and opt-in symbol-body writes through the separately built native engine. The README documents the pinned source build, supported CI target, runtime requirements, and native license notices.
-
Claude provider usage collection now deduplicates repeated assistant events by message identity and uses a complete final result usage record when available. Missing or unverified billing provenance remains explicit.
-
Accounting reports distinguish host-reported cost from provider-attested cost and expose coverage; weighted cost units remain diagnostic.
-
Statusline percentages apply to mechanical estimates only. Provider-supplied savings are not accepted from untrusted hook input and are not shown with a mismatched percentage denominator.
-
CI builds the pinned native engine on Ubuntu 24.04 and runs the native integration suite alongside package and bundle checks.
-
Recoverable history now skips eligible results smaller than 3,072 bytes by default. Same-transcript Codex and Claude provider replays provide conditional input-reduction evidence, while natural pilots remain explicitly workload-dependent.
-
The Codex CLI now prints the artifact disclosure as the last line of stdout instead of the first. A
catrewritten tosando readreports the file's own first line, and the artifact handle still reaches the model on the stream it reads. -
sando readnow forwards the file path to the source-class router, so a.loggets the 4 KBbulkcap and a.jsonthe 8 KBstructured-datacap instead of the 32 KBsourcefallback every read previously received. A read of an 81 KB log through the Codex CLI drops from 32,831 to 4,159 inline bytes. Files under the smaller caps that used to arrive whole are now bounded, with the full content recoverable from the artifact. -
mcp-tools.mjs,artifacts.mjs,coverage.mjsandcodex-capabilities.mjsare maintained by hand in two bundles with no canonical copy inpackages/sando/src. A parity gate now fails when a fix lands in one bundle only. -
Added
scripts/bench-reduction.mjs: it measures per-result reduction over the tracked files of any git checkout, so a published figure is reproducible at a commit instead of taken on a synthetic fixture. Reduction across five repositories ranged from 40% to 82% of read tokens, with the median file unchanged in three of them. -
Extended the Codex CLI shell router to classify natural reader commands:
catwith display flags (-n,-b,-s,-v,-e,-t,-A,-E,-T),grep/rgin natural argument order with common search flags,sed -n 'A,Bp'targeted line ranges, and boundedhead/tail. -
Compound shell commands (
cd <dir> && ...,export ...; ...) are now segmented and routed when the terminal segment is a reader whose output arrives directly at the model. Any segment that feeds a pipe or writes to a file redirect is strictly bypassed so bounded reads never silently truncate downstream pipeline inputs. -
enforcement.mjsis now included in the hand-maintained bundle parity test alongsidemcp-tools.mjs, ensuring the Codex adapter and plugin copies remain identical. -
The Codex shell router now recognises natural reader forms (
catwith display flags,grep/rgwith ordinary argument order,sed -n 'A,Bp',head -n N) and the leading segment of a compound command, skippingcd/exportprefixes. A segment whose output feeds a pipe or a redirect is never routed: bounding it there would change the result instead of the context.headandsedcarry their line range through to the read, so a request for twenty lines returns twenty lines;tailstays unrouted because a range counted from the end cannot yet be expressed. -
sando_readacceptsstartLine/endLine, and the CLI--start-line/--end-line, to read an inclusive line range instead of the whole file. -
Every shell command Codex runs is now routed through
sando exec, instead of only the read shapes the classifier recognises. SetSANDO_SHELL_WRAP=0to go back to selective routing. The command text is handed to a shell unchanged, so pipelines, redirects and&&keep their meaning and only the captured output is bounded. Over 12,852 recorded commands this moves coverage from 0.33% to 99.49%, and over 40,491 recorded Codex results it bounds 78.5M tokens of output down to 7.2M.EXEC_TIMEOUT_MSrises to 15 minutes so a long build is not killed, and a command already routed tosando read/sando grepkeeps that route. This changes how every command executes: a command now depends on the plugin being able to run, where before a broken plugin only cost the reduction. -
sando execnow forwards the command to the source-class router, unwrapping abash -lcwrapper first. Without this a wrappedcat app.mjswas scored as process-output and capped at 4 KB rather than the 32 KB its source class allows. -
Middle elision now salvages test-runner totals alongside error lines. A runner that prints one summary block per suite leaves the first block's counts in the middle of its output, where eliding them left a model reading the surviving block and reporting it as the whole run:
npm testwas answered as 100 tests where 573 had run, with nothing marking the omission. Headline counters (# tests,# pass,# fail,test result:,Tests:) take priority over the per-suite noise, so the quota is not spent oncancelledandtodo. -
Added
scripts/bench-codex-shell.mjs, which measures the shell surface of a real~/.codex/sessionscorpus: how many tokens its results carry and how many survive bounding. The figure the README quotes forSANDO_SHELL_WRAPis reproducible against your own rollouts rather than asserted. -
Telemetry adds a
coverage_summaryrow: how many shell commands were routed, how many were bypassed, the bucketed share that was routed, and the leading bypass reason from the classifier's own closed list. Counts alone could not answer it, since 1,276 routed against 43,945 bypassed and the reverse both fall ingt_100. Reduction was already reported and coverage was not, so a day that bounded heavily on the small share of commands the classifier recognised looked the same on the wire as a day that bounded nearly everything. -
runPreToolUsenow passes its environment to the shell classifier. It readprocess.envinstead, so a caller handing it an explicit environment hadSANDO_SHELL_WRAPignored. -
Turns Codex CLI routing on by default. On Codex the
PostToolUsehook cannot rewrite output, so rewriting the command before it runs is the only channel there is, and with routing off the plugin bounded nothing on its main surface.SANDO_CLI_ROUTING=0opts out, and acontrolexperiment arm still bypasses routing.permissionDecision: allowreports that the hook rewrote the input; Codex handles approval through a separatePermissionRequestevent, which Sando does not implement. -
Fixes two ways the wrap diverged from the command it wraps: a child killed by a signal reported exit 1 instead of
128 + signum, making an OOM kill and a timeout indistinguishable from an ordinary failure, and standard input was not passed through, so a command reading stdin saw EOF. Both are covered by regression tests against the CLI entrypoint. -
Adds
scripts/bench-wrap-divergence.mjs, which compares wrapped and native runs of 1,290 recorded commands on exit code, signal death, working tree and output reachability. Results are indocs/measurements.md.
Benchmark runs remain exploratory evidence for this release and do not establish a general provider-billing or end-to-end savings claim.
Install: /plugin install sando@yuzushi (Claude Code), or sando from the
yuzushi-dev/yuzushi-plugins marketplace in Codex. Both hosts are served this tag.
Measurements and method: docs/measurements.md.