If you find a security issue in pi-until-done, please report it
privately rather than filing a public issue.
- Email: kiren@fantasymetals.com
- Subject prefix:
[security] pi-until-done — <short description> - Expected response time: within 7 days
Please include:
- The version (
pi-until-doneversion + Pi version + Bun + mise). - A reproducible example or proof of concept.
- The impact you observed and the impact you believe is possible.
- Any logs or session JSONL excerpts that help — but redact secrets.
A coordinated-disclosure release will follow once a fix is ready.
/until-done is a continuation-loop extension. Its core trust assumption
is that the active model is the judge. The extension itself does not
introduce new attack surface beyond what Pi already exposes via its
built-in tools (read, bash, edit, write, grep, find, ls).
What the extension does:
- Persists goal state via
pi.appendEntry(Pi session JSONL only). - Appends a goal reminder to the system prompt via
before_agent_start(never replaces). - Auto-prepends
mise exec --toverifyCommandso all shell calls go through mise's pinned tool versions. - Spawns mise as a subprocess for CI checks (
mise tasks ls --json,mise run <verb>,mise exec -- <cmd>). - Optionally writes
.until-done/tasks.yamland.until-done/distilled.mdinside the project's cwd.
What the extension does NOT do:
- No network calls of its own (only what Pi/the model invoke).
- No credential reads, writes, or transmissions.
- No telemetry, no analytics, no auto-updates.
- No system-prompt replacement (composes only).
- No
pi.setActiveTools(would silently disable user tools — Pi-philosophy violation). - No daemons, no background processes outside an active Pi session.
askBefore[]is the user-defined gate for sensitive commands. The extension'stool_callhook compares eachbashinvocation against this list and triggers actx.ui.confirmdialog (with 30s timeout) before the command runs. On dismiss/timeout, the tool is blocked.- Hard ceiling: turn budget capped at 20000 (with a confirm dialog above
500), regardless of what the model requests. The orthogonal gates —
spin guard, clean-end nudge, CI-failure → block, user input,
/until-done pause, and compaction — are turn-independent. - Any tool the user has not enabled in Pi cannot be invoked by the extension.
When the model reads untrusted input (web pages, third-party files, external APIs), prompt injection is possible against the goal contract. Mitigations baked into the extension:
- The North Star (goal, doneCriteria, verifyCommand, askBefore) is
locked at
until_done_set; replans cannot change it. - The verifiability discipline (injected every turn) refuses
proxy-signal completions and requires quoted
verifyCommandoutput. - The spin-guard blocks the loop when a turn produces no progress signals — preventing models from "agreeing" to stop.
Only the latest minor version of pi-until-done is supported. Update via
pi update pi-until-done or npm install -g pi-until-done@latest.