Skip to content

refactor(runner): drop the Devin, agy and dsh repository refusals (#204) - #215

Merged
mergify[bot] merged 2 commits into
mainfrom
feat/204-remove-repository-refusals
Oct 16, 2026
Merged

mergify[bot] merged 2 commits into
mainfrom
feat/204-remove-repository-refusals

Conversation

@ericlitman

@ericlitman ericlitman commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

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.

 executeLane(lane)
-  projectConfigRefusal(adapter.id, cwd, adapter.launch.projectConfig)   # .devin/, .agents/ and siblings, cwd .env, home-directory rule
   preflight.guard (dsh --version, unchanged)
   preflight → launch → parse → receipt
 ProviderAdapter.launch
-  projectConfig: readonly (`${string}/` | `./${string}`)[]
  • Devin no longer refuses a repository holding .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.
  • The Devin, agy and dsh catalog notes now state what each CLI loads from a repository: Devin's .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.md says each provider's notes describe the repository configuration its CLI loads.
  • dsh's version pin (dsh --version must be 0.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

  • Direct live checks, through this branch's launcher (pstack-runner --parent claude --mode read-only), each from a git fixture whose marker the lane read back:
    • agy:gemini-3.8-flash@high in a repository holding .agents/: preflight passed, complete, output equal to the marker.
    • dsh:deepseek-flash@max with a cwd .env holding PSTACK_FIXTURE=1: preflight passed, complete, output equal to the marker.
    • devin:swe-2@max in a repository holding .devin/: preflight passed, complete, served model swe-2-max verified, output equal to the marker.
    • Each fixture's git status was unchanged afterwards.
  • Unit: run.test.ts runs a Devin lane beside .devin/, an agy lane beside .agents/, and a dsh lane whose cwd holds .env; the refusal tests and projectConfigRefusal tests are removed with the code.
  • Exact-head live gate: passed on 3d46e72 from trusted main 2d5fe99, 5 planned sessions: evidence comment. The Claude and Codex parents each dispatched dsh:deepseek-flash@max read-only through the installed launcher; both receipts read complete with preflight passed, after the unchanged version guard. (Round 1 head 25617b2 also 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 .env now 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.

Feature Why
claude:runner, codex:runner with --runner-route dsh:deepseek-flash@max The changed code is the runner's launch path shared by every provider; one route dispatched from each parent exercises it, and dsh also keeps the pre-launch guard beside the deleted code. The other two providers ran live above.

No catalog: only notes changed in the generated catalog, not route resolution.

Acceptance criteria

Criterion (#204) Verification
"The runner no longer refuses a Devin lane in a repository holding .devin/ (#69, c50514a), an agy lane in one holding .agents/, .agent/, _agents/ or _agent/, or a dsh lane whose cwd holds .env." The diff; the three run.test.ts cases; the three direct live lanes.
"The project-config walk and the home-directory rule in runner/run.ts and the projectConfig contract field are deleted if no adapter uses them afterwards." Deleted from run.ts, registry/contract.ts and every adapter.
"Each provider's catalog notes say plainly what repository configuration the CLI loads into a lane ..., replacing the refusal notes." references/model-catalog.md Devin, agy and dsh notes.
"Unit tests and the live gate cover a lane in a repository that holds the formerly refused configuration." Unit tests above; the live gate covers the shared launch path, and the direct live lanes ran in such repositories.

Gate results

On head 3d46e72 (25617b2 plus the round-1 note fix):

Check Exit Summary
bun run test 0 501 pass, 0 fail
bun run typecheck 0
bun run static 0 verifier suite 166 pass, 0 fail
claude plugin validate plugins/pstack 0 Validation passed

Not verified

  • A lane in a cwd under the home directory outside a repository, which the removed home-directory rule used to refuse.
  • Planted hooks or MCP servers in those directories: the notes carry the earlier measurements.

🤖 Generated with Claude Code

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>
@mergify

mergify Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 2 merge protections satisfied — ready to merge.

Show 2 satisfied protections

🟢 Queue ready pull requests

Automatically queue non-draft pull requests targeting main after verify, Unfret, and live-gate pass on the head and every review thread is resolved.

  • #review-threads-unresolved = 0
  • -draft
  • check-success=Unfret
  • check-success=live-gate
  • check-success=verify

🟢 🚦 Auto-queue

When all merge protections are satisfied and these conditions match, this pull request will be queued automatically.

  • -files~=^\.github/
  • base = main

@ericlitman

Copy link
Copy Markdown
Owner Author

Live evidence: Open Pstack

  • Candidate SHA: 25617b297a25f1f7e288e1e7406d2b4f4e62cb34
  • Base SHA: 2d5fe99ef157aa5a50c6cfdb27d4e641a20eb4f6
  • Result: PASSED — named features verified
  • Self-test: not requested
  • Planned sessions: 5 (limit 12)
  • Publisher revision: 2d5fe99ef157aa5a50c6cfdb27d4e641a20eb4f6
  • Evidence-set SHA-256: 99436e08edf37d2d7c3e5e3a3bbfa8cf23a64836545469c153e3d6f219ebad43
  • Installation (claude): CLI 2.1.301 (Claude Code), plugin 1.14.0, candidate 25617b297a25f1f7e288e1e7406d2b4f4e62cb34, tree 60f54012c104186e0cac80201ca673f13738fdca7db2d2d1ecc7320b8cd9598e.
  • Installation (codex): CLI codex-cli 0.163.0, plugin 1.14.0, candidate 25617b297a25f1f7e288e1e7406d2b4f4e62cb34, tree 60f54012c104186e0cac80201ca673f13738fdca7db2d2d1ecc7320b8cd9598e.
  • Observation (claude / runner): surface claude -p stream-json with the candidate plugin-dir; action recipe runner: route-1, full-access-writer, bounded-writer; result passed 16 assertions; ids retained privately; 16 assertions machine-checked; transcript SHA-256 b7cac3d9ba34ed5e03481ab79b08293d0dd5d732d20656ca158fc4d840bccf02; artifact-set SHA-256 4736b7206dc236abee27db863b1049a274b4684fc03c0612e46fb6bb5ad51392.
  • Observation (codex / runner): surface codex exec --json with the run-owned candidate installation; action recipe runner: route-1, linked-worktree-writer; result passed 10 assertions; ids retained privately; 10 assertions machine-checked; transcript SHA-256 8c6d9b3227aef415dea31f57662a1a4444c5f00786205dbf2a97768d0fbf0d8d; artifact-set SHA-256 eb8b2c475b6366b4b2721b86de07f5ef948629b8dcf18ec1b61b218997a53d71.
  • Policy: every new head requires a fresh run; this verifier does not change PR state, queue, or merge.

@greptile-apps

greptile-apps Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileTier: plus

[Medium impact] The PR appears safe to merge under the documented repository-configuration policy.

Summary

Removes the repository and home-directory refusals for Devin, agy, and dsh.

  • Devin, agy, and dsh lanes now run with repository settings.

ericlitman explicitly accepts repository hooks, MCP servers, agy agent replacement, dsh .env values, and home-directory configuration applying as-is. These intentional changes are not reported as defects.

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

@unfret-eal

unfret-eal Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

✅ No blocking findings

Walkthrough

This PR removes the runner's last repository-based refusals: Devin lanes no longer refuse repositories with `.devin/`, agy lanes no longer refuse `.agents/`, `.agent/`, `_agents/` or `_agent/`, and dsh lanes no longer refuse a cwd holding `.env`, and the home-directory rule goes with them. The `projectConfigRefusal` walk and the `projectConfig` contract field are deleted from `run.ts`, the contract and all nine adapters. The Devin, agy and dsh catalog notes and `docs/reference.md` now describe what repository configuration each CLI loads into a lane, and the old refusal tests are replaced with tests that run each lane beside its formerly refused config. The author reports passing unit gates and live runs. One low-severity note remains: a home-level agy agent that overrides the run-owned agent is still not disclosed.

Area What changes
Runner launch path Lanes no longer get a pre-preflight `child-failed` refusal based on project config or home-directory location. The dsh version guard stays.
Provider contract and adapters Removes `projectConfig` from `ProviderAdapter.launch` and from every adapter and its tests.
Catalog notes and docs The Devin, agy and dsh notes now say which hooks, MCP servers, rules, skills or `.env` values load from the repository and home directory, instead of describing refusals.
Tests Adds run tests for a Devin lane beside `.devin/`, an agy lane beside `.agents/`, and a dsh lane whose cwd holds `.env`, all expecting `complete`. Removes the refusal tests and the `projectConfigRefusal` tests.
Advisories (1)
  • 🔵 Low · Home agy agent overrides remain undisclosed · plugins/pstack/skills/poteto-mode/scripts/runner/providers/agy.ts:132
    The new note adds the ancestor/home walk, but still says only “A repository agent” can replace `pstack-read-only`. Because the same walk continues to `/` outside repositories, a supported lane from `$HOME/notes` also finds `$HOME/.agents/agents/pstack-read-only.md`; that host agent replaces the run-owned agent and can change its prompt and tools, while the generated catalog presents this override as repository-only. The required host-configuration disclosure therefore remains incomplete.
    Not blocking because: The head note already says lanes under the home outside a repository load ~/.agents/ and its siblings, whose hooks and MCP servers run with no trust check; only the override sentence says 'repository'. The override needs an operator-authored ~/.agents/agents/pstack-read-only.md, so no run or trust decision changes.
Since the last review
  • Fixed: agy note omits the ancestor and home-directory walk these lanes now reach. Why: The carried ancestor/home-walk omission is repaired. The current adapter note and generated catalog explicitly name all four configuration directories, the walk through parents to the Git root or filesystem root, and the home-directory configurations reached outside a repository or in a repository rooted at home. They also disclose hooks, MCP servers, rules and skills. Thus the reported repository-only description no longer exists. The narrower question of home-agent replacement precedence is adjudicated separately in finding-0000.
  • Fixed: Devin note omits the ancestor and home-directory walk these lanes now reach. Why: The carried Devin omission is repaired. The current note names .devin/config.json hooks and permissions and .devin/mcp_config.json MCP servers, explains the cwd-to-Git-root or cwd-to-filesystem-root search, and explicitly states that a non-repository lane below home loads ~/.devin/. It also explains --respect-workspace-trust false. The generated catalog contains the same disclosure, so the reported repository-only limitation no longer exists.
  • Fixed: Reference claims every provider's notes disclose repository config loading. Why: The false completeness claim is removed. The current reference explicitly limits its statement to OpenCode, Amp, Cursor, Devin, agy and dsh; it no longer says every provider's notes disclose configuration loading. Claude, Codex and Grok are not included in that assertion. Their unchanged notes therefore do not contradict the current sentence, resolving the carried finding.
Details
Lane / stage Model Effort Outcome Duration
broad-gpt-5.6-sol-xhigh / review openai/gpt-5.6-sol → gpt-5.6-sol · primary xhigh succeeded 1 min 41 s
broad-opus-5.5-max / review anthropic/claude-opus-5-5 → claude-opus-5-5 · primary max succeeded 6 min 16 s
focal-gpt-5.6-sol-xhigh copy / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 4 min 53 s
focal-gpt-5.6-sol-xhigh copy 2 / review openai/gpt-6.1-sol → gpt-6.1-sol · primary xhigh succeeded 5 min 22 s
judge / judge openai/gpt-6-astra → gpt-6-astra · primary high succeeded 42 s
confirmation / confirmation anthropic/claude-opus-5-5 → claude-opus-5-5 · primary max succeeded 4 min 38 s

Reviewed the whole pull request.
4 reviewers finished.
Commit 3d46e72.
Check run.
Run: GET /unfret/run/panel:3d46e7246044a2227be0a3bc9b25f2edf17286ae:7mJeL9vc6vK:CNSyKLzOOe0.

@unfret review · @unfret status · @unfret help

@unfret-eal unfret-eal Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 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

Comment thread plugins/pstack/skills/poteto-mode/scripts/runner/providers/agy.ts Outdated
Comment thread plugins/pstack/skills/poteto-mode/scripts/runner/providers/devin.ts Outdated
Comment thread docs/reference.md Outdated
…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>
@ericlitman

Copy link
Copy Markdown
Owner Author

Live evidence: Open Pstack

  • Candidate SHA: 3d46e7246044a2227be0a3bc9b25f2edf17286ae
  • Base SHA: 2d5fe99ef157aa5a50c6cfdb27d4e641a20eb4f6
  • Result: PASSED — named features verified
  • Self-test: not requested
  • Planned sessions: 5 (limit 12)
  • Publisher revision: 2d5fe99ef157aa5a50c6cfdb27d4e641a20eb4f6
  • Evidence-set SHA-256: 9fecbc59896f706729f7e3b99c818dfbddbb34c6cb686233ea4b770f356380d8
  • Installation (claude): CLI 2.1.301 (Claude Code), plugin 1.14.0, candidate 3d46e7246044a2227be0a3bc9b25f2edf17286ae, tree 7077c5122435324827ae093dfd43a8c9ab53fe1a6e79ac714348de19b285c41a.
  • Installation (codex): CLI codex-cli 0.163.0, plugin 1.14.0, candidate 3d46e7246044a2227be0a3bc9b25f2edf17286ae, tree 7077c5122435324827ae093dfd43a8c9ab53fe1a6e79ac714348de19b285c41a.
  • Observation (claude / runner): surface claude -p stream-json with the candidate plugin-dir; action recipe runner: route-1, full-access-writer, bounded-writer; result passed 16 assertions; ids retained privately; 16 assertions machine-checked; transcript SHA-256 ad4398a27060e2c4133ee2ebfc00a9d4b6b49aae606d305c568dddb08335827c; artifact-set SHA-256 c509346d6f6907bb8eb6e23fbe473d2adbaaade5c68d24660c7435c38754239e.
  • Observation (codex / runner): surface codex exec --json with the run-owned candidate installation; action recipe runner: route-1, linked-worktree-writer; result passed 10 assertions; ids retained privately; 10 assertions machine-checked; transcript SHA-256 387317dce1e5646a68bb6069359156e84eb39479e0f8afc1400e5fd132fdfbbe; artifact-set SHA-256 b4e269332c73a1b7fd821ee84cdffacc174d904dcc0c81712f0c3a0720dfbe7a.
  • Policy: every new head requires a fresh run; this verifier does not change PR state, queue, or merge.

@unfret-eal unfret-eal Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No blocking findings
Check

@mergify

mergify Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • ✅ Entered queue — 2026-10-16 20:44 UTC · Rule: default · triggered by merge protections
  • ✅ Checks skipped · PR is already up-to-date
  • ✅ Merged — 2026-10-16 20:44 UTC · at ae3f98d6486bbf8319d69508d95c5c72e046dbc9 · merge

This pull request spent 8 seconds in the queue, including 1 second running CI.

Required conditions to merge

@mergify
mergify Bot merged commit ae3f98d into main Oct 16, 2026
6 checks passed
fitziboy3-source added a commit to fitziboy3-source/open-pstack that referenced this pull request Oct 20, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runner: remove the Devin, agy and dsh repository refusals

1 participant