Environment
- Pi
0.84.2 (pinned) and Pi 0.85.1 (current global), Node v26.7.0, npm 11.19.0, macOS, Apple Silicon
- SoL-Pi
main @ d7ecfc089944f0d04b80122a0a9a6ca0d786f3d0, version 0.1.0
- Model backend:
deepseek/deepseek-v4-flash via openai-completions (not a frontier model, and not xhigh)
- Pi installed in an isolated prefix; agent dir isolated via
PI_CODING_AGENT_DIR. Upstream Pi was not patched.
- Config:
actionFusion: true, observationPack: true, evidencePreservingReducer: false, onlineContextCompact: false
What I verified as working
Thanks for the held-out methodology and for shipping a no-Pi-patches extension. The following all passed on the pinned release:
npm ci --ignore-scripts — 289 packages
npm run typecheck — clean
npm test — 18 files / 139 tests passed
npx vitest run tests/all-mechanisms.test.ts — 4/4
node scripts/check-pi-compat.mjs — exit 0
scripts/check-sol-pi-config.mjs — correctly rejects unknown keys, version != 1, non-boolean flags, and partial config under --require-all-enabled (all exit 1)
- Pi startup with
--offline --approve, no extension load error
Both local mechanisms produce real, auditable effect:
Action Fusion — edit with then_run executes and returns one fused observation:
Successfully replaced 2 block(s) in calc.js.[then_run:succeeded]
PASS add(2,3): got 5, expected 5
...
ALL TESTS PASSED
Turns dropped 4 -> 3 versus stock Pi on the same task.
ObservationPack — archive and ledger are real. ledger.jsonl:
{"event":"placeholder","sendNumber":3,"originalBytes":11499,"originalTokens":2875,"placeholderTokens":336,"removedTokens":2539,"tool":"bash"}
On a longer trajectory a single replacement removed 12,472 tokens (12,822 -> 350).
Numbers I could not reproduce, and what I think the gap is
I measured the same task under stock Pi and SoL-Pi, parsing per-turn usage from --mode json.
| Task shape |
Turns |
Token delta |
| Small file, seconds |
4-6 |
-8.1% over 3 pairs (one pair was +0.1%) |
| 5 modules x 12 KB, minutes |
5 |
-21.1% (57,967 -> 45,772) |
README claims 45-49% fewer tokens than Pi. I believe the gap is mostly scope, not a defect:
- Trajectory length. README states the mechanisms are measured over multi-hour trajectories, and explicitly notes shorter benchmarks do not match the research question. My tasks run in seconds to minutes. The delta scales with length in my own data (-8% -> -21%), which is consistent with your thesis.
- Config scope. I enabled 2 of 4 mechanisms. The README figure is the assembled harness with all four.
- Reasoning effort and backend. All your comparisons ran at
xhigh on frontier backends. I ran a non-frontier model at a low thinking level, which likely generates less repeated context to compress.
So this is not a contradiction, but I think the README would set expectations better if the 45-49% were labeled with its preconditions (all four mechanisms, multi-hour trajectories, xhigh).
Actionable findings
1. then_run is not used autonomously — the mechanism is model-opt-in, not harness-forced.
This is the largest practical gap I hit. With SoL-Pi loaded and actionFusion: true, the model still issued a separate edit followed by a separate bash on the first attempt:
--- stock Pi --- bash, edit, bash
--- SoL-Pi --- bash, edit, bash <- then_run absent, zero savings
Action Fusion only fired when I explicitly instructed the model to use the then_run parameter in the same call. Net token change on that run was +14% (8,508 -> 9,914): the longer edit/write schemas cost more, and the saved round-trip never materialized.
Since base-Pi rollouts are the stated motivation, the tool description probably needs to be much more directive (or the fusion offered as a system-prompt hint), otherwise users may see a small net loss on short tasks rather than a gain.
2. Issue #20 (then_run silently no-ops on Pi 0.85.1) is not reproducible on my machine.
I tested Pi 0.85.1 with SoL-Pi loaded, including the exact repro from the report (then_run: {"command": "cat <same-file>", "timeout": 15}):
emitted then_run = {"command":"cat /private/tmp/solpi-bench/calc.js","timeout":15}
result Successfully replaced 1 block(s)...[then_run:succeeded]
export function mean(values) { ... return sum / (values.length); }
The command ran and the output was appended, identical to 0.84.2. I could not reproduce the silent failure either with or without the timeout field. This may be environment-specific (the reporter used npx and a SoL-Pi-only profile); it may be worth asking for their exact invocation, or closing it if it was a local artifact. I am flagging it rather than claiming it is fixed.
3. --no-session produces a hard extension failure rather than degrading.
Extension error (.../src/sol-pi/index.ts): SoL-Pi requires a persistent Pi session directory
This comes from runtime-paths.ts:11. --no-session / --session-dir omission is a legitimate Pi invocation, and a thrown error aborts the extension load. It would be friendlier to disable the archiving mechanisms with one warning and keep the rest of the harness working.
4. There is no per-mechanism ablation, so the 45-49% cannot be attributed.
The README gives one combined figure for four mechanisms. The swarm section already acknowledges this ("It does not by itself isolate which SoL-Pi mechanism caused the observed gain"). Since contributors are invited to improve individual mechanisms, a per-mechanism or leave-one-out table on a held-out subset would make the claim actionable. My own measurement suggests Action Fusion and ObservationPack behave very differently by task length.
5. peerDependencies accepts any Pi version, which is what #11 and #15 report.
All four Pi peer deps are "*". Combined with the finding that the practical compatibility boundary is a moving target (see #20), a floor such as >=0.84.2 would fail loudly at install time instead of at runtime.
Both mechanisms can be silently disabled by other extensions
Worth adding to the list above, because I hit it on a real setup and it took payload-level
instrumentation to diagnose. Neither mechanism warns when it loses its slot.
a. A competing editor tool makes Action Fusion a no-op.
A common third-party extension ships its own editor named str_replace_editor and hides the
built-in edit/write from the model. With SoL-Pi installed and actionFusion: true, the wire
tool list still contains edit, registration succeeds, and the then_run schema is present — but
the model picks str_replace_editor instead, and then_run is silently ignored:
tool_call: str_replace_editor hasThenRun=True <- argument accepted by nobody
tool_call: bash hasThenRun=False
result: Successfully replaced 1 block(s) in calc.js. <- no [then_run:*] marker
So on such a setup Action Fusion costs schema tokens and delivers nothing, with no signal that it
is inert. This is a different case from #20: there the argument is dropped between model and
execution, here the model never chooses the tool SoL-Pi replaced.
b. A third-party setActiveTools() snapshot removes obs_recall.
Another extension in my config calls pi.setActiveTools(snapshot) using a tool list captured at
its own load time. If that extension loads before SoL-Pi, the snapshot predates the
obs_recall registration and the tool is dropped from every provider request for the entire
session. Only packages order changes the outcome:
SoL-Pi first: ["read","bash","edit","write","obs_recall","str_replace_editor"]
other first: ["read","bash","edit","write","str_replace_editor"] <- obs_recall gone
Reordering fixed it. I have filed the root cause against that extension separately, but from
SoL-Pi's side the lesson is that registerTool succeeding does not imply the tool reaches the
model. Since the project's own methodology already includes "Prove mechanism activation" (MV15)
and "Evaluate a mechanism at its exact first firing point" (M8), a lightweight self-check that
reports when a replacement tool is not in the wire payload (or when then_run never fires in a
session) would surface both cases immediately instead of after a benchmark anomaly.
Reproducibility caveat
One trial per condition in my numbers as well; I observed -17.1%, +0.1% and -5.7% across three identical pairs, so short-task variance is large and single-run comparisons in this regime are not reliable. I am reporting the aggregate rather than any single run.
Happy to re-run any of this against a frontier backend at xhigh if that would make the comparison fairer, and to retest #20 on a second machine if useful.
Environment
0.84.2(pinned) and Pi0.85.1(current global), Nodev26.7.0, npm11.19.0, macOS, Apple Siliconmain@d7ecfc089944f0d04b80122a0a9a6ca0d786f3d0, version0.1.0deepseek/deepseek-v4-flashviaopenai-completions(not a frontier model, and notxhigh)PI_CODING_AGENT_DIR. Upstream Pi was not patched.actionFusion: true,observationPack: true,evidencePreservingReducer: false,onlineContextCompact: falseWhat I verified as working
Thanks for the held-out methodology and for shipping a no-Pi-patches extension. The following all passed on the pinned release:
npm ci --ignore-scripts— 289 packagesnpm run typecheck— cleannpm test— 18 files / 139 tests passednpx vitest run tests/all-mechanisms.test.ts— 4/4node scripts/check-pi-compat.mjs— exit 0scripts/check-sol-pi-config.mjs— correctly rejects unknown keys,version != 1, non-boolean flags, and partial config under--require-all-enabled(all exit 1)--offline --approve, no extension load errorBoth local mechanisms produce real, auditable effect:
Action Fusion —
editwiththen_runexecutes and returns one fused observation:Turns dropped 4 -> 3 versus stock Pi on the same task.
ObservationPack — archive and ledger are real.
ledger.jsonl:{"event":"placeholder","sendNumber":3,"originalBytes":11499,"originalTokens":2875,"placeholderTokens":336,"removedTokens":2539,"tool":"bash"}On a longer trajectory a single replacement removed 12,472 tokens (12,822 -> 350).
Numbers I could not reproduce, and what I think the gap is
I measured the same task under stock Pi and SoL-Pi, parsing per-turn
usagefrom--mode json.README claims 45-49% fewer tokens than Pi. I believe the gap is mostly scope, not a defect:
xhighon frontier backends. I ran a non-frontier model at a low thinking level, which likely generates less repeated context to compress.So this is not a contradiction, but I think the README would set expectations better if the 45-49% were labeled with its preconditions (all four mechanisms, multi-hour trajectories,
xhigh).Actionable findings
1.
then_runis not used autonomously — the mechanism is model-opt-in, not harness-forced.This is the largest practical gap I hit. With SoL-Pi loaded and
actionFusion: true, the model still issued a separateeditfollowed by a separatebashon the first attempt:Action Fusion only fired when I explicitly instructed the model to use the
then_runparameter in the same call. Net token change on that run was +14% (8,508 -> 9,914): the longeredit/writeschemas cost more, and the saved round-trip never materialized.Since base-Pi rollouts are the stated motivation, the tool description probably needs to be much more directive (or the fusion offered as a system-prompt hint), otherwise users may see a small net loss on short tasks rather than a gain.
2. Issue #20 (
then_runsilently no-ops on Pi 0.85.1) is not reproducible on my machine.I tested Pi 0.85.1 with SoL-Pi loaded, including the exact repro from the report (
then_run: {"command": "cat <same-file>", "timeout": 15}):The command ran and the output was appended, identical to 0.84.2. I could not reproduce the silent failure either with or without the
timeoutfield. This may be environment-specific (the reporter usednpxand a SoL-Pi-only profile); it may be worth asking for their exact invocation, or closing it if it was a local artifact. I am flagging it rather than claiming it is fixed.3.
--no-sessionproduces a hard extension failure rather than degrading.This comes from
runtime-paths.ts:11.--no-session/--session-diromission is a legitimate Pi invocation, and a thrown error aborts the extension load. It would be friendlier to disable the archiving mechanisms with one warning and keep the rest of the harness working.4. There is no per-mechanism ablation, so the 45-49% cannot be attributed.
The README gives one combined figure for four mechanisms. The swarm section already acknowledges this ("It does not by itself isolate which SoL-Pi mechanism caused the observed gain"). Since contributors are invited to improve individual mechanisms, a per-mechanism or leave-one-out table on a held-out subset would make the claim actionable. My own measurement suggests Action Fusion and ObservationPack behave very differently by task length.
5.
peerDependenciesaccepts any Pi version, which is what #11 and #15 report.All four Pi peer deps are
"*". Combined with the finding that the practical compatibility boundary is a moving target (see #20), a floor such as>=0.84.2would fail loudly at install time instead of at runtime.Both mechanisms can be silently disabled by other extensions
Worth adding to the list above, because I hit it on a real setup and it took payload-level
instrumentation to diagnose. Neither mechanism warns when it loses its slot.
a. A competing editor tool makes Action Fusion a no-op.
A common third-party extension ships its own editor named
str_replace_editorand hides thebuilt-in
edit/writefrom the model. With SoL-Pi installed andactionFusion: true, the wiretool list still contains
edit, registration succeeds, and thethen_runschema is present — butthe model picks
str_replace_editorinstead, andthen_runis silently ignored:So on such a setup Action Fusion costs schema tokens and delivers nothing, with no signal that it
is inert. This is a different case from #20: there the argument is dropped between model and
execution, here the model never chooses the tool SoL-Pi replaced.
b. A third-party
setActiveTools()snapshot removesobs_recall.Another extension in my config calls
pi.setActiveTools(snapshot)using a tool list captured atits own load time. If that extension loads before SoL-Pi, the snapshot predates the
obs_recallregistration and the tool is dropped from every provider request for the entiresession. Only
packagesorder changes the outcome:Reordering fixed it. I have filed the root cause against that extension separately, but from
SoL-Pi's side the lesson is that
registerToolsucceeding does not imply the tool reaches themodel. Since the project's own methodology already includes "Prove mechanism activation" (MV15)
and "Evaluate a mechanism at its exact first firing point" (M8), a lightweight self-check that
reports when a replacement tool is not in the wire payload (or when
then_runnever fires in asession) would surface both cases immediately instead of after a benchmark anomaly.
Reproducibility caveat
One trial per condition in my numbers as well; I observed -17.1%, +0.1% and -5.7% across three identical pairs, so short-task variance is large and single-run comparisons in this regime are not reliable. I am reporting the aggregate rather than any single run.
Happy to re-run any of this against a frontier backend at
xhighif that would make the comparison fairer, and to retest #20 on a second machine if useful.