What's new in v2.3.0
Highlights
pi extension (#122, thanks @jbanety)
- autoresearch now runs in the pi coding agent. The extension ports the Claude hooks to pi events: scout, privacy and dangerous-command blocks, iteration context, dev rules, simplify gate, session init, stop notification and subagent context.
- Every hook fails open and honors the same
AR_DISABLE_*env flags as the Claude hooks. - The 14 autoresearch commands ship as pi prompt templates (
/autoresearch,/autoresearch_debug, ...). The dispatcher is a pi skill (/skill:autoresearch). - Subagent context works with the pi-subagents extension when it is installed, and is skipped when it is not.
- The pi bundle is generated from
.claude/byscripts/transform.sh --pi, like the OpenCode and Codex ports. - Install:
./scripts/install.sh --pi --global, orpi install git:github.com/uditgoenka/autoresearch.
Muse support (#124, thanks @zorrobyte)
- Muse is now a supported harness.
scripts/transform.sh --musegenerates.muse/skills/autoresearchfrom the canonical.claudesource. Commands are merged into the skill directory. Muse has no hooks. scripts/install.sh --museinstalls it. Global installs useMUSE_CONFIG_DIR, thenXDG_CONFIG_HOME, then the default. Local installs use.agents/skills.- New
tests/test-install.shsuite.release.shnow runs it and checks Muse version parity.
Fork-and-flush rounds (#126, thanks @philipk19238)
- When a metric loop stalls inside one family of ideas, autoresearch now forks K fresh-context branches from the best commit (default 4), runs each for a short budget, and keeps the best. This follows "Fork-and-Flush: Escaping Idea Basins in Autoresearch Agents" (Cai et al.).
- Rounds run at 33% and 66% of the iteration budget (50% when N is under 12, every 20 when unbounded). A round also runs after 5 iterations with no
keep; it replaces the next scheduled round. - Branches are random or guided. A random branch gets only the task. A guided branch gets one experiment from a stateless Advisor that reads the results TSV and
git logand never edits files.Guided: Rsets the split; the default 0.5 gives 2 + 2 at K = 4.Guided: 0is plain fork-and-flush. orchestrate.sh verdictreturnsFORK(withship=no) beforePLATEAUwhilefork_rounds_since_progressis under 2. After 2 rounds with no progress it returnsPLATEAU.- Flags:
--no-forkturns rounds off.Forks: Ksets the branch count (use 2 for slow or shared-resource Verify commands).
Behavior-preserving optimization reference (#114, thanks @64andrewwalker)
- New reference for performance goals: latency, throughput, runtime, CPU, memory, allocation, binary size, power, bandwidth and compute cost.
- It separates the working search metric from final acceptance. A
keepmarks a better exploratory result, not proof that behavior survived. - It asks for independent guards that fail on a known-bad change, held-out or adversarial confirmation, comparable provenance, resource limits and rollback.
- Routed from the skill router, the classic loop and the plan command, and copied to the Claude, Codex/Agents and OpenCode mirrors.
Fixes and hardening
Orchestrator
- Goal classification matches keywords at the start of a word. "prefix" is no longer read as "fix", and "address" is no longer read as "add". Compounds such as debug, hotfix, bugfix and rebuild still match.
- A metric target of
0is detected numerically, so0.0and similar forms no longer cause a divide-by-zero. screen-cmdnow refuses:curlorwgetpiped throughsudo,envand similar launchers into a shell or interpreter;- process substitution such as
bash <(curl ...)andsource <(curl ...); sh -c "$(curl ...)"andeval "$(curl ...)";- abbreviated
rmlong options such as--recand--for.
- Every database URL in a command is checked. A safe first URL no longer vouches for a second one.
- A password with
&in it, or a quoted user name, no longer hides the database host from the check. bash --noprofile -c "$(curl ...)"and other interpreter flags before-care refused too.- A goal that starts with "debug" routes to fix-broken. "add debug logging" stays a build goal. "redeploy" routes to ship-ready and "reimplement" to build-feature.
- Database URLs are now read by an allow-list. Only
localhost,127.0.0.1or a plain container name (starting with a letter) count as local. Any other host needs a database name ending in_testor_ci. - URLs the check cannot read safely are refused:
%encoding, several hosts, a backslash, two@signs, quotes inside the URL, an empty host, and thehost,hostaddr,dbnameandservicequery keys. - Destructive commands are caught after
;,&,|,(and backticks, and when the name is quoted or escaped ('rm',\rm). - Brace lists (
{rm,-rf,/}) and$IFSspacing (rm${IFS}-rf${IFS}/) are read the way bash runs them.$'...'quoting is refused. - The
curl, launcher, process-substitution andddchecks also see quoted names, such assudo "bash"andof="/dev/sda". - A quoted or escaped URL scheme (
'postgres'ql://), an empty URL, a?or#before the@, a#anywhere in the URL, and a database name built from$or wildcards are refused. - Variables, command substitution and brace lists can build any command name (
$X,${X}m,r``m,`printf rm`,r{m,}), soscreen-cmdnow refuses them as a whole kind. It reads quotes the way bash does, so escaped quotes and quotes inside quotes cannot hide them. - The command checks also stop at
<and>, sorm>x -rf /andbash<<<"rm -rf /"are seen. - A glob in a command name (
r? -rf /,sudo /bin/r[m]),$"..."strings, a backslash before a newline, control bytes andenv -Sare refused as whole kinds. A script passed tobash -c,sh,su -c,.orevalis screened on its own, and an escaped\$or backtick next to one of them is refused. A glob aftersudooption values (sudo -u root /bin/r?) or afterif,thenanddois caught too. - The
find -delete,chmod -R 000,truncate -s 0and curl-to-shell checks also see a separator right after the command (find / -delete;true).
pi extension
- Ignore patterns treat regex characters literally. Bracket classes still work.
rmlong-option prefixes are blocked, as in the orchestrator.- Quotes in the Windows toast notification are escaped.
- A heredoc body is checked when a shell reads it (
bash <<EOF,cat <<EOF | sh). A quote in the body cannot hide the lines after it. - A heredoc end word the check cannot read safely (split by a backslash-newline, or holding
$, a backtick or a carriage return) no longer hides the commands after it. - A heredoc ends only on a line that equals its end word exactly, and several heredocs on one line end in order.
- A redirect before the command name (
<<EOF rm ...,2>/dev/null rm ...,<>f rm ...) no longer hides the command. The redirect target is still checked by the privacy and scout hooks (<.env cat). &>is checked both the way bash reads it (a redirect, sorm &>/dev/null -rf /is caught) and the way sh reads it (run in the background, then a redirect).- Ignore patterns with a leading
/now match from the project root. install.sh --pi --globalreadsPI_CODING_AGENT_DIR, the variable pi uses.- The pi guardrail tests now run on Windows: temp paths use the
C:/form, and test snippets useimportinstead ofrequire. - Blocked file paths are no longer written to the hook log.
- A subagent started in a subfolder still finds the run's results file.
Upgrade notes
- Claude Code:
claude plugin marketplace update autoresearch && claude plugin update autoresearch@autoresearch - Codex:
npx skills update - pi:
./scripts/install.sh --pi --global, orpi install git:github.com/uditgoenka/autoresearch - Muse:
./scripts/install.sh --muse - Fork-and-flush is on by default for every metric loop. It costs more. Each round runs K sub-agent branches (default 4), each for
max(2, round(0.06 × N))iterations, so one round at K = 4 is about 24% of the loop's iteration budget. With the two scheduled rounds, that is roughly half the budget again, plus any early rounds after 5 iterations with nokeep. Each branch also uses its own worktree. To lower the cost, setForks: 2. To turn it off, add--no-fork. Turn it off for mechanical sweeps, or when one Verify run is slow or uses a shared resource. - Goal classification changed. A goal that relied on a keyword inside a longer word may now route differently.
- Commands that the orchestrator now refuses (remote scripts run through launchers or process substitution) need to be run by hand.
screen-cmdnow refuses some harmless commands to stay on the safe side. A loop that ran them before will now stop withrefuse. Run these by hand:- any backtick, and any
$outside single quotes that is followed by a name, a digit,{,(or a quote. This coversnpm test $FILE,cd "$HOME",echo $(date)andprintf $'a\nb'. A$right before a closing double quote, a space or the line end is fine (grep "ok$" log), and so is anything inside single quotes; - a brace list outside quotes, such as
cp file{,.bak}; - a glob in a command name (
./build-*.sh), a backslash at the end of a line, andenv -S. Globs in arguments (ls *.txt) are fine; - a
$or backtick inside the script given tobash -c,sh -coreval, such asbash -c 'echo $HOME'. When a command runs a shell orevalanywhere, every quoted part is checked as a command, sobash run.sh '*.ts'andbash x | awk '{print $1}'are refused too; - a glob in any word after a launcher such as
sudoornice(nice -n 19 ls *.txt); - a database name with
$,{,},*,[or~in it, even on localhost (postgres://localhost/$DB); - a database URL with
#anywhere in it, or?before the@, even when they are only part of the password; - a database URL with an empty value, or a quoted URL that contains a space.
- any backtick, and any
screen-cmdis extra protection, not a security wall. It matches text patterns, and shell commands can be written in endless ways, so some risky commands will still get past it. Keep reviewing what the loop runs, and keep production credentials out of reach of the agent.- Known limit: a database URL with a dotted user name and
&in the password (for examplepostgres://first.last:p&ss@localhost/app) is refused even on localhost. Run it by hand. - Known limit:
screen-cmdreads the host from the URL only. A host set byPGHOST,PGHOSTADDR,PGSERVICEorpsql -h, or by ahost=connection string, is not checked. It also reads only lower-casepostgres://andpostgresql://, soPOSTGRES://andpostgresql+psycopg://are not checked. - Known limit: the nested-script check knows
sh,bash,zsh,dash,ksh,fish,source,su,.andeval. Other programs that run a command or script for you (ssh,watch,xargs,find -exec,setsid,flock,chroot,csh,tcsh) are not looked into, and neither is text built at run time and piped into a shell (base64 -d x | sh). - Known limit: goal keywords now match only at the start of a word. A goal such as "undocumented API" no longer routes to the document archetype, and "fixture" still reads as "fix".
Contributors
Thank you to:
- @64andrewwalker for the behavior-preserving optimization reference (#114)
- @jbanety for the pi extension (#122)
- @zorrobyte for Muse support (#124)
- @philipk19238 for fork-and-flush rounds (#126)
Full change: v2.2.3...v2.3.0