Repository navigation
Releases: DevMortimer/pi-warden
Release list
pi-warden 1.7.0
Added
security.shareLinkParamsnames the query parameters whose value is a share link rather than a credential, so a link the user reuses (a RED post'sxsec_token) stays openable in the tool result instead of coming back as a dead[redacted]URL. Empty by default, user config only, and matched as a whole parameter name, with its case. A credential by construction is still masked inside a listed parameter, and a value that also appears outside the URL is masked everywhere. (Configuration)
pi-warden 1.6.0
Added
- The Token Guardian observer: for each valid
pi-subagents/supervision-evaluate/v1event it makes one Jev request with five questions over allow-listed redacted metrics (the root ID is not sent), and records the answers and the answering model as onesubagenttrace entry. Nothing claims the event, steers, wakes, or holds. The new keysubagent.observerdefaults totrueand needs Jev consent. (Guards)
pi-warden 1.5.0
Added
- The config panel has selectors for mode, judgment backend, widget placement and bar mode, conscience skill mode, and recall tool. Left/right wraps through supported values; Enter saves the chosen field and Esc cancels. Invalid values and custom backends remain intact until a choice is made, and other staged edits keep their existing
ssave behavior. (Configuration)
pi-warden 1.4.0
pi-warden 1.4.0 is the first release since 1.1.1. Versions 1.1.2, 1.2.0, 1.3.0 and 1.3.1 were not released on their own, so their notes are below too.
Heads-up: the new cause-check guard (1.3.0) is on by default. Set cause.enabled to false in your config to turn it off.
1.4.0
Added
- When the session runs in a herdr pane, a warden confirm dialog now reports through herdr's
herdr:blockedchannel while it waits, so the pane's sidebar shows blocked instead of working. Interactive sessions only; no emission on hold-steers or headless runs. (Guards)
1.3.1
Fixed
- The commands that send their own prompt to the agent (
/warden init,/warden rules tune,/warden audit,/warden index) no longer swallow it. Each set its busy flag beforesendUserMessage, and the busy-flag guard on theinputevent saw the command's own prompt (which arrives withsource: "extension") and answered "handled", so no run ever started and the command reported the file (or report, or index) was never created — every time, deterministically. The guard now waits only for operator input (interactive/rpc); warden's own prompt passes and, like any user prompt, invalidates in-flight conscience assessments. - Those commands also no longer report before the run they injected ends. Pi's extension-facing
sendUserMessageis fire-and-forget, so theawait ctx.waitForIdle()that followed it could return before the injected run even flipped the session busy — the command reported while the agent was still working, or its status message was steered into the next run instead of recorded. Each command now waits in two phases: first forbefore_agent_startcarrying the prompt it sent (30 seconds; on a miss — a preflight failure or another extension handling the input — it clears its flag and reports right away instead of blocking operator input), then foragent_endof that run with no cap (pi emits it on an abort too, so Esc still ends the wait), and finally for the host to go idle so the status message is recorded rather than steered.
Tests
- A real-session e2e runs
/warden initthe way Pi does (the shipped entry in a real agent session with a scripted model): the injected prompt reaches the model, the agent's write call lands, and "pi-warden.md created" is recorded only after the run ended. Two unit tests pin the guard (extension input passes while a flag is set, operator input waits) and the wait (the command does not report before the run starts or ends). The session-testwritestub now really writes, relative to the session directory, so the e2e can prove the file on disk.
1.3.0
Added
- The cause-check guard (on by default,
cause.enabled): when the final reply of a run states a likely cause, or asks a person to check something the agent could inspect itself, and no tool result in that run checked it, pi-warden sends the reply back with one follow-up turn: check the cause with its own tools (a query, a log, a file, or a command) and give the evidence, or say plainly that the cause is unverified and why it cannot check it. It is the sibling of the done-check. An offline pre-filter (causePreFilter) fires on causal and hand-off wording, so a reply about results or next steps spends no request; the guard asks Jev whether the reply states a cause or hands off a check, whether the run checked it, and, when the project has an earlier unchecked cause inside the window, which earlier cause the reply repeats. The request carries the task, the final message, the last 40 of the run's tool calls, and up to five earlier redacted cause sentences with their keys and dates. Each unchecked cause is stored per project forcause.windowDays(default 7) as the redacted sentence that states it; a later reply whose cause Jev matches to an earlier one gets a stronger steer that names the earlier date, and a reply that hands a check to a person gets a steer that says so. When the done-check steers the same reply, the cause-check records its decision in the trace and sends no steer, so one reply gets at most one end-of-run steer. The repeat history lives in acausestable in the same owner-only database as the hold log, and every request, stored summary, and trace line passes throughredact().
Docs
docs/guards.mddescribes the new cause-check;docs/configuration.mdlists its keys, widget template, and tokens;docs/data-handling.mdand the consent notice name the cause-check request and its stored repeat history;README.mdlists the guard next to the done-check.eval/reports/2026-10-07-cause-check/measures the offline pre-filter on recorded sessions: the totals, the flagged count, and how many of a 20-reply sample were real unchecked causes.
1.2.0
Added
-
The action guard reads a script a command runs from disk and applies the same pattern floor and ask gate to its body:
bash FILE,./FILE,source FILEand. FILE,npm/pnpm/yarn/bunscripts frompackage.json(withpreNAMEandpostNAME),make TARGETor the default target, andnode/python/python3/ruby/perl/deno run FILE. A body is read only when it resolves, after symlinks, inside the project root or a temp root, as a regular file of at most 64 KB, and one level deep. A body hit keeps the id and severity it has when typed directly and its label names the source ((via cleanup.sh),(via npm run clean));action.exemptRulesand usercommandRulesapply to it; a body hit makes the ask gate ask withruns a script with <shape>; and the body lines that hit ride the request to Jev asscript_lines, redacted and bounded to five lines and 600 characters. -
/warden statusshows the build that runs: the pi-warden version, the checkout commit when the package is a git tree, thedist/extension.jsbuild time, and the loaded pi-typesafe version. Session start warns once when asrc/file is newer than the build (pi-warden runs an old build: run npm run build) and once when the loaded pi-typesafe version is outside the range inpackage.json.
Changed
- The done-check nudge names one check command instead of "whatever exists": the last check that passed earlier in this session in this project, else the
checkthentestscript of the project'spackage.jsonrun with the package manager its lock file names (pnpm-lock.yaml,yarn.lock,bun.lockborbun.lock, else npm), else the sameMakefiletargets; with none of those it keeps the generic ask. The UI nudge names the last local URL a tool result printed this session (http://localhost:PORT,127.0.0.1,[::1]) when there is one. - Done-check UI proof now counts only what shows the page to the agent: a successful tool result that contains an image, a page text snapshot (
agent-browser snapshot,agent-browser get text, the MCPtake_snapshottool), a browser or device test run (playwright test,flutter testwithintegration_testor golden tests), or areadof an image file. A screenshot command that only writes a file (agent-browser screenshot PATH,idb screenshot,xcrun simctl io … screenshot,chrome --headless --screenshot),agent-browseropen/close/click/fill/set/wait/eval, and MCP navigation tools no longer count; a saved screenshot counts once something reads it. Thedone.visualToolsdefaults match, and every config key still works. - pi-typesafe
^0.9.1(was^0.9.0). npm run checkbuilds before it tests, so the offline suite exercises a freshdist/(the entry Pi ships) instead of a stale one.
Fixed
- The done-check counts a shell command as a check only when a check runner starts one of its shell segments, after
cd DIR, environment assignments, andtimeout/time/env/npx/pnpm exec/bunx/yarn/uv run/poetry run/python -mwrappers (a wrapper is stripped only when what follows does not start a runner, soyarn testandyarn run lintare checks). A runner name in an argument (grep -n jest package.json,which eslint,npm view vitest version) no longer counts as a check. - A check run counts as proof only when it really ran and its output agrees: a failure summary is a failed check even with exit code 0, and a visible failure stays a failed check also with a passing summary; a summary that reports zero tests (
Tests: 0 total,[no tests to run], and similar) is never a check, unless a line of the output shows tests did run (cargo doc-tests after real results, a package ago testfilter skipped); and when the shell can hide the exit code of any runner segment (a pipe right after its segment withoutset -o pipefail, or a||,;, or newline with more commands anywhere after it) the exit code is no proof — with no runner summary the run is not a check at all. Each run that names a runner but does not count gets one trace-only detail with the reason and no command; the reason names the word after the hiding separator only when it is a bare command name. - The done-check reads more runner summaries as proof: vitest, pytest without the
===frame (-q), mypy, ruff (check, format, and--fix), black, prettier, biome, tsc pretty output, eslint, bun, mocha, playwright, flutter, deno, and cargo build, check and clippy; and the generic wrapper failure lines (make: *** … Error N,npm error Lifecycle script … failed,npm ERR! code ELIFECYCLE, pnpm and yarnCommand failed with exit code N). The generic lines decide only when a runner starts the command, so a failednpm installis not a failed check. A failure marker anywhere in the tail wins over a passing one (black and ruff formatN files would be reformattedbesideN files would be left unchanged., any goFAILline, any cargotest result: FAILED.after anok, pytest2 passed, 1 error, an indented orpkg:test:-prefixed vitest summary), a generic failure line overrides a passing summary in the same output, and the `Finishe...
pi-warden 1.1.1
1.0.0 was the last release on npm. 1.0.1 and 1.1.0 were not published on their own, so this release also ships their changes.
1.1.1
Fixed
scripts/live-smoke.mjsandscripts/security-cases.mjsno longer crash when a verdict has no off-task answer, which is now the usual case: the acting request does not askoff_task, only the trace sample does. The missing value prints as-.- The three off-task cases in
scripts/security-cases.mjs(side comment, take over previous work, new instruction overrides history) passtraceSample: 1, so every call asks the off-task question and the cases test its answer again.
1.1.0
Added
"typesafeBackend": "liquid"sends judgments to Liquid AI (api.liquid.ai, key inLIQUID_API_KEY, default modeld1:free) through pi-typesafe 0.9.0.d1:freeis free but slow (median about 14 seconds a request against the 5-second defaulttimeoutMs), and the paidd1counts the state once per question, so a 7-question action request costs several times what it costs on Jev; see docs/configuration.md.
Changed
- pi-typesafe
^0.9.0(was^0.8.0).
1.0.1
Fixed
- The run-end rules check no longer judges files that a
git pullbrought in when the pulled commit was made during the run, such as a squash commit from a pull request merged on the hosting service: a commit counts as brought by git when this worktree's HEAD reflog shows that the checkout did not create it, whatever its date. The commit-date rule stays as the fallback when the reflog is off.
pi-warden 1.0.0
pi-warden 1.0.0 is the first stable release. From 1.0 it follows semver for the surface listed under Versioning in the README.
Upgrading from 0.74.1
0.74.1 was the last release on npm. docs/upgrading.md lists what changes for you: two removed settings (now named in a config warning), project files that can only make settings stricter, and the new defaults.
What changed since 0.74.1
- Fixed: a freeze in the credential check. In 0.74.1 the check could take seconds on one long string, and longer as the string grew. Masking also no longer treats a code expression after a credential key as a secret. (#154)
- A cheaper action guard. Jev is asked only when its answer can change what the agent sees, with a smaller request: 48.9% fewer requests and 68.1% fewer input tokens on recorded sessions, while 96.7% of the calls whose answer changed what the agent saw are still asked. (#153)
- Rules at turn start. Before each new user message, one background request names the project rules that apply to it, and the agent gets them at the end of a turn that continues. A prompt no longer waits for Jev. (#152, #157)
- Approval on demand. After a hold, the approval question is asked only for a held call (90.0 to 0.7 per 1,000 judged calls), with the agent's own words of that turn as context. A reply releases a held call only when it approves it and points at that action: wrong releases fell from 45 to 1 in the measured runs. (#160, #161)
- Conscience (beta, off by default). It ranks candidates on the machine before it asks Jev: requests per prompt fell from 2 to 1. (#155)
rmprecision. Removing a scratch directory that the same command created withmktempis no longer held. Home and project paths, other variables, and data moved into a temp path stay held. (#148)- A smaller hold database. A 52,362-row copy shrank from 285.9 MiB to 41.6 MiB, and records of calls that were not held are pruned after 90 days. (#149)
- Fewer false alarms. The run-end rules check skips changes that a pull or merge brought in, the done-check ignores files outside the project, and
/warden testsends one request. (#157) - Removed:
conscience.loadThresholdandlearning.adaptiveThresholds. A config that still sets them loads and names each one in a warning. (#163)
What did not ship is recorded too: working-memory pruning, stale-result stubs, and a hybrid compaction each failed a measured gate. The numbers are in the Calibration section of docs/guards.md.
Full detail, release by release: CHANGELOG.md, sections 0.75.0 to 1.0.0.
v0.80.0
Changed
- Rule values are never silently weakened. Every rule kind reads
denyandblockas the same value. An unknownseverityin a command rule, or an unknownactionin a path or arming rule, used to fall back to the weakest level (warn,note, or dropping the arming rule); it now applies atconfirm(a deny-list rule staysdeny), and a config warning names the rule, the value, and the valid values. - Arming durations: a number in
arms.foris milliseconds and a string without a unit is minutes, as before; a string also takesms,s,m, orhwith decimals ("1.5h") in every code path. A config warning names a rule that arms for under one second and a string with no unit. - A project file may make the action guard and security stricter, never weaker. It can no longer set
enabled,action.enabled, orsecurity.enabledtofalse, raiseaction.irreversible.warn,action.irreversible.confirm, orsecurity.thresholdabove the user's value, remove a tool fromaction.tools(it may add one), or setaction.failOpentotrueover the user'sfalse. Each ignored value gives one config warning. Other guards stay tunable both ways from a project file. - Config warnings: a value pi-warden cannot apply as written is shown once when a session starts and again in
/warden status. action.shouldProceed.holdis renamedaction.shouldProceed.threshold; it never held a call. The old name is still read through 1.x and is deprecated.- An arming rule with no
actionis still ignored, and now gives a config warning naming the rule. - Removed the settings nothing read:
learning.adaptiveThresholds,learning.minHoldsForAdaptive,learning.adaptationRate, andconscience.loadThreshold. A config file that still sets them loads as before.
Fixed
learning.retentionDays: 0keeps every hold record, as documented; it used to become 365.- The capability index files that
/warden indexwrites are owner-only, as documented: the folders are created0700and each file is written0600through an atomic replace; before, they had the default permissions.
Docs
docs/configuration.mdlists the project-file keys that only get stricter, documentswidget.barModeandstuck.churnThreshold, and the lab profile now turns the security guard off in the user file.docs/commands.mdhas a row for/warden enableand shows/warden init [--force].docs/data-handling.mdlistssteer-stats.json, the capability index files, and the migration notice marker.docs/extension-authors.mdnames exactly the exports semver covers; every other export is internal.README.mdhas a Versioning section that says what semver covers from 1.0.CONTRIBUTING.mdgives the hold threshold as 0.9.
v0.79.1
Fixed
- The hold log is now written to a temporary file and renamed into place, so a reader always sees a whole file. Before, a reader during an in-place rewrite could get a line cut short, which made an extension test fail now and then.
Tests
npm testclears everyPI_*variable and judge key and gives each test process its own agent directory, so a run in a shell inside Pi no longer writes trace lines or steer stats to the developer's directories; the host test builds into a temporary directory instead ofdist/, and no test file shares a fixed temporary path.
v0.79.0
Changed
warden_rememberrecords a lesson with no user correction or failure before it, for example a fact about the project that later sessions need; the rules for a lesson are unchanged, and it still reaches later sessions only once recorded in a second session or said by the user.
v0.78.1
Docs
docs/hero.pngis now rendered byscripts/render-hero.mjs(npm run hero), and every number in it comes from the 2026-09-24 field report (759 sessions); the install line readspi install npm:pi-warden.