Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pstack",
"version": "0.15.36-shared.1",
"version": "0.15.36-shared.2",
"description": "Shared pstack engineering workflows for Claude Code and Codex, with one configuration and host-specific runtime adapters.",
"author": {
"name": "Local adaptation; upstream Lauren Tan"
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pstack-codex",
"version": "0.15.36-shared.1",
"version": "0.15.36-shared.2",
"description": "Shared pstack engineering workflows for Codex and Claude Code, with one configuration and native host adapters.",
"author": {
"name": "Lauren Tan; local Codex adaptation"
Expand Down
11 changes: 8 additions & 3 deletions ADAPTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ The [fork guards](./docs/ci.md#fork-guards) reject the denylisted Cursor primiti
- **#805's transcript timing in `worktree-audit.sh`.** The local script reads no transcripts, so it runs no `stat` or `date` on them.
- **#986's rejected-slug fallbacks and the `run_in_background` note.** Arena's dropped-seat chain, poteto-mode's rule for a slug the Task tool rejects, and the note that a steer or resume runs in the background all handle Cursor's Task tool and its slugs. This fork resolves models through `config.json` and never substitutes silently.
- **Orchestrate's Cursor runtime (#1043).** Cloud-VM workers (`environment: "cloud"`), the Project tracker and store, and the `control-ui` and `control-cli` checks from `cursor-team-kit`. The fork's playbook takes the agentic design with the host capabilities under [Host-neutral wording](#host-neutral-wording).
- **#986's interrogate rewrite, for now.** Upstream's adversaries prove each finding by running commands and repros in their own worktrees. This fork's xagent reviewers run `ro`, which is plan mode with no commands for Claude and Gemini, and `scripts/pstack-host-e2e.py` accepts a reviewer only as `ro` or as an unedited, snapshot-bracketed native run, so a separate change ports the rewrite with both. Until then `skills/interrogate/` with its references, and the interrogate lines in `README.md`, `docs/guide/04-design.md`, `docs/guide/10-recipes-and-pitfalls.md`, and poteto-help, keep their 0.15.32 text. `check-upstream.mjs` no longer lists them, so port them from upstream `ab1f702c`.
- **`make-bot-ui` and the Benny automation pack.** Both drive Cursor platform features: make-bot-ui creates a Cursor webhook routine with `update_state`, takes its sender key through a Cursor secret request, and posts to `api2.cursor.sh`; Benny is two Cursor automations for Slack issue reports. The fork's earlier ports kept them as dormant prose with no platform behind them on Codex, Claude Code, or Antigravity, and every sync still had to re-adapt them, so 0.15.32-shared.5 removed both. Host features and the maintainer's setup cover the same jobs (checked 2026-10-25):
- **Scheduled runs.** Both hosts schedule work. Codex Automations run a prompt on a cron schedule, locally or in a worktree; every automation on the maintainer's machine is a cron schedule, and none uses an outside trigger. The Claude desktop app runs local scheduled tasks, and Claude Code has cloud [scheduled tasks](https://code.claude.com/docs/en/routines.md), a research preview, whose API trigger takes a per-task bearer token, so a local page's server can POST to wake one. That API trigger is the closest match to make-bot-ui's custom page.
- **Chat bug reports.** A Feishu/Lark bridge to the local CLI agents, such as lark-channel-bridge with one bot per agent, runs Claude Code or Codex when a group message mentions its bot, so a reported bug can be handed to pstack's bug-fix playbook, and a chat message can wake an agent where make-bot-ui's page is not needed. It acts only on messages sent to it, with a mention in a group, so it does not watch a channel and triage every report as Benny did; the message has to name the repository, because the bridge starts each agent in its own workspace; and a bot with full access acts for anyone allowed to mention it. In Slack, [Claude Tag](https://claude.com/docs/claude-tag/overview.md), on Team and Enterprise, takes a bug report to a draft PR.
Expand All @@ -70,7 +69,7 @@ The [fork guards](./docs/ci.md#fork-guards) reject the denylisted Cursor primiti

| Upstream | Synced | From | Pull request |
|---|---|---|---|
| 0.15.36 (`c742dd61`, #977–#1043) | 2026-10-30 | 0.15.32 (`e73df471`) | #31 |
| 0.15.36 (`c742dd61`, #977–#1043) | 2026-10-30 | 0.15.32 (`e73df471`) | #31, #32 (interrogate, #986) |
| 0.15.32 (`e73df471`, #791–#807) | 2026-10-24 | 0.15.30 (`4ec7ffa1`) | #25 |
| 0.15.30 (#776, #779 follow-ups) | 2026-10-22 | 0.15.25 (`99743e9c`) | #21, #22, #23 |
| 0.15.25 (#633, #634) | 2026-10-16 | 0.15.21 (`997ffc7f`) | #10 |
Expand Down Expand Up @@ -124,6 +123,12 @@ The command downloads nothing on its own: `findTlc` in `run.ts` runs `mise insta

The runtime gate downloads nothing either: `scripts/check.sh` runs statechart's render test, which installs Pele, Mermaid, and jsdom from npm, only when `STATECHART_INSTALL=1` is set, as CI sets it. [Run the CI checks locally](./docs/ci.md) says which other statechart tests skip. The launcher's symlink test resolves its temporary folder first, because a relative link computed from macOS's `/var/folders` path breaks under its real `/private/var` path.

### interrogate

interrogate takes upstream's adversaries (#986): each one tries to break the change in its own worktree and reports only findings a run proves, the parent reruns each finding's command in that adversary's worktree per arena Phase F and skips arena Phases C, D, and E, and the reviewer prompt, rubric, lead-judgment, and code-quality-review references went with the old review rounds. Where upstream reads the `interrogate reviewers` line and spawns each adversary as `generalPurpose`, the skill reads that panel from `config.mjs show` and spawns a worker that can edit files and run commands in its worktree. An `xagent:` adversary runs `rw` in an exclusive worktree, because `ro` is plan mode for claude and gemini, which runs no commands. Its commands are those its agent's `rw` entry in the xagent table allows, so where that entry limits them, the skill tells the adversary to prove each finding with a test that an allowlisted command runs, and its dropouts follow xagent's retry and unresolved-outcome rule. The output names each adversary's model, keeps the fork's disclosure that adversaries sharing the inherited model are independent runs, not distinct model families, and says which adversaries ran no command.

`scripts/pstack-host-e2e.py` follows: an adversary slot takes an `rw` xagent attempt or a native dispatch whose worktree held the final fix from its start, repro files allowed, and each rerun the parent records in `findings.json` must be a command the host's own log shows the parent ran in that worktree. The script's module docstring holds the exact rules, and `scripts/e2e-snapshot.py` went with the read-only review.

### Other skills

- poteto-help uses the Codex and Claude entry points, reads the shared `~/.config/pstack/config.json` policy, links to this checkout, and does not claim Cursor Custom Modes, `/loop`, Cursor model paths, or Cursor delegation tools.
Expand Down Expand Up @@ -175,7 +180,7 @@ For all CI checks, including strict TypeScript checks, Bun tests and reproducibl

The CLI tests use real Git checkouts and subprocesses with vendor stand-ins, including staged/committed read-only violations, misleading verdicts, timeout and cancellation. Vendor acceptance pins the fixture's test contents and checks the worker's successful test receipt against its final source before independently rerunning it. The shared verification runner gives each command a fresh Python bytecode-cache prefix and disables cache writes; `-B` alone can still load stale bytecode after an equal-size edit in the same second. A worker receipt is not sufficient without that independent run. Importing the test, rewriting it, or reusing a receipt from older code cannot satisfy the full acceptance gate.

Run `scripts/xagent-e2e.sh` after changing `bin/xagent*` or upgrading an agent CLI; it calls every vendor. Run `python3 scripts/pstack-host-e2e.py <new-run-dir>` after changing cross-agent routing: actual Claude and Codex hosts run swarm, then interrogate, through their current shared policy on synthetic fixtures. The host harness accepts a run only on evidence the host cannot write, such as xagent receipts, the host's own logs, snapshots the snapshot tool printed, and its own independent tests, because the host's success report is the thing under test. Its acceptance rules live in the script's module docstring, beside the code and tests that enforce them, so change them there. Neither harness changes preferences. Both bound the outer host process with `timeout` and a kill-after limit, and a verification timeout is a failed check with exit code 124.
Run `scripts/xagent-e2e.sh` after changing `bin/xagent*` or upgrading an agent CLI; it calls every vendor. Run `python3 scripts/pstack-host-e2e.py <new-run-dir>` after changing cross-agent routing: actual Claude and Codex hosts run swarm, then interrogate, through their current shared policy on synthetic fixtures. The host harness accepts a run only on evidence the host cannot write, such as xagent receipts, the host's own logs, including the commands the host ran itself, and its own independent tests, because the host's success report is the thing under test. Its acceptance rules live in the script's module docstring, beside the code and tests that enforce them, so change them there. Neither harness changes preferences. Both bound the outer host process with `timeout` and a kill-after limit, and a verification timeout is a failed check with exit code 124.

The runtime checks start with `scripts/check-fork.mjs`, which validates the manifests, all SKILL.md and agent frontmatter, each workflow skill's link to the shared runtime contract and its absence from the `STANDALONE` skills, local links, a denylist of the Cursor-only wording this guide replaces, and the files and anchor sentences of the local decisions it requires; see [Fork guards](./docs/ci.md#fork-guards). Use a fresh Codex app-server skills/list and Claude `plugin details` to verify inventory; a static validator alone is not a discovery or behavioral test.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ $interrogate review this pr.
| [`$architect`](./skills/architect/SKILL.md) | you're about to write code that crosses a function boundary and want the caller's usage, types, and module shape settled first. |
| [`$arena`](./skills/arena/SKILL.md) | you want N parallel attempts at the same thing, then to grab the best parts of each. |
| [`$swarm`](./skills/swarm/SKILL.md) | you want N parallel workers across different slices or races, then one aggregated report. |
| [`$interrogate`](./skills/interrogate/SKILL.md) | you have a diff and want several different models to try to break it, including a strict code-quality lens. |
| [`$interrogate`](./skills/interrogate/SKILL.md) | you have a diff and want several different models to try to break it, keeping only findings a run proves. |
| [`$automate-me`](./skills/automate-me/SKILL.md) | you want your own `-mode` skill, drafted from how you've actually worked. |
| [`$setup-pstack`](./skills/setup-pstack/SKILL.md) | you want to pick which models pstack uses per role. detects your models and writes a config rule. |
| [`$reflect`](./skills/reflect/SKILL.md) | a long task landed and you want the recipe captured as a skill edit. |
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ $poteto-mode 我暂时离开。请在独立 worktree 中准备并验证这组改

$how 取消任务的调用链是什么?批量取消时是否会产生 N+1 查询?

$interrogate review 这个 PR,重点检查行为回归和维护成本。
$interrogate 这个 PR,用实际运行找出行为回归。
```

流程会像上游一样推送自己的分支、开出并更新自己的 PR,不再逐次询问,但不会直接推送主干。合并、`--auto`、对他人分支的 force-push、部署、发布、PR 以外的远程消息、资源创建和破坏性清理,都需要覆盖相应动作和范围的授权。pstack 不安装定时器,也不会自动创建目标、计划任务或 webhook。
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/01-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Use `pstack-codex@personal` instead for an existing personal-marketplace install

## Maintain and publish

Edit this checkout, preserve the host adapters, and bump both plugin manifest versions together when publishing runtime or skill changes. Run the [CI checks](../ci.md), validate the manifests, and check changed helper scripts before committing and pushing. Run `scripts/xagent-e2e.sh` when `bin/xagent*` changes. After changing cross-agent routing or host lifecycle rules, run `python3 scripts/pstack-host-e2e.py <new-run-dir>` with authorized vendor access; it checks both hosts against synthetic fixtures using their current configured external workers and reviewers, with final-source verification and separate reviewer worktrees. The live harnesses need a `timeout` command supporting `-k`; each verification command also has a 30-second deadline, configurable with `--check-timeout` in the host harness. Verification timeouts remain failed checks and retain logs. When TypeScript helper sources change, use the Bun version in `.bun-version`, install the pinned dependencies with `bun install --frozen-lockfile` in `skills/poteto-mode/scripts`, then rebuild from the repository root with `python3 scripts/build-runtime.py` and run `bash scripts/check.sh`.
Edit this checkout, preserve the host adapters, and bump both plugin manifest versions together when publishing runtime or skill changes. Run the [CI checks](../ci.md), validate the manifests, and check changed helper scripts before committing and pushing. Run `scripts/xagent-e2e.sh` when `bin/xagent*` changes. After changing cross-agent routing or host lifecycle rules, run `python3 scripts/pstack-host-e2e.py <new-run-dir>` with authorized vendor access; it checks both hosts against synthetic fixtures using their current configured external workers and adversaries, with final-source verification, an exclusive worktree per adversary, and the parent's own rerun of each finding. The live harnesses need a `timeout` command supporting `-k`; each verification command also has a 30-second deadline, configurable with `--check-timeout` in the host harness. Verification timeouts remain failed checks and retain logs. When TypeScript helper sources change, use the Bun version in `.bun-version`, install the pinned dependencies with `bun install --frozen-lockfile` in `skills/poteto-mode/scripts`, then rebuild from the repository root with `python3 scripts/build-runtime.py` and run `bash scripts/check.sh`.

Run `node scripts/check-upstream.mjs` for a read-only upstream comparison. Review changes before applying them; it never overwrites adapters or model preferences. Retain the MIT license and update `UPSTREAM.json` when accepting a new upstream version.

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/04-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ Reach for it when parallelism buys coverage or lets independent checks race. `$a
$interrogate the whole branch, but skeptically. no nitpicks unless it's an actual bug or regression.
```

[`$interrogate`](../../skills/interrogate/SKILL.md) sends the same diff, intent, and rubric to several reviewers on different model families. Model diversity is the point. Different models have different blind spots, so a finding two models raise independently is high-confidence signal. The lead sorts everything into `Act on`, `Consider`, `Noted`, and `Dismissed`, with a reason for each dismissal, and applies nothing automatically.
[`$interrogate`](../../skills/interrogate/SKILL.md) gives the change and its intent to adversaries on the configured models, and each tries to break it with a run against the real code. Adversaries find different failures. A finding survives only when rerunning its command shows a failure that breaks the intent. The report lists every verified finding with the adversaries that found it, then what each adversary dropped and why, and applies nothing.

Read the dismissals too. The lead is a pragmatic senior engineer, not an oracle, and you can override it.
Read the Dropped list too. You can override the verdict.

## How much design work does a task deserve?

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/10-recipes-and-pitfalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Each worker owns one package. The parent waits for every slice and returns one `
$interrogate the whole branch, but skeptically. don't change anything yet. no nitpicks unless it's an actual bug or regression in behavior.
```

The qualifiers do real work. "don't change anything yet" keeps it read-only, and the nitpick rule pre-filters the noise so `Act on` findings are worth your time.
The qualifiers do real work. "don't change anything yet" keeps it read-only, and the nitpick rule pre-filters the noise so the verified findings are worth your time.

## Prove a property tests rarely reach

Expand Down Expand Up @@ -110,7 +110,7 @@ To watch the catch-up instead, run [`$ketchup-video`](../../skills/ketchup-video
- **A vague finish condition.** "make it better" gives `/goal` nothing to check. Give a command or artifact that can pass or fail. A goal is finite work, not a timer.
- **Parallel agents in one worktree.** They overwrite each other, and nobody can tell which agent changed what. Say "own worktree per attempt" and the isolation is free.
- **Using `$arena` for coverage.** `$arena` repeats one design or code brief, then picks a base and grafts the best parts. `$swarm` partitions slices or declared race arms and aggregates one report.
- **Accepting every review comment.** Bots and humans both file real catches and noise in one list. `$interrogate` sorts findings into act-on and dismissed buckets with reasons, and you can override either way.
- **Accepting every review comment.** Bots and humans both file real catches and noise in one list. `$interrogate` keeps only the findings a rerun proves and lists what it dropped and why, and you can override either way.
- **Treating `auto` as a model slug.** `auto` and `inherit-parent` mean "omit the model field so the subagent inherits the parent chat model." [Setup](./01-setup.md) covers the roles and the pstack-specific JSON file.
- **Reporting success off a green build.** A build proves it compiles. Ask for the real command, flow, stored value, or profile, and expect the evidence in the reply.
- **Writing a `SKILL.md` freehand.** Route it through the [Authoring or modifying a skill playbook](../../skills/poteto-mode/playbooks/authoring-a-skill.md) so validation and review happen.
Expand Down
21 changes: 21 additions & 0 deletions scripts/check-fork.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,27 @@ export const REQUIRED = [
hint: "the render guide asks the user before installing Pele from npm",
section: "local-decisions",
},
{
id: "interrogate-policy-panel",
file: "skills/interrogate/SKILL.md",
pattern: /Read the `interrogate reviewers` list from the effective policy from `node <plugin-root>\/bin\/config\.mjs show --host <codex\|claude\|t3>` in place of `arena runners`/,
hint: "interrogate reads its adversaries from the effective policy, not from upstream's model sheet",
section: "interrogate",
},
{
id: "interrogate-adversaries-rw",
file: "skills/interrogate/SKILL.md",
pattern: /Spawn each adversary as a worker that can edit files and run commands in its own worktree; an `xagent:<agent>` adversary runs `rw`[^\n]*adversary runs only the commands in `<plugin-root>\/bin\/xagent-allowed-commands`/,
hint: "each adversary edits and runs commands in its own worktree; an xagent one runs rw, within its agent's allowlist",
section: "interrogate",
},
{
id: "interrogate-parent-rerun",
file: "skills/interrogate/SKILL.md",
pattern: /Verify each finding per arena Phase F by rerunning its command yourself in that adversary's worktree\./,
hint: "the parent reruns each finding's command itself, in that adversary's worktree",
section: "interrogate",
},
{
id: "xagent-skill",
file: "skills/xagent/SKILL.md",
Expand Down
Loading
Loading