Repository navigation
refactor(runner): drop the Devin, agy and dsh repository refusals (#204) - #215
Conversation
Read-only means the read-only settings pstack passes to each CLI (#203). Devin, agy and dsh lanes now run in any repository; the runner no longer refuses .devin/, .agents/ and its siblings, or a cwd .env, and the project-config walk and home-directory rule go with them. The catalog notes say what each CLI loads from a repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge Protections🟢 All 2 merge protections satisfied — ready to merge. Show 2 satisfied protections🟢 Queue ready pull requestsAutomatically queue non-draft pull requests targeting main after verify, Unfret, and live-gate pass on the head and every review thread is resolved.
🟢 🚦 Auto-queueWhen all merge protections are satisfied and these conditions match, this pull request will be queued automatically.
|
Live evidence: Open Pstack
|
|
[Medium impact] The PR appears safe to merge under the documented repository-configuration policy. SummaryRemoves the repository and home-directory refusals for Devin, agy, and dsh.
ericlitman explicitly accepts repository hooks, MCP servers, agy agent replacement, dsh Source review only; tests and live lanes were not rerun. Reviews (1) · Last reviewed commit: "refactor(runner): drop the Devin, agy an..." · Reviewed by Greptile |
✅ No blocking findingsWalkthroughThis PR removes the runner's last repository-based
Advisories (1)
Since the last review
Details
Reviewed the whole pull request. @unfret review · @unfret status · @unfret help |
There was a problem hiding this comment.
🛑 3 blocking findings
🔵 Low · agy note omits the ancestor and home-directory walk these lanes now reach
🔵 Low · Devin note omits the ancestor and home-directory walk these lanes now reach
🔵 Low · Reference claims every provider's notes disclose repository config loading
Check
…oviders whose notes cover it (#204) Unfret round 1 on #215. The agy and Devin notes now say the CLI loads its config directories from the cwd and each parent up to the git root, or up to / outside a repository, so a lane under the home directory outside a repository also loads the home directory's own. docs/reference.md names the providers whose catalog notes describe the configuration they load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live evidence: Open Pstack
|
Merge Queue Status
This pull request spent 8 seconds in the queue, including 1 second running CI. Required conditions to merge
|
* feat(registry): add GPT-6 Luna, Sonnet and the exact Opus 5.5 pin (ericlitman#54) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: describe every Claude family's native agents and the exact pin (ericlitman#54) docs/reference.md and the README described the native agents as Fable and Opus only, using the rolling alias. Each Claude family in the catalog now ships agents, and a registered exact pin keeps its own model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only Devin provider with SWE-2 and SWE-1.6 (ericlitman#69) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): prove the new families' probe routes and the Codex mirror, and widen the pin scan (ericlitman#54) The new-families setup case checked only the rewritten sheet, so a run that probed Sonnet or the pin through the rolling Opus agent still passed. It now requires the Claude Agent calls to pstack-opus-5-5-max and pstack-sonnet-max, and a complete runner receipt for each external probe in its own empty probes directory. The three setup cases that remove Codex's AGENTS.md mirror now check that setup wrote it back as the sheet's exact bytes. The Claude pin scan covers Sonnet, and it removes only the registered pin's token before matching, so another pin on the same line still fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): let a model-sheet setting give Codex writer lanes full access (ericlitman#80) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): prove the new native agents directly and check the Codex mirror exactly (ericlitman#54) Step back on head 2's probe check, which inferred setup's internal probes from transcripts and kept growing variants (nested or extensionless receipts, wrong effort, undrained background agents). It is gone. A catalog case on Claude now dispatches pstack-sonnet-max and pstack-opus-5-5-max, and each child writes a fixture nonce it read, with its tool calls recorded under its Agent call. The Codex mirror check follows setup's contract exactly: one marker pair, and the sheet's exact bytes after the begin marker's newline. The pin scan's exemption ends only at a character that cannot continue a model ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): test Sonnet migration in setup, reject native-agent model overrides, tighten the mirror and pin scans (ericlitman#54) The new-families setup case now feeds a versioned Sonnet, which this PR's setup migration must write as claude:sonnet. The native-agents case rejects an Agent call that overrides the model. The mirror check counts a stray begin marker even without its newline, and the second pin scan no longer depends on the file path having no colon. ericlitman#54's acceptance criteria are corrected: setup's probe routes are not this PR's change, and the new routes are proven by the native-agents and runner cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): refuse Devin lanes in repositories with .devin/ config, and widen setup's writer roles (ericlitman#69) A Devin lane bypasses workspace trust, and Devin loads a project's .devin/config.json hooks and permissions and its .devin/mcp_config.json servers, with no key to turn them off. The runner now refuses a Devin lane whose cwd or any parent up to the git root holds .devin/, through an adapter-declared projectConfigDir checked before launch. An interruption is a cancellation only when Devin writes it as a system step. Setup refuses a read-only provider for every writer role: the four playbook roles, hardest tasks, arena runners and swarm workers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(setup): refuse read-only providers for architect runners, prove the refusal live, and guard only .devin directories (ericlitman#69) Architect runs Arena with its own runners, which write to their own output locations, so setup's writer roles include architect runners. A new setup case assigns bug-fix to Devin and requires setup's refusal with no configuration change, so the live gate tests the new rule. The project-config guard refuses only a .devin directory; a plain file holds no Devin config. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): quote the browser case's paths, and prove setup and parents keep writers bounded unless opted in (ericlitman#80) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): dispatch a bounded Codex writer live, control configure's setting, and parse quoted paths with newlines (ericlitman#80) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * build: add root check scripts so Unfret registers and shares them (ericlitman#185) Unfret registers one check per root package.json script and runs it with the packageManager named there. open-pstack had no root package.json, so each focal review lane ran bun install and the tests through run_command. The root scripts are CI's verify steps: test, typecheck and static. CI now calls them, so the reviewers and CI run one definition, and setup-bun reads the Bun version from packageManager instead of a second pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * verify: map the root package.json and ci.yml to project proof (ericlitman#185) Both paths were unmapped, so a PR touching either failed closed before any install. CI now runs the root scripts, which include the verifier's own tests, so both are verifier enforcement like tests/skill-collision-repro.sh: a change to either selects project-skill and cannot pass as no runtime change. The fail-closed case for unregistered workflows keeps a new workflow path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * verify: give the unit tests a real account when USER and LOGNAME are unset (ericlitman#185) Unfret runs a registered check with only PATH, HOME, TMPDIR and locale variables, so run_check static failed 23 verifier tests on isolatedEnv's "Real USER and LOGNAME are required". The test script now supplies the account from id -un when the environment has none. The live verifier's guard is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.9.0 with Luna, Sonnet, the Opus 5.5 pin, Devin and Codex full access (ericlitman#190) Bumps the manifests, marketplace entry and version lines to 1.9.0 and adds the 1.9.0 CHANGES.md section, written from PRs ericlitman#182 (ericlitman#54), ericlitman#183 (ericlitman#69) and ericlitman#184 (ericlitman#80), with one line for PR ericlitman#186 (ericlitman#185). The Cursor sync point stays at pstack 0.15.20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(verify): keep fixture git out of the host's global config (ericlitman#172) The host's global git config routes trace2 events to the git-ai daemon, which writes .git/ai and refs/notes/ai into each fixture repository after the git command exits. In provenance.test.ts that write recreated the fixture root after the test renamed it, so the symlink at line 132 failed with EEXIST. Fixture git calls in the provenance, harness and publisher tests now run with GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_NOSYSTEM=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * skills: import in-your-own-words and sharpen from Cursor pstack 0.15.25 (ericlitman#191, ericlitman#187) Upstream added two typed-only skills after the 0.15.20 sync point: in-your-own-words (7d8d909, reworded in dbf4981) and sharpen (79afd75). Both are verbatim at 0.15.25 and keep disable-model-invocation, like the port's other typed-only skills. This commit carries soulmachine's PR ericlitman#188 as written: the two skills, their poteto-help rows, the typed-only list, the recipes, the README and reference rows, and the verifier feature registry entries. Co-authored-by: soulmachine <soulmachine@gmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * sync: port Cursor pstack 0.15.21-0.15.25 skill content (ericlitman#191) Applies the 17 upstream pstack commits from 1b6d44f to 99743e9 through scripts/upstream-audit.py and scripts/upstream-merge.py (11 verbatim, 11 clean merges, 28 hand-resolved, 3 unmapped and excluded). - poteto-mode takes ce649c0's "Match the model to the job" rule as upstream wrote it, adapted to the port's descriptors: the starting level is the role's configured effort, an unlisted effort moves to the row's nearest listed one, a configured ultra stays, and the speed sentences go because the port has no speed selector. Every routed skill and playbook points at the rule. provider-dispatch.md says the parent may move the effort per spawn and a child never does. - e5136d8's restated principles replace the port's local corrections to test-behavior-not-implementation, attack-the-premise and correct step 3. - Shipping keeps its nine landing steps and takes upstream's new rules and reasons. Autopilot-full takes upstream's seven steps with the port's guarded rebase and push in step 2, its step 5 merge prep, and the affirmative-failure stuck rule. Autopilot-stack takes upstream's four steps with the fork and topology rules folded into step 2. The landing invariants follow the moved text. - orch frontier reads the PR base chain instead of Graphite; watch-pr treats an owner-approval Code Review Gate as the gate; worktree-audit reads Origin PRs; ketchup, swarm, interrogate, the principles, and poteto-agent take upstream's cuts with the port's substitutions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: sync Cursor pstack 0.15.25 as Open Pstack 1.10.0 (ericlitman#191) Records the 0.15.25 sync point (99743e9) in UPSTREAM.md, NOTICE.md, README.md and docs/reference.md, sets 1.10.0 in the three manifests, and adds the 1.10.0 CHANGES section. UPSTREAM.md retires the 00b14f1 test-principle and 9511e60 correct exclusions, which e5136d8 supersedes; rewrites the 23e4138 trunk-move exclusion for ce649c0's revision; extends the expected-runtime and family-fallback exclusions to ce649c0; records the Cursor manifest, docs/guide and poteto-agent path-search exclusions; and adds the ericlitman#191 ledger entry for the landing playbooks and the per-spawn effort rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): let adapters set run-owned environment and lane config (ericlitman#68, ericlitman#159, ericlitman#158, ericlitman#37) The next four providers need values the contract cannot express: OpenCode and Amp turn off host context only through environment variables, dsh carries the model and effort in a per-lane config file, agy takes its prompt as one JSON line and needs its agent file under a subdirectory, and agy and Amp refuse more than one project config path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only OpenCode provider with DeepSeek V4.1 Flash (ericlitman#68) Add the opencode adapter and the deepseek-v4.1-flash-free family (opencode/deepseek-v4.1-flash-free on OpenCode Zen, efforts low, high and max, default max). The OpenCode 1.19.1 captures changed the original request: - No bounded writer. OpenCode has no OS sandbox, and a shell write escaped the cwd with external_directory denied, so the adapter supports only read-only. A run-owned opencode.json denies every tool except read, glob, grep, list and todowrite. - Provider keys are not passed. The child environment is the base allowlist plus run-owned values, with no OPENCODE_* variable from the parent (OPENCODE_PERMISSION turned bash and edit back on) and no OPENROUTER_API_KEY. A lane uses OpenCode's stored logins or a free Zen model. - Project config is off by environment: XDG_CONFIG_HOME and OPENCODE_CONFIG point at the lane's provider directory, and OPENCODE_DISABLE_PROJECT_CONFIG, _CLAUDE_CODE, _EXTERNAL_SKILLS and _AUTOUPDATE are set. A live lane showed OpenCode still imports .opencode/plugins/*.js, running its top-level code, with --pure and the disable switch, so the runner refuses a cwd holding .opencode/. - Pinned-argv proof. No JSON event names the served model. The preflight is `opencode models <provider>`. The lane passes --title so OpenCode makes no second model call, and --print-logs --log-level ERROR so an unknown model's cause reaches stderr. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only DeepSeek Harness (dsh) provider (ericlitman#159) Adds the dsh adapter and the deepseek-flash and deepseek-v4-pro families (efforts low, high, max; default max). What the dsh 0.2.0-rc.2 captures changed in the design: - Model and effort are config, not flags. Each lane gets a run-owned --patch file that pins agent-default-model, a read-only sandbox-policy with the lane's cwd, approval ask (which overrides DSH_PERMISSION_MODE), and turns off rules, skills, web, subagent and workflow tools, the title call, the plugin inventory and the session-log upload. - dsh has no status command. The preflight is a turn against a closed loopback port with retries off: TRANSPORT means a key is stored or exported (not validated), MISSING_CREDENTIAL is unauthenticated. - dsh reports no served model, so the proof is the pinned argv and patch. - SIGTERM exits 0 with a partial final and no turn_end, so a lane is complete only after a completed turn_end; exit 0 without one is never complete. - Read-only only for now: the Seatbelt workspace-write writer waits for a writer route in the live gate. DeepSeek's real unknown-model refusal is matched as unavailable-model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only Amp provider with DeepSeek V4.1 Flash (ericlitman#158) Add the Amp adapter and its first family, amp-deepseek-v4.1-flash, from the 2026-10-15 Amp CLI captures: - The model is an official Amp agent mode from Amp's own official-modes plugin, which Amp serves to every user. The mode carries the effort, so the family maps its one effort to the mode name. - The preflight is `amp usage` without a terminal, because other logged-out Amp commands can start a browser device login on their own. It records a fixed summary, because the output holds the account email and credits. - Failed and cancelled turns can exit 0, so the stream's result event decides: is_error with the SIGINT/SIGTERM text is cancelled, any other is_error is child-failed with its error text. - A cwd .amp overrides the run-owned settings and runs plugin code at startup, so the runner refuses a workspace that holds it. - The stream never names the model, so the proof is the pinned mode in the argv. The thread export's served IDs are hosting-specific and are not used. - Amp has no sandbox and a shell write escaped the cwd, so there is no bounded writer: the lane is read-only, with a run-owned settings file that enables only Read and rejects every other tool, and AMP_IGNORE_GUIDANCE_FILES=* in an allowlisted environment. The adapter suite now checks that argv carries the effort's CLI model ID anywhere, not only after --model, because Amp selects the mode with -m. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only Antigravity (agy) provider with Gemini 3.8 Flash (ericlitman#37) Adds the agy adapter and the gemini-3.8-flash family (low, medium, high; default high). The agy captures changed the design from ericlitman#37: - Gemini 3.7 Flash is unavailable: `agy models` does not list it for this account. The family registers Gemini 3.8 Flash explicitly and no 3.7 request maps to it. - The prompt goes to stdin as one stream-json line, {"event":"user","message":{"role":"user","content":...}}, through the stdinEnvelope hook; agy has no prompt-file flag. - Each lane writes a run-owned agent file, .agents/agents/pstack-read-only.md, in its private provider directory and runs --add-dir <dir> --agent pstack-read-only. It declares only view_file, no MCP servers and no skills, so web search, subagents, schedule, send_message and the browser are gone. A missing file fails closed with "unknown agent". - The runner refuses a cwd whose path up to the git root holds .agents, .agent, _agents or _agent: agy runs their hooks and MCP servers with no trust check. - An exit-0 result with an empty response and denied_actions is child-failed. An "interrupted" result is cancelled; "invalid model selection" is unavailable-model. - agy never reports the served model, so the proof is the pinned argv. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): refuse a dsh other than the measured 0.2.0-rc.2 (ericlitman#159) dsh 0.2.0-rc.2 ignores a --patch row it does not have, so a later dsh that renamed the sandbox or approval row would run a read-only lane under its default workspace-write sandbox without an error. The runner now checks `dsh --version` before the preflight and refuses any other version until the adapter is measured against it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add a read-only Cursor CLI provider with Composer 2.5 and Gemini 3.7 Flash (ericlitman#71) The Cursor captures changed the design in these ways: - The executable is `cursor-agent`. Cursor also installs `agent`, which resolved to Grok's CLI on the measured host and gave the empty status in ericlitman#94. - The preflight is `cursor-agent models`, not `status`: `status` reports a stored login as authenticated while every model call fails, and it ignores CURSOR_API_KEY. The lane's CLI model ID must start a listed line. Exit 1 with `Error: Authentication required` is unauthenticated; any other output, including empty output, is inconclusive, never unauthenticated (ericlitman#94). - Each lane sets CURSOR_CONFIG_DIR to its private provider directory and writes a cli-config.json there that denies Write(**), Shell(*) and Mcp(*:*), with approvalMode allowlist, the sandbox on and web approvals off. Without it every -p run rewrites ~/.cursor/cli-config.json. The allowlist adds only CURSOR_API_KEY and CURSOR_AUTH_TOKEN. - The runner refuses a cwd holding .cursor/, .claude/settings.json or .claude/settings.local.json up to the git root: a project .cursor/cli.json replaces the deny list, and those hooks run. - The reply is the last assistant event's text, because the result field joins every assistant text segment. - The proof is the pinned argv: the stream names only a display label. - Read-only only: `--mode ask --sandbox enabled --trust` refused every edit and shell request, and no mode is a bounded writer. - `Cannot use this model:` is unavailable-model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): keep home config out of read-only lanes (ericlitman#68, ericlitman#37, ericlitman#158, ericlitman#71) Unfret round 1 on ericlitman#196. OpenCode 1.19.1 merged ~/.opencode/opencode.json after the run-owned lockdown and imported ~/.opencode/plugins, so a home config allowing bash and edit let a read-only lane write files. The adapter now sets OPENCODE_TEST_HOME to the lane's sidecar directory, which is where OpenCode looks for the home .opencode/; OPENCODE_CONFIG_CONTENT and OPENCODE_CONFIG_DIR did not win over the home config. The project-config walk now stops below the home directory, so a lane no longer refuses on the user's own ~/.cursor/ or ~/.claude/settings.json; it still stops at the git root and at /. A file where a parent directory should be (a plain file named .claude) reads as absent instead of throwing ENOTDIR. agy's .agents, .agent, _agents and _agent and Amp's .amp match only directories. An OpenCode text event with empty text no longer counts as a reply: the joined reply must be non-empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): pin every dsh sandbox and approval row in the lane patch (ericlitman#159) A dsh user layer applies before the adapter's --patch, and the patch wins only for rows it names. It named sandbox-policy and approval, so a user layer could still disable bash-sandbox, fs-sandbox or sandbox, or widen the read-only preset. The patch now pins each of those rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): run dsh lanes on a run-owned dsh home; fail agy turns that end on a denial (ericlitman#159, ericlitman#37) Unfret round 2 on ericlitman#196. The dsh user layer composes under the lane's --patch and could redirect inference and credentials, change the preflight's provider route and move the file sandbox's cwd. Each lane now uses its own DSH_HOME and reads the stored login in place, so no user layer loads, and the row pins that defended against it are gone. An agy turn that ended on a denied tool is child-failed even with a preamble. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): refuse a dsh lane whose cwd holds .env; resolve DSH_HOME as dsh does (ericlitman#159) Unfret round 3 on ericlitman#196. dsh loads the invoking directory's .env into bash's environment at boot, so a repository could set GIT_CONFIG_PARAMETERS and run its own script from a read-only lane. The runner now refuses a dsh lane whose cwd holds .env. The credentials path now expands ~ and ignores a blank DSH_HOME, as dsh does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): refuse lanes whose project-config walk would reach the home directory (ericlitman#68, ericlitman#159, ericlitman#158, ericlitman#37, ericlitman#71) Unfret round 4 on ericlitman#196. Round 1 stopped the runner's walk below the home directory, but the CLIs' own walks reach it when no git root stops them: OpenCode then loads ~/.opencode plugins, and a dsh lane whose cwd is the home loads ~/.env. A lane for a provider with project config now runs under the home directory only inside a git repository rooted below it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(runner): refuse an OpenCode lane whose effective permissions exceed the lockdown (ericlitman#68, ericlitman#159) Unfret round 5 on ericlitman#196. OpenCode merges a managed config after the run-owned one, the third layer to override the read-only lockdown. The runner now reads OpenCode's effective permissions with the lane's environment before launch and refuses the lane if anything beyond reading is allowed, whichever layer set it. The check generalizes dsh's version pin into one pre-launch guard per adapter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(runner): move OpenCode, Amp and Cursor out of this PR (ericlitman#68, ericlitman#158, ericlitman#71) Eric split ericlitman#196 after five review rounds. It keeps the runner contract changes plus the dsh and Antigravity adapters. OpenCode, Amp and Cursor return in their own PRs with more containment work: OpenCode's account and organization config, Amp's managed settings and plugins, and Cursor's npx language-server worker. Their last versions are in this branch's history at 08556cd. The verifier changes that only they needed are reverted, so this PR no longer changes the verifier. The directory-or-file entry form and its ENOTDIR handling leave with Cursor, the only adapter that used them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(runner): compare config-carried effort line by line (ericlitman#159) Unfret round 6 on ericlitman#196. The adapter suite's default-effort check searched the whole dsh patch for "high", so a DSH_HOME such as /tmp/high-dsh made the credentials path fail it. The check now requires exactly one added line carrying the effort between the default and high configs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(runner): check dsh's default effort on its own line (ericlitman#159) Unfret round 7 on ericlitman#196. The default-effort assertion searched the whole patch for "reasoningEffort", so a DSH_HOME such as /tmp/reasoningEffort-dsh failed it through the credentials path. It now matches only the setting's own line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.11.0 with the DeepSeek Harness and Antigravity providers (ericlitman#198) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * verify: enforce live-gate feature selection (ericlitman#200) verify.sh run now refuses a named feature outside the PR's classified reach, prints the planned session count before any install, and refuses more than 12 sessions without --wide "<reason>", which the evidence comment records. A manifest change that only bumps the version reaches hook:startup in that manifest's harness. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add OpenCode as a read-only external provider (ericlitman#68) Restores the OpenCode adapter from 08556cd. Before the authentication preflight, the runner now reads OpenCode's merged configuration with `opencode debug config --pure` under the lane's environment and refuses the lane unless it equals the run-owned read-only lockdown, so a managed, remote, home or project layer cannot add MCP servers, LSP commands, plugins, provider routing or agent changes. The verifier's route patterns accept OpenCode's `/` model IDs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(review): read-only means pstack's own CLI settings, with no refusals for the operator's setup (ericlitman#203) Eric's rule, 2026-10-16: a read-only runner lane means the read-only settings pstack passes to the provider CLI. The operator's host, account, repository and organization configuration applies as they set it up; the runner adds no refusal, guard or account check because of it, and the catalog notes disclose what it can do. A failure that needs such configuration to widen a lane is out of scope for review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(runner): drop OpenCode's pre-launch guard and .opencode/ refusal (ericlitman#68) Read-only means the read-only settings pstack passes to OpenCode (ericlitman#203). OpenCode lanes no longer refuse a repository holding .opencode/ or a host whose merged configuration differs from the lockdown; the guard's tests and recorded fixtures go with it (approved by Eric, 2026-10-16). The catalog notes say what managed, remote, stored-login and repository configuration still load and what each was measured to do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.12.0 with the OpenCode provider (ericlitman#206) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add Amp as a read-only external provider (ericlitman#158) Restores the Amp adapter from 08556cd. A lane runs Amp's official deepseek-v4.1-flash mode with a run-owned settings file that enables only Read, private threads and ignored guidance files. Under ericlitman#203, it runs in any repository; the catalog notes say what plugins and managed, workspace and repository settings still load and what each was measured to do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.13.0 with the Amp provider (ericlitman#209) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runner): add Cursor CLI as a read-only external provider (ericlitman#71) Restores the Cursor adapter from 08556cd with Composer 2.5 and Gemini 3.7 Flash (low, medium, high). A lane runs cursor-agent in ask mode with the sandbox on and a run-owned config that denies writes, shell and MCP calls. Under ericlitman#203, it runs in any repository; the catalog notes say what the language-server worker and enterprise, team, user and repository hooks still run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.14.0 with the Cursor CLI provider (ericlitman#213) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(runner): drop the Devin, agy and dsh repository refusals (ericlitman#204) Read-only means the read-only settings pstack passes to each CLI (ericlitman#203). Devin, agy and dsh lanes now run in any repository; the runner no longer refuses .devin/, .agents/ and its siblings, or a cwd .env, and the project-config walk and home-directory rule go with them. The catalog notes say what each CLI loads from a repository. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(runner): disclose the agy and Devin config walk, and name the providers whose notes cover it (ericlitman#204) Unfret round 1 on ericlitman#215. The agy and Devin notes now say the CLI loads its config directories from the cwd and each parent up to the git root, or up to / outside a repository, so a lane under the home directory outside a repository also loads the home directory's own. docs/reference.md names the providers whose catalog notes describe the configuration they load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * release: Open Pstack 1.15.0 without the Devin, agy and dsh repository refusals (ericlitman#216) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix fork verification coverage and Windows flag fixture * Route native verification and exercise formal model maintenance * Require native consent for formal fixture skill writes --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Eric Litman <eric@litman.org> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Eric A. Litman <ericlitman@studio2.tail062eee.ts.net> Co-authored-by: soulmachine <soulmachine@gmail.com> Co-authored-by: Adam Vellequette <249975382+fitziboy3-source@users.noreply.github.com>
Summary
Removes the last repository refusals from the runner, under #203: a read-only lane means the read-only settings pstack passes to each CLI, and the runner adds no refusal because of the operator's repository configuration. Closes #204.
.devin/, agy one holding.agents/,.agent/,_agents/or_agent/, and dsh a cwd holding.env. The home-directory rule that came with the walk goes too. The field is gone from the contract and all nine adapters..devin/hooks, permissions and MCP servers (the lane passes--respect-workspace-trust false); agy's hooks, MCP servers, rules and skills under the four directories, with no trust check; dsh's cwd.env, whose non-bootstrap values reach its bash tool.docs/reference.mdsays each provider's notes describe the repository configuration its CLI loads.dsh --versionmust be0.2.0-rc.2) stays: it keeps pstack's own patch rows from being ignored silently. runner: remove the Devin, agy and dsh repository refusals #204 leaves it as a question for Eric.Evidence
pstack-runner --parent claude --mode read-only), each from a git fixture whose marker the lane read back:agy:gemini-3.8-flash@highin a repository holding.agents/: preflight passed,complete, output equal to the marker.dsh:deepseek-flash@maxwith a cwd.envholdingPSTACK_FIXTURE=1: preflight passed,complete, output equal to the marker.devin:swe-2@maxin a repository holding.devin/: preflight passed,complete, served modelswe-2-maxverified, output equal to the marker.git statuswas unchanged afterwards.run.test.tsruns a Devin lane beside.devin/, an agy lane beside.agents/, and a dsh lane whose cwd holds.env; the refusal tests andprojectConfigRefusaltests are removed with the code.3d46e72from trustedmain2d5fe99, 5 planned sessions: evidence comment. The Claude and Codex parents each dispatcheddsh:deepseek-flash@maxread-only through the installed launcher; both receipts readcompletewith preflightpassed, after the unchanged version guard. (Round 1 head25617b2also passed.)Merge Danger
Door: two-way. Restoring the refusal is a revert.
Blast Radius: Devin, agy and dsh lanes. Lanes that were refused in repositories holding those directories or a
.envnow run, and the CLI loads that repository configuration, as the notes say.Live gate
Run from trusted
main, because the PR does not change the verifier.claude:runner,codex:runnerwith--runner-route dsh:deepseek-flash@maxNo
catalog: only notes changed in the generated catalog, not route resolution.Acceptance criteria
.devin/(#69,c50514a), an agy lane in one holding.agents/,.agent/,_agents/or_agent/, or a dsh lane whose cwd holds.env."run.test.tscases; the three direct live lanes.runner/run.tsand theprojectConfigcontract field are deleted if no adapter uses them afterwards."run.ts,registry/contract.tsand every adapter.references/model-catalog.mdDevin, agy and dsh notes.Gate results
On head
3d46e72(25617b2plus the round-1 note fix):bun run testbun run typecheckbun run staticclaude plugin validate plugins/pstackNot verified
🤖 Generated with Claude Code