pi-extensions GitHub

Bounded workflow outcome pilot

node scripts/workflow-eval.mjs --live --output /tmp/pi-workflow-pilot-<unique> opts into real calls to the physical default pi model. Without --live it only prints usage. It copies only that provider's credential into private disposable configuration and deletes the copy after each run; no user settings are changed.

This pilot compares the pre-change verifier prompt at HEAD with the current verifier plus an explicit project recipe reference. It tests a narrow verification intervention, not all extensions or the value of subagents. Four frozen executable CLI verification tasks include good and defective implementations; two are held out from prompt development. Both variants receive the same acceptance criteria and files. Existing shallow tests pass even when an edge case is defective. Independent execution scores the verdict and unchanged fixture, not an LLM judge. These controlled fixtures are not production tasks.

Budget: eight sessions total, six turns/90 seconds per session, 2048 model output tokens per response where the provider honors the model override. Stop scheduling runs once reported cost reaches $2; one in-flight run can exceed that soft cost ceiling. Turn/time/run limits remain hard when cost is unavailable. No optimization or correction retries; only a demonstrated harness defect justifies rerunning. Alternate variant order. Freeze case/prompt hashes before requests. No background watcher or automatic promotion follows the pilot.

Artifacts contain protocol, frozen prompts/cases, real tool events, final outputs, fixture directories, acceptance verdicts, elapsed time and reported token/cost usage. Treat provider cost as an estimate; zero or missing cost is not proof of free usage. Human corrections and rework are unmeasured (null), not zero. One run per case/variant cannot establish statistical improvement or model generality. Inspect failure transcripts before changing prompts; reserve a fresh held-out set for any subsequent optimization. Retain useful checks, delete ineffective instructions, and do not claim improvement from this integration smoke alone.

Lightweight outcome record

For an explicitly chosen workflow experiment, append one manual row per real task to its existing artifact or notes: task/revision, workflow variant, acceptance commands and results, accepted/rejected/unknown outcome, observed human corrections, observed rework, elapsed time and available token/cost data. Use null for observations not collected; do not turn unknown corrections or cost into zero. Keep comparable scope and inspect failure transcripts before changing a rule. No background telemetry or mandatory pilot for ordinary tasks. A green integration test demonstrates wiring, not improved productivity.

Recorded pilot: 2026-10-07

Executed eight real deepseek/deepseek-flash sessions, thinking off. Frozen protocol, hashes, command results and final responses are preserved in workflow-evaluation-results.json; full raw events and fixture Git repositories remain at /tmp/pi-workflow-pilot-20261007-r2 (temporary, not archival).

Variant Correct verdicts Strict accepted runs Total time Reported cost Tokens
Prior verifier 4/4 4/4 26.677 s $0.006501 41,765
Current verifier + recipe 4/4 3/4 35.544 s $0.009309 62,272

Both variants correctly detected both defects, including the held-out defect. There is no observed detection improvement. The candidate used more time/tokens on these tiny tasks. Its held-out good case emitted the correct final answer at turn six, then the harness killed it at the turn boundary. That is a conservative normal-completion failure with cap ambiguity, not a wrong verification verdict. Do not add another live rerun to make the result look better.

The initial setup-only attempt stalled on inherited Git signing before any model call. Fixture commits now disable signing locally. An initial scorer also missed an actual command piped to od; all stored logs were rescored with the same quote-aware command recognizer and original scores retained, with no new calls. The matcher is a conservative heuristic, not proof of arbitrary shell semantics; these recorded accepted invocations were also inspected. It remains deliberately narrow; unsupported command forms require manual evidence review, never an automatic successful score.

Use project recipes where setup or acceptance is easy to miss. This pilot does not justify mandatory elaborate ceremony on tiny tasks, nor a claim that the entire agent system is better. Human correction/rework rates are unmeasured.

Subagent usage report

Which built-in types are worth keeping is a measurement, not a guess. On the machine that has the sessions (they are not in this repo):

node scripts/subagent-usage-report.mjs
node scripts/subagent-usage-report.mjs --json
node scripts/subagent-usage-report.mjs --since 2026-01-01 --limit 50
node scripts/subagent-usage-report.mjs --sessions ~/.pi/agent/sessions

The default directory is ~/.pi/agent/sessions. --since is a UTC date (YYYY-MM-DD or any Date.parse value) and keeps sessions with activity on or after that instant, then drops spawns that started earlier. --limit keeps the newest N of those session files. The script is read-only: it never writes into the sessions directory.

It reads two things the subagents extension already records. Parent sessions are Pi JSONL. Each spawn is a subagent tool call; tokens come from that tool result's usage (totalTokens, otherwise input + output + cacheRead + cacheWrite, the same total as tokensFromUsage). Duration is the wall clock from the assistant message that issued the call to the tool result. usage has no duration field, so this interval includes preflight and triage as well as the child. Jev ledger entries are the custom / jev-decision records askSystemOne appends, with feature: "subagents". Question ids distinguish the three calls: self_contained is preflight, outcome is triage, out_of_scope is scope. Triage stores a choice index, not the label. The index follows the criteria order in triageQuestions(): answered, partial, blocked, off_task.

A fan-out is two or more children that all started before the first of them finished. Calls from one assistant message share a start, so they are a fan-out. Every other spawn is lone sequential. A preflight rejection (Task rejected:) and an isError result are not spawns. A ledger entry whose outcome is not ok contributes no label.

Lossy handoff is an approximate telephone-game signal: after the child returns, and before the next user message, the parent calls read on a path the child also read. Paths are resolved against the session cwd, hashed, and never printed. grep, bash, and a read issued in the same turn as the spawn do not count. The child's reads come from the transcript path on details.transcript (or the transcript: line), usually ~/.pi/agent/subagent-runs/*.jsonl. A missing transcript counts as no handoff, so the rate is a lower bound.

Fold candidates are types with more lone sequential spawns than fan-out spawns, and more partial or blocked labels than answered or off_task. A tie is not enough. Types with no triage labels are not candidates. Built-in names come from packages/subagents/agents/*.md and are listed even at zero; any other type name seen on a spawn is appended.

Output is counts and those definitions only. Prompt text, file contents, file paths and tool arguments are not printed. --json is the same report.