diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 1f5a1a5b..919c42e9 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -1,7 +1,7 @@ { - "name": "open-pstack", + "name": "pstack-flex", "interface": { - "displayName": "pstack" + "displayName": "pstack-flex" }, "plugins": [ { diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c0125930..afd3c0e6 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,9 +1,9 @@ { - "name": "open-pstack", + "name": "pstack-flex", "owner": { - "name": "Eric Litman" + "name": "Martin Patino" }, - "description": "Pstack for Claude Code and Codex, tracking Cursor's upstream pstack.", + "description": "pstack for Claude Code and Codex on the models you choose: subscription CLIs or API-key gateway lanes.", "plugins": [ { "name": "pstack", @@ -13,7 +13,7 @@ "author": { "name": "Lauren Tan (original)" }, - "homepage": "https://github.com/ericlitman/open-pstack", + "homepage": "https://github.com/thisguymartin/pstack-flex", "license": "MIT", "keywords": [ "pstack", diff --git a/AGENTS.md b/AGENTS.md index 6dc9c069..89410e5b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,11 +1,11 @@ -# open-pstack +# pstack-flex Track all durable work in this repository's GitHub Issues. Do not create a parallel Linear queue. Read `UPSTREAM.md` before changing upstream-derived content. Cursor's `cursor/plugins/pstack` tree is the content upstream. Keep one shared skill tree for Claude Code and Codex; adapt harness primitives at the existing mapping boundaries instead of forking skills or adding compatibility layers. The parent harness resolves provider routing once. Children do not detect or reroute themselves. -Before opening a pull request, run the Bun tests, strict typecheck, static invariants, and plugin validation. +Before opening a pull request, run the Bun tests, strict typecheck, static invariants, and plugin validation: `bash scripts/check.sh` runs all of them. -Nothing merges, tags, releases, or rolls out until the exact candidate is installed and the changed behavior passes a live test from the real user surface in every affected harness. Unit tests, validators, source inspection, and self-reports do not satisfy this gate. Record the installed version, surface, action, and observed result in the pull request template. A pull request without that evidence remains a draft. +Nothing merges, tags, releases, or rolls out until the exact candidate is installed and the changed behavior passes a live test from the real user surface in every affected harness. Unit tests, validators, source inspection, and self-reports do not satisfy this gate. Record the installed version, surface, action, and observed result in the pull request template. A pull request without that evidence remains a draft. `docs/LIVE-GATE.md` lists the steps per change and the evidence format. Do not add an implicit runtime timeout or a weaker-model fallback. diff --git a/CHANGES.md b/CHANGES.md index b5d39977..9e791df2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # CHANGES — applied substitutions +## Unreleased: pstack-flex becomes its own distribution + +- The marketplace is now `pstack-flex` (was `open-pstack`) in both the Claude Code and Codex marketplace files. Install with `pstack@pstack-flex`. The plugin keeps the name `pstack`, so skill names such as `pstack:poteto-mode` are unchanged. Manifests, package names, and docs point at `thisguymartin/pstack-flex`; attribution to open-pstack, pstack-claude, and Cursor pstack stays in README and NOTICE. +- New skills: `intake` ([#10](https://github.com/thisguymartin/pstack-flex/issues/10)) turns GitHub issues into ready-to-run poteto-mode briefs with a playbook, an observable exit condition, a verification plan, and a worktree; it is read-only and parks briefs with open product questions. `diff-behavior` ([#15](https://github.com/thisguymartin/pstack-flex/issues/15)) runs the same scenarios on trunk and head through `swarm`, normalizes, and classifies every difference as intended, unintended, or noise. Neither changes an upstream skill body; wiring them into poteto-mode and the multi-phase-plan regression lane is a follow-up. +- Fixes: `codex-tools.md` now says the default panel runs four lanes across three providers (it said four providers). `docs/LANES.md` replaces the stale claim that OpenRouter needs a local translator with OpenRouter's documented Claude Code connection and the probes from [#7](https://github.com/thisguymartin/pstack-flex/issues/7). + ## Unreleased: lane journal - `pstack-runner` writes an opt-in lane journal (start record with the head of the prompt, stdout as it arrives, receipt copy) under `~/.pstack-flex/lanes/` while that directory exists. `--label` names a lane. A journal failure never changes a lane's receipt, exit status, or output. [psf-monitor](https://github.com/thisguymartin/psf-monitor) reads the journal to show lanes while they run; the agent monitor that first shipped here moved there. Tracked in [pstack-flex #23](https://github.com/thisguymartin/pstack-flex/issues/23). diff --git a/README.md b/README.md index bf413900..04e937ac 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # pstack-flex [![CI](https://github.com/thisguymartin/pstack-flex/actions/workflows/ci.yml/badge.svg)](https://github.com/thisguymartin/pstack-flex/actions/workflows/ci.yml) -[![Fork of open-pstack v1.5.0](https://img.shields.io/badge/fork%20of-open--pstack%20v1.5.0-blue)](https://github.com/ericlitman/open-pstack/releases/tag/v1.5.0) +[![Based on open-pstack v1.5.0](https://img.shields.io/badge/based%20on-open--pstack%20v1.5.0-blue)](https://github.com/ericlitman/open-pstack/releases/tag/v1.5.0) [![MIT license](https://img.shields.io/github/license/thisguymartin/pstack-flex)](LICENSE) -**pstack-flex runs [Lauren Tan (@poteto)](https://x.com/poteto)'s [pstack](https://github.com/cursor/plugins/tree/main/pstack) in Claude Code and Codex on the models you actually have.** It is a fork of [ericlitman/open-pstack](https://github.com/ericlitman/open-pstack), which translates pstack's Cursor-specific parts for Claude Code and Codex. open-pstack assumes four frontier subscriptions. This fork keeps its skills and workflows and changes one thing: which models setup accepts and how they are reached. +**pstack-flex runs [Lauren Tan (@poteto)](https://x.com/poteto)'s [pstack](https://github.com/cursor/plugins/tree/main/pstack) in Claude Code and Codex on the models you actually have.** It is built on [ericlitman/open-pstack](https://github.com/ericlitman/open-pstack), which translates pstack's Cursor-specific parts for Claude Code and Codex. open-pstack assumes four frontier subscriptions. pstack-flex keeps its skills and workflows, changes which models setup accepts and how they are reached, and adds its own skills. The agent monitor lives in its own repository, [psf-monitor](https://github.com/thisguymartin/psf-monitor). Lauren built pstack from the skills she uses to ship code at Cursor. In a [55-minute interview with Denis Labelle](https://x.com/DenisLabelle/status/2091337807939706928), she says that she shipped 1,000 pull requests in one month after steadily improving how her agents work and verify their results. @@ -80,7 +80,7 @@ Run these commands inside Claude Code: ```text /plugin marketplace add thisguymartin/pstack-flex -/plugin install pstack@open-pstack +/plugin install pstack@pstack-flex /reload-plugins ``` @@ -90,7 +90,7 @@ Run these commands in your shell: ```shell codex plugin marketplace add thisguymartin/pstack-flex --ref main -codex plugin add pstack@open-pstack +codex plugin add pstack@pstack-flex ``` Turn on Codex subagents in `~/.codex/config.toml` so pstack can compare work in parallel: @@ -161,6 +161,8 @@ The agent monitor is a separate plugin, [psf-monitor](https://github.com/thisguy | `maintain-verification-skill` | The project's verification instructions no longer match the product. | | `babysit` | A pull request needs CI failures and review comments handled until it is ready. | | `reflect` | A hard task is finished and its lessons should improve the next run. | +| `intake` | You have GitHub issues and want each turned into a ready-to-run brief with a playbook, an observable exit condition, and a worktree. | +| `diff-behavior` | You want to know what a change did from the outside: the same scenarios on trunk and head, with every unclaimed difference flagged. | Plugin skills include `pstack:` in their name. In Claude Code, invoke a native skill such as `/pstack:architect`. In Codex, ask for the skill, such as `Use pstack:architect for this design.` See the [technical reference](docs/reference.md) for the full list. @@ -194,8 +196,8 @@ Also kept here: [the original README](README-UPSTREAM.md), unchanged; [the techn Fixes for Claude Code or Codex, new lanes, and help bringing over new pstack releases are welcome. Search this repository's [GitHub Issues](https://github.com/thisguymartin/pstack-flex/issues) before opening a new one. For changes to upstream-derived content, explain why the change belongs here instead of in open-pstack or Lauren's original project. -Read [UPSTREAM.md](UPSTREAM.md) and [UPSTREAM-FLEX.md](UPSTREAM-FLEX.md) before changing content brought over from either upstream. Pull requests must keep one shared skill tree for Claude Code and Codex and pass the repository's tests, type checks, plugin validation, and static checks. Nothing merges until the exact candidate is installed and the changed behavior passes a live test from the real user surface in every affected harness; the [pull request template](.github/pull_request_template.md) records that evidence, and a PR without it stays a draft. Adding a gateway provider has its own checklist in [docs/LANES.md](docs/LANES.md#adding-a-gateway-provider). +Read [UPSTREAM.md](UPSTREAM.md) and [UPSTREAM-FLEX.md](UPSTREAM-FLEX.md) before changing content brought over from either upstream. Pull requests must keep one shared skill tree for Claude Code and Codex and pass the repository's tests, type checks, plugin validation, and static checks. Nothing merges until the exact candidate is installed and the changed behavior passes a live test from the real user surface in every affected harness; the [pull request template](.github/pull_request_template.md) records that evidence, and a PR without it stays a draft. Run `bash scripts/check.sh` for the local checks and follow [docs/LIVE-GATE.md](docs/LIVE-GATE.md) for the live test. Adding a gateway provider has its own checklist in [docs/LANES.md](docs/LANES.md#adding-a-gateway-provider). ## License -MIT. pstack was created by Lauren Tan. open-pstack builds on Michael Denyer's [pstack-claude](https://github.com/michael-denyer/pstack-claude) port and includes attributed MIT-licensed work from Cursor Team Kit and Superpowers. pstack-flex is a fork of open-pstack. See [NOTICE.md](NOTICE.md) and the preserved license files for details. +MIT. pstack was created by Lauren Tan. open-pstack builds on Michael Denyer's [pstack-claude](https://github.com/michael-denyer/pstack-claude) port and includes attributed MIT-licensed work from Cursor Team Kit and Superpowers. pstack-flex started as a fork of open-pstack and is maintained as its own distribution. See [NOTICE.md](NOTICE.md) and the preserved license files for details. diff --git a/UPSTREAM-FLEX.md b/UPSTREAM-FLEX.md index 86db01c6..b13e5a8c 100644 --- a/UPSTREAM-FLEX.md +++ b/UPSTREAM-FLEX.md @@ -37,6 +37,7 @@ All flex changes are additive and live in port-owned files so upstream merges st - The assignment-first restructure of `skills/setup-pstack/SKILL.md` - `docs/LANES.md`, this file, the README fork section, and the NOTICE/LICENSE/CHANGES additions - `plugins/pstack/hooks/session-start-context.md`, which the fork rewrote from open-pstack's auto-fire mandate into an opt-in gate, and the docs lines that describe it +- The `intake` and `diff-behavior` skills: `plugins/pstack/skills/intake/` and `plugins/pstack/skills/diff-behavior/`. Upstream has no equivalent, so they never conflict. - The lane journal: `runner/flex-journal.ts` and its test (new), its call sites in `runner/{types,run,cli}.ts` (an optional stdout callback on the model run, the journal opened after output reservation and finished on both return paths, and the `--label` flag), the journal tests in `run.test.ts`, and the pstack-flex paragraph after the invocation block in `references/provider-dispatch.md`. On a sync, keep these call sites; they change no receipt or exit status. Every upstream skill body is byte-unchanged except for the default-descriptor mentions listed above. Since [#17](https://github.com/thisguymartin/pstack-flex/issues/17), the stock matrix carries three fork-owned GPT-6 rows and the first-run sheet uses them, so those two surfaces conflict on every upstream sync and are resolved by hand: keep the fork's rows and defaults, take upstream's wording for everything else. diff --git a/UPSTREAM.md b/UPSTREAM.md index 87968c73..c9c5704f 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -45,7 +45,7 @@ No output means the tracked pstack tree has not changed. This comparison does no ## Incorporate a change -1. Create or update a GitHub issue in `ericlitman/open-pstack` and branch from current `main`. +1. Create or update a GitHub issue in `thisguymartin/pstack-flex` and branch from current `main`. 2. Read each upstream pstack commit in order. Bring over its intent and content, then apply only the Claude Code and Codex substitutions documented in `CHANGES.md`. 3. Keep one shared `plugins/pstack/skills/` tree. Put harness translation in the existing `codex-tools.md` and provider routing in `provider-dispatch.md`; do not fork a skill per harness. 4. Update the commit and version in this file, the affected provenance rows in `NOTICE.md`, and `README-UPSTREAM.md` when upstream changes it. diff --git a/docs/LANES.md b/docs/LANES.md index ca4d8d86..36156629 100644 --- a/docs/LANES.md +++ b/docs/LANES.md @@ -126,7 +126,7 @@ Quality note: this trades peak capability for cost control. The hardest-task rol ## Optional lanes -- **OpenRouter (off by default).** OpenRouter has no Anthropic-format endpoint, so a lane needs a local translator that serves `/v1/messages` — musistudio/claude-code-router or a version-pinned LiteLLM — with `ANTHROPIC_BASE_URL` pointed at it. That is one extra long-running local process, which is why it is documented rather than shipped. Expect roughly a 5.5% credit fee on top of provider list prices. If you build it, model it as another gateway provider in `flex-providers.ts`. +- **OpenRouter (not shipped).** OpenRouter documents a direct Claude Code connection (`ANTHROPIC_BASE_URL=https://openrouter.ai/api`, `ANTHROPIC_AUTH_TOKEN` from `OPENROUTER_API_KEY`, and an explicitly empty `ANTHROPIC_API_KEY`), so no local translator is needed. It guarantees that route only for Anthropic models, so DeepSeek, MiniMax, and other catalog models through OpenRouter must pass the live probes in [issue #7](https://github.com/thisguymartin/pstack-flex/issues/7) (tool call, second turn, effort, model identity) before a lane ships. If it does, model it as another gateway provider in `flex-providers.ts`. Expect a credit fee on top of provider list prices; check OpenRouter's current pricing page. - **Local via Ollama (planned).** Ollama serves an Anthropic-compatible API since v0.14, so a `local` gateway provider pointed at it is the natural next lane: full compute control, zero per-token cost, your hardware. Not wired in yet. ## Adding a gateway provider diff --git a/docs/LIVE-GATE.md b/docs/LIVE-GATE.md new file mode 100644 index 00000000..fc275573 --- /dev/null +++ b/docs/LIVE-GATE.md @@ -0,0 +1,72 @@ +# Live gate + +AGENTS.md says nothing merges, tags, releases, or rolls out until the exact candidate is installed and the changed behavior passes a live test from the real user surface in every affected harness. Unit tests, validators, and source reading do not count. This page is how to run that test and where to record it. + +There are two halves: + +1. **Local gate.** One command, runs anywhere: `bash scripts/check.sh`. It installs both Bun packages, runs their tests and strict typechecks, parses every manifest, runs the static invariants, and runs `claude plugin validate` on the marketplace and both plugins when the `claude` CLI is present. +2. **Live gate.** You, in a real Claude Code and a real Codex session, with the candidate installed. Steps below. + +## 1. Install the exact candidate + +Push the branch first, so both harnesses install the same commit. + +Claude Code: check out the branch, then add that checkout as the marketplace (inside a session): + +```text +! git clone -b https://github.com/thisguymartin/pstack-flex ~/src/pstack-flex-candidate +/plugin marketplace add ~/src/pstack-flex-candidate +/plugin install pstack@pstack-flex +/reload-plugins +``` + +Codex (shell): + +```shell +codex plugin marketplace add thisguymartin/pstack-flex --ref +codex plugin add pstack@pstack-flex +``` + +Start a new session in each harness afterwards. Record the installed version: the `pstack` version from the plugin list, plus `claude --version` and `codex --version`. + +If you had open-pstack or an older pstack-flex installed under the `open-pstack` marketplace name, remove it first so only one plugin named `pstack` is active. + +## 2. Run the checks for what changed + +Run the rows that match the change. A change that touches the runner or the model sheet runs rows A to C in both harnesses. + +| Row | Action | Pass when | +| --- | --- | --- | +| A. Opt-in gate | In a fresh session, ask for a two-line fix without naming pstack. Then ask again with "Use pstack for this." | The first request runs no `pstack:` skill. The second enters `pstack:poteto-mode`. | +| B. Setup | Run `/pstack:setup-pstack` (Claude Code) or `Use pstack:setup-pstack.` (Codex). Keep defaults or change one role. | Every assigned family probes `complete`, the sheet is written to `~/.claude/pstack-models.md` or `~/.codex/pstack-models.md`, and a failed probe writes nothing. | +| C. Mixed panel | `Use pstack:interrogate on the last commit.` | Each configured reviewer returns, external lanes write receipts with `status: complete`, and any missing CLI shows as a named dropout, not a substitute. | +| D. Gateway lane | With `DEEPSEEK_API_KEY` or `MINIMAX_API_KEY` exported, assign one role to that family in setup and run it once. | The receipt shows `status: complete`, the requested model, and `costUsd: null`. | +| E. Lane journal | `mkdir -p ~/.pstack-flex/lanes`, run one external lane (for example an interrogate with a Codex reviewer from Claude Code), then `rm -rf ~/.pstack-flex/lanes`. With [psf-monitor](https://github.com/thisguymartin/psf-monitor) installed, watch the lane on its page instead. | While it runs, the lane's directory holds `lane.json` and a growing `stream.jsonl`; after it ends, `receipt.json` matches the runner's receipt. With the directory removed, the next lane writes nothing there and its receipt is unchanged. | +| F. intake | In a scratch repo with a real issue: `Use pstack:intake for #.` | A brief appears under `.pstack/intake/`, with one playbook, an observable exit condition, and open questions when the issue is vague. No product code changes. | +| G. diff-behavior | In a scratch repo, make a branch that changes one scenario on purpose and one by accident. `Use pstack:diff-behavior on this branch.` | The report lists the accidental change as unintended and the deliberate one as intended, with evidence for both sides. | + +## 3. Record the evidence + +Paste this into the pull request under "Live evidence", one block per harness: + +```text +Harness: Claude Code | Codex +Installed: pstack @ +Row : +Observed: +Result: pass | fail +``` + +A pull request without this stays a draft. + +## Outstanding live tests + +These merged without an installed live test. Clear them with one session per harness on current `main`, then record the results in a tracking issue and tick the rows. + +| PR | Change | Rows to run | Status | +| --- | --- | --- | --- | +| #16 | GPT-6 families and first-run defaults | B, C | not run | +| #19, #20 | Opt-in gate (Claude Code and Codex) | A | not run | +| #22 | open-pstack 1.5.0 merge, setup step order, grok-4.7 pin | B, C | not run | +| #24, #25 | Lane journal (the monitor itself moved to psf-monitor in #28) | E | checkout build only, not installed | +| #26 | Rename to pstack-flex, intake, diff-behavior, doc fixes | A, B, F, G | not run | diff --git a/docs/USAGE.md b/docs/USAGE.md index 189411e1..069b85b9 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -34,15 +34,15 @@ flowchart TD Every lane is a real agent process with tools and file access. The parent harness (your Claude Code or Codex session) resolves the route once; children never pick their own models. -## Install this fork +## Install -The marketplace keeps upstream's name (`open-pstack`), so only the source changes. +The marketplace is named `pstack-flex` and carries the `pstack` plugin. If you have Eric Litman's open-pstack installed, remove it first: both ship a plugin named `pstack`, so their skills would share the `pstack:` names. Claude Code: ```text /plugin marketplace add thisguymartin/pstack-flex -/plugin install pstack@open-pstack +/plugin install pstack@pstack-flex /reload-plugins ``` @@ -50,7 +50,7 @@ Codex: ```shell codex plugin marketplace add thisguymartin/pstack-flex --ref main -codex plugin add pstack@open-pstack +codex plugin add pstack@pstack-flex ``` Plus [Bun](https://bun.sh) for the lane runner, and `multi_agent = true` under `[features]` in `~/.codex/config.toml` if Codex is your parent. Sign in only to the CLIs whose subscriptions you actually have — missing families are fine now. diff --git a/docs/reference.md b/docs/reference.md index 2f23f3df..7483874d 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,4 +1,4 @@ -# open-pstack technical reference +# pstack-flex technical reference This page contains the full skill, dependency, runtime, and porting reference. For the plain-English introduction and quick start, see the [main README](../README.md). @@ -17,8 +17,8 @@ This is not a verbatim copy. Skill bodies have been edited so every Cursor-speci This repo ships as a Claude Code marketplace containing one plugin (`pstack`). ```text -/plugin marketplace add ericlitman/open-pstack -/plugin install pstack@open-pstack +/plugin marketplace add thisguymartin/pstack-flex +/plugin install pstack@pstack-flex /reload-plugins ``` @@ -29,8 +29,8 @@ pstack runs only when you ask for it. A `SessionStart` hook on startup, `/clear` The same plugin carries a `.codex-plugin/plugin.json` manifest and a root `.agents/plugins/marketplace.json`. Install it through the Codex marketplace: ```shell -codex plugin marketplace add ericlitman/open-pstack --ref main -codex plugin add pstack@open-pstack +codex plugin marketplace add thisguymartin/pstack-flex --ref main +codex plugin add pstack@pstack-flex ``` Codex discovers the plugin skills under the `pstack` namespace, so they list as `pstack:poteto-mode`, `pstack:tdd`, and so on. The namespace comes from `plugins/pstack/.codex-plugin/plugin.json`. To enable the multi-model and parallel-subagent skills (`interrogate`, `arena`, `how`, `why`, `reflect`, `architect`), turn on subagents in `~/.codex/config.toml`: @@ -43,8 +43,8 @@ multi_agent = true For local plugin development, you can clone the repository and link its skills directly: ```shell -git clone https://github.com/ericlitman/open-pstack -cd open-pstack +git clone https://github.com/thisguymartin/pstack-flex +cd pstack-flex for s in plugins/pstack/skills/*/; do ln -s "$PWD/$s" ~/.agents/skills/"$(basename "$s")"; done ``` @@ -56,10 +56,10 @@ The marketplace install is the normal user path. Direct links are only for testi . ├── .claude-plugin/marketplace.json # Claude Code marketplace manifest (repo root) ├── .agents/plugins/marketplace.json # Codex marketplace manifest (repo root) -├── plugins/pstack/ # the plugin itself +├── plugins/pstack/ # the pstack plugin │ ├── .claude-plugin/plugin.json # Claude Code manifest │ ├── .codex-plugin/plugin.json # Codex manifest (skills: ./skills/) -│ ├── skills/ # 55 skills shared by Claude Code and Codex +│ ├── skills/ # 56 skills shared by Claude Code and Codex │ │ ├── poteto-mode/references/{codex-tools,provider-dispatch}.md # tool + provider routing │ │ └── poteto-mode/scripts/ # bun/bash/node tooling: watch-pr, orch, runner, check-plan.mjs, worktree-audit.sh │ ├── hooks/ # SessionStart opt-in gate: pstack runs only on request (Claude Code and Codex) @@ -82,13 +82,13 @@ Plugin-internal `skills//` path references in the docs below are relative The Codex build shares one `skills/` tree with the Claude Code build. Nothing is forked or generated. Two narrow references keep runtime translation separate: `codex-tools.md` maps harness primitives and `provider-dispatch.md` maps model providers. pstack otherwise keeps the upstream Claude-native prose and adds a one-line Platform note to each skill that names a Claude primitive, so the port stays in lockstep with upstream sync. - **Skill invocation.** Codex loads `SKILL.md` natively. There is no `Skill` tool. You invoke a skill by name (ask for it, or pick `pstack:poteto-mode` from the list). -- **Package surface.** The native `skills/` tree is the only workflow source. The plugin ships no `commands/` layer and does not link prompts into `~/.codex/prompts/`. Codex would migrate such files into duplicate source-command skills while loading the native skill tree. The 23 `principle-*` leaves declare `user-invocable: false`. Claude keeps them out of its user picker; Codex 0.149.0 currently shows them despite that metadata ([#8](https://github.com/ericlitman/open-pstack/issues/8)). +- **Package surface.** The native `skills/` tree is the only workflow source. The plugin ships no `commands/` layer and does not link prompts into `~/.codex/prompts/`. Codex would migrate such files into duplicate source-command skills while loading the native skill tree. The 23 `principle-*` leaves declare `user-invocable: false`. Claude keeps them out of its user picker; Codex 0.149.0 currently shows them despite that metadata ([open-pstack #8](https://github.com/ericlitman/open-pstack/issues/8)). - **Tool and built-in mapping.** Claude tool names and built-in skills resolve through [`codex-tools.md`](../plugins/pstack/skills/poteto-mode/references/codex-tools.md). Model execution resolves separately through [`provider-dispatch.md`](../plugins/pstack/skills/poteto-mode/references/provider-dispatch.md), so Codex can keep Sol native while invoking Claude and Grok externally. - **Subagents.** The `Agent` tool maps to Codex `spawn_agent` / `wait_agent`, enabled by `multi_agent = true`. Parallel fan-out is multiple `spawn_agent` calls in one turn. If the native Codex lane is unavailable, record that lane as a dropout; external Claude and Grok lanes still run, and no provider is silently substituted. There is no `poteto-agent` subagent type on Codex; route ad-hoc subagents by dispatching a `spawn_agent` told to read `poteto-mode` first. -- **Opt-in.** Codex runs the plugin's `hooks/` SessionStart hook and adds the opt-in gate to each session as a developer message (observed on Codex 0.157.1). Codex records trust for the hook in `~/.codex/config.toml` under `hooks.state`. Enter `pstack:poteto-mode` by name, or add a standing instruction to `~/.codex/AGENTS.md` if you want every non-trivial task routed into it. After a plugin update, run `codex plugin marketplace upgrade open-pstack` so the installed copy carries the current gate. +- **Opt-in.** Codex runs the plugin's `hooks/` SessionStart hook and adds the opt-in gate to each session as a developer message (observed on Codex 0.157.1). Codex records trust for the hook in `~/.codex/config.toml` under `hooks.state`. Enter `pstack:poteto-mode` by name, or add a standing instruction to `~/.codex/AGENTS.md` if you want every non-trivial task routed into it. After a plugin update, run `codex plugin marketplace upgrade pstack-flex` so the installed copy carries the current gate. - **Models.** `/setup-pstack` writes provider-qualified descriptors and asks one requested effort per assigned family (`low`, `medium`, `high`, `xhigh`, `max`). The first-run panel is Fable max, GPT-6 Astra high, Grok 4.7 xhigh, and Opus max. Fable and Opus use Claude's rolling aliases. Runtime dispatch normalizes older versioned descriptors in memory, so an installed sheet stops pinning immediately. A setup rerun persists that migration while keeping each role's family and effort. The GPT-6 Astra, Sol, and Luna Codex families are stock: GPT-6 Sol high carries `feature, refactoring`, `bug-fix`, `perf-issue`, and `hillclimb`; Luna high carries `how explorer` and `swarm workers`; Astra high sits on every panel. GPT-5.6 Sol remains a selectable family. In Codex, every Codex family uses native `spawn_agent`; Claude and Grok use the deterministic external runner. In Claude Code, Fable and Opus use native agents; the Codex families and Grok use the runner. Children never detect the parent or reroute themselves. The solo code roles stay on a Codex model instead of upstream's Fable default because it costs less for these frequent delegated code roles. -Verified in fresh installed Claude Code and Codex sessions: the user-facing skills are discovered and namespaced under `pstack`; both parents fan out the configured panel through the documented native/external route table, retain long-running handles without a default timeout, and cross-judge only after every candidate is terminal. The `principle-*` leaves remain available for `poteto-mode` to read by path. Claude honors their `user-invocable: false` metadata; Codex 0.149.0 does not ([#8](https://github.com/ericlitman/open-pstack/issues/8)). +Verified upstream in fresh installed open-pstack Claude Code and Codex sessions (pstack-flex's own live-test record is in [LIVE-GATE.md](LIVE-GATE.md)): the user-facing skills are discovered and namespaced under `pstack`; both parents fan out the configured panel through the documented native/external route table, retain long-running handles without a default timeout, and cross-judge only after every candidate is terminal. The `principle-*` leaves remain available for `poteto-mode` to read by path. Claude honors their `user-invocable: false` metadata; Codex 0.149.0 does not ([open-pstack #8](https://github.com/ericlitman/open-pstack/issues/8)). ## Dependencies @@ -137,6 +137,8 @@ The table uses the short upstream names. Claude Code exposes each native skill w | `/figure-it-out` | design a rigorous, auditable playbook for a task no bundled playbook fits | | `/show-me-your-work` | log decisions to a reviewable tsv decision trail | | `/blast-radius` | find what a change could break beyond the diff and prove safety by running code | +| `/intake` | turn GitHub issues into ready-to-run poteto-mode briefs with a playbook, exit condition, and worktree (pstack-flex) | +| `/diff-behavior` | run the same scenarios on trunk and head and classify every observable difference as intended, unintended, or noise (pstack-flex) | | `/recall` | catch up on recent working context from chat history, live state, and the shared record | | `/setup-pstack` | configure pstack per-role model choices and per-family requested effort | | `/unslop` | clean up writing by removing AI tells | diff --git a/plugins/pstack/.claude-plugin/plugin.json b/plugins/pstack/.claude-plugin/plugin.json index 59bbf654..61c3b97c 100644 --- a/plugins/pstack/.claude-plugin/plugin.json +++ b/plugins/pstack/.claude-plugin/plugin.json @@ -6,8 +6,8 @@ "author": { "name": "Lauren Tan" }, - "homepage": "https://github.com/ericlitman/open-pstack", - "repository": "https://github.com/ericlitman/open-pstack", + "homepage": "https://github.com/thisguymartin/pstack-flex", + "repository": "https://github.com/thisguymartin/pstack-flex", "license": "MIT", "keywords": [ "pstack", diff --git a/plugins/pstack/.codex-plugin/plugin.json b/plugins/pstack/.codex-plugin/plugin.json index 4bc05459..d87d532b 100644 --- a/plugins/pstack/.codex-plugin/plugin.json +++ b/plugins/pstack/.codex-plugin/plugin.json @@ -5,8 +5,8 @@ "author": { "name": "Lauren Tan" }, - "homepage": "https://github.com/ericlitman/open-pstack", - "repository": "https://github.com/ericlitman/open-pstack", + "homepage": "https://github.com/thisguymartin/pstack-flex", + "repository": "https://github.com/thisguymartin/pstack-flex", "license": "MIT", "keywords": [ "pstack", @@ -23,7 +23,7 @@ "displayName": "pstack", "shortDescription": "Rigorous, parallelizable agent workflows: go deep first, write less, verify everything", "longDescription": "pstack guides agent work through poteto-mode's principles, parallel design exploration (architect/arena), adversarial multi-model review (interrogate), root-cause debugging, prose deslopping, and verified delivery. Skills are shared with the Claude Code build; on Codex, tool names resolve via the codex-tools mapping.", - "developerName": "Lauren Tan (original), open-pstack maintainers", + "developerName": "Lauren Tan (original), pstack-flex maintainers", "category": "Developer Tools", "capabilities": [ "Interactive", @@ -34,7 +34,7 @@ "Work on this in poteto-mode.", "Interrogate this diff with multiple models." ], - "websiteURL": "https://github.com/ericlitman/open-pstack", + "websiteURL": "https://github.com/thisguymartin/pstack-flex", "brandColor": "#7C3AED" } } diff --git a/plugins/pstack/skills/diff-behavior/SKILL.md b/plugins/pstack/skills/diff-behavior/SKILL.md new file mode 100644 index 00000000..d2775e16 --- /dev/null +++ b/plugins/pstack/skills/diff-behavior/SKILL.md @@ -0,0 +1,75 @@ +--- +name: diff-behavior +description: "Run the same scenarios against trunk and head, list every observable difference in output, UI, logs, timing, and errors, and flag the ones the change didn't claim. Use for /diff-behavior, 'what did this PR change in behavior', 'prove no behavior change', a dependency bump, a migration, or a perf claim to confirm." +--- + +# Diff behavior + +A diff shows what changed in the code. This skill shows what changed in behavior, and whether all of it was intended. Both sides always run. A head-only run is not a diff. + +Companion to **blast-radius**. Blast radius proves the one fact a change is safe because of. Diff behavior drives the whole load-bearing surface on both builds and lists what differs. + +**Dispatch contract.** Scenario workers run through the **swarm** skill, which resolves `swarm workers` through [`provider-dispatch.md`](../poteto-mode/references/provider-dispatch.md). Workers never pick a model. No implicit timeout. A dropout is named by provider, model, and receipt, and never replaced. On Codex, resolve Claude tool names via [`codex-tools.md`](../poteto-mode/references/codex-tools.md). + +## Start + +Open a todolist with one entry per phase before starting. + +1. Build both sides +2. Pick scenarios +3. Run both +4. Normalize and diff +5. Classify +6. Report + +## Phase A: Build both sides + +1. Name the base (trunk by default, or the PR's base branch) and the head. Record both exact SHAs. +2. Create one worktree per side. Never use the primary checkout. +3. Build each side the same way: same command, same env, same config, same seed data. Note anything that cannot match, such as a migration that only head has. + +## Phase B: Pick scenarios + +1. Start from the project's verification skill and its feature map when one exists. When it does not, say so, and suggest the **create-verification-skill** skill as a follow-up. +2. Add scenarios from **how** on the touched surface and from every claim in the PR description or brief. +3. Keep the load-bearing scenarios even when the diff looks unrelated. Finding unexpected changes is the point. +4. Each scenario names what it captures: + + | Capture | Example | + | --- | --- | + | stdout and exit code | a CLI command | + | HTTP response | status, headers that matter, body | + | Screenshot | one UI state, compared by image diff as in the Visual parity playbook | + | Log lines | the lines a scenario emits, filtered by component | + | Metric | latency, memory, row count, with sample count and method | + | Files written | path and contents | + +5. Write the scenario set to `/scenarios.md` so it can be rerun. `` defaults to `.pstack/diff-behavior//`. + +## Phase C: Run both + +1. Run the **swarm** skill as a partition with one worker per scenario. Each worker runs base, then head, and captures both sides to `//base/` and `//head/`. Each brief names both SHAs and both worktree paths. +2. For timing scenarios, interleave base and head runs so drift hits both sides equally, and take enough samples to clear the noise (median or p95 of N, as in the Perf issue playbook). +3. Use the same seed, clock, and fixtures on both sides where the app allows it. + +## Phase D: Normalize and diff + +1. Strip what the app does not promise: timestamps, generated ids, temp paths, ordering of unordered collections. Put every rule in `/normalize.md` with its reason. +2. Diff what is left. Compare screenshots by image diff. Report metrics as base value, head value, and ratio. +3. Never compute a ratio between unlike scenarios. When base lacks the feature, record that and report head's absolute value against a stated budget instead. + +## Phase E: Classify + +Give every difference exactly one class: + +- **Intended.** A claim in the PR description or brief covers it. Cite the claim. +- **Unintended.** No claim covers it. This list is the deliverable. +- **Noise.** A normalizer gap. Fix the rule in `normalize.md` and rerun that scenario. Noise is never waved off. + +Zero unintended differences is a real result. Say so plainly. + +## Phase F: Report + +Write `/report.md` from [`references/report-template.md`](references/report-template.md). Post it to the PR only when asked. + +**Reply:** base and head SHAs, scenario count, the unintended differences first with evidence paths, then intended and the count of identical scenarios, any dropouts, and the rerun command for the scenario set. diff --git a/plugins/pstack/skills/diff-behavior/references/report-template.md b/plugins/pstack/skills/diff-behavior/references/report-template.md new file mode 100644 index 00000000..37c701ec --- /dev/null +++ b/plugins/pstack/skills/diff-behavior/references/report-template.md @@ -0,0 +1,32 @@ +# Behavior diff: + +- Base: `` () +- Head: `` () +- Scenarios: ( identical, intended, unintended) +- Scenario set: `/scenarios.md` +- Normalizer rules: `/normalize.md` + +## Unintended differences + +| Scenario | Base | Head | Difference | Evidence | +| --- | --- | --- | --- | --- | +| | | | | `//` | + +## Intended differences + +| Scenario | Base | Head | Difference | Claim it matches | Evidence | +| --- | --- | --- | --- | --- | --- | + +## Metrics + +| Scenario | Method | Base | Head | Ratio | +| --- | --- | --- | --- | --- | +| | | | | | + +## Identical + + + +## Dropouts and gaps + + diff --git a/plugins/pstack/skills/intake/SKILL.md b/plugins/pstack/skills/intake/SKILL.md new file mode 100644 index 00000000..dd46204a --- /dev/null +++ b/plugins/pstack/skills/intake/SKILL.md @@ -0,0 +1,69 @@ +--- +name: intake +description: "Turn one or more GitHub issues into ready-to-run poteto-mode briefs: read the issue and its comments, ground it in the repo with how, pick a playbook, write a brief with an observable exit condition, and prepare a worktree. Use for /intake, 'intake #41 #42', 'turn these issues into briefs', or before autopilot-stack or a batch of unattended work." +--- + +# Intake + +Every pstack run starts from a brief. Intake writes it from the issue, so the human reviews a brief instead of writing a prompt. + +Intake is read-only. It never edits product code. Launching poteto-mode on a brief is a separate, explicit step. + +**Dispatch contract.** Grounding runs `how`, which resolves its `how explorer` and `how explainer` roles through [`provider-dispatch.md`](../poteto-mode/references/provider-dispatch.md). Intake adds no route of its own. Children never pick a model. No implicit timeout and no fallback model. + +**Platform note.** Forge commands below use GitHub CLI (`gh`), the default forge in the Babysit and Shipping playbooks. On Codex, resolve Claude tool names via [`codex-tools.md`](../poteto-mode/references/codex-tools.md). + +## Start + +Open a todolist with one entry per phase, plus one entry per issue under Phase B. + +1. Collect +2. Ground and brief, per issue +3. Gate +4. Hand off + +## Phase A: Collect + +1. Resolve the repository once with `gh repo view --json nameWithOwner` and record it as ``. Pass `--repo "$repo"` to every `gh` command. +2. Read each issue in full: `gh issue view --repo "$repo" --json number,title,body,labels,comments,state,url`. Read every comment. Comments often hold the real decision ("we agreed on OIDC only"). +3. Read linked PRs and referenced issues when the body or comments point at them. A closed duplicate or a reverted PR is part of the spec. +4. Skip closed issues and say so. + +## Phase B: Ground and brief, per issue + +Run issues in parallel when there are several. Each issue gets its own grounding and its own brief. + +1. **Ground.** Run the **how** skill on the subsystem the issue names. Collect file pointers, entry points, the test command, and the project's verification skill if one exists (`.claude/skills/verify-*` or the equivalent). Keep pointers, not pasted code (the **guard-the-context-window** principle skill). +2. **Classify.** Pick exactly one poteto-mode playbook and say why in one sentence: + + | The issue asks for | Playbook | + | --- | --- | + | A defect with a symptom to reproduce | `bug-fix` | + | New or changed behavior | `feature` | + | Same behavior, different structure | `refactoring` | + | Measured slowness | `perf-issue` | + | A question, not a change | `investigation` | + | A large or cross-cutting change, or nothing above fits | the **figure-it-out** skill | + +3. **Write the brief.** Copy [`references/brief-template.md`](references/brief-template.md) to `/issue-.md` and fill every field. `` defaults to `.pstack/intake//` in the repository. Add `.pstack/` to `.git/info/exclude` so briefs stay out of commits unless the operator asks to keep them. + - The exit condition is observable: a command, a test name, a URL and expected response, or a screenshot. "Works" is not an exit condition. + - The verification plan names unit, live, and perf boxes. A box that does not apply says `n/a: `. + - Every ambiguity the issue leaves open becomes a numbered question. Do not answer product questions yourself. + - When the issue carries a repro (sample input and expected output), turn it into the failing-test candidate for the **tdd** skill and say so. + +## Phase C: Gate + +Mark each brief **ready** or **needs a human**. + +- **Ready.** Scope is clear, the exit condition is observable, and no open question changes the design. +- **Needs a human.** An open question changes what gets built, or the exit condition needs a number nobody gave (for example "make search faster" with no target). + +The **never-block-on-the-human** principle covers mechanics, not intent. Product and preference calls go to the operator. When the operator is present, ask the questions in one batch. When running unattended, post the questions as one comment on the issue with `gh issue comment --repo "$repo" --body-file `, ending with a line that says an agent wrote it, and leave the brief parked. + +## Phase D: Hand off + +1. For each **ready** brief, prepare a worktree off the default branch: `git worktree add -b issue-- /issue- origin/`. Record the path in the brief. Writers never use the primary checkout. +2. Default: stop here and return the briefs for review. +3. When the operator asked intake to run the briefs, start each one in its worktree as `Use pstack:poteto-mode. Follow the brief at .` For several ready briefs, hand the set to the Autopilot-stack playbook (`../poteto-mode/playbooks/autopilot-stack.md`) instead of starting them one by one. + +**Reply:** one row per issue: issue link, playbook, ready or needs a human, brief path, worktree path, and the open questions. Then the single next action for the operator. diff --git a/plugins/pstack/skills/intake/references/brief-template.md b/plugins/pstack/skills/intake/references/brief-template.md new file mode 100644 index 00000000..0b220304 --- /dev/null +++ b/plugins/pstack/skills/intake/references/brief-template.md @@ -0,0 +1,42 @@ +# Brief: (#) + +- Issue: +- Playbook: , because +- Status: +- Worktree: + +## Goal + + + +## Scope + +In scope: +- + +Out of scope: +- + +## Exit condition + + + +## Verification plan + +- Unit: +- Live: +- Perf: + +## Grounding + +- Entry points: +- Test command: +- Verification skill: + +## Decisions found in the thread + +- + +## Open questions + +1. diff --git a/plugins/pstack/skills/poteto-mode/references/codex-tools.md b/plugins/pstack/skills/poteto-mode/references/codex-tools.md index b7b2c9f3..68e49981 100644 --- a/plugins/pstack/skills/poteto-mode/references/codex-tools.md +++ b/plugins/pstack/skills/poteto-mode/references/codex-tools.md @@ -42,7 +42,7 @@ poteto-mode's Subagents section sets Claude-specific defaults (`subagent_type: " ## Models and providers -Do not replace every configured entry with a Codex model. `/setup-pstack` writes portable descriptors such as `claude:fable@max`, `codex:gpt-5.6-sol@max`, and `grok:grok-4.7@xhigh`. In a Codex parent, only `codex:*` is native. Route Claude and Grok descriptors through the external launcher exactly as `provider-dispatch.md` specifies. The current default panel intentionally keeps four-provider frontier diversity and contains no older GPT or Claude substitute. pstack-flex gateway descriptors (`deepseek:*`, `minimax:*`) also always route through the external launcher in a Codex parent; they are never `spawn_agent` lanes. +Do not replace every configured entry with a Codex model. `/setup-pstack` writes portable descriptors such as `claude:fable@max`, `codex:gpt-5.6-sol@max`, and `grok:grok-4.7@xhigh`. In a Codex parent, only `codex:*` is native. Route Claude and Grok descriptors through the external launcher exactly as `provider-dispatch.md` specifies. The current default panel runs four lanes across three providers (Fable and Opus are both Claude) and contains no older GPT or Claude substitute. pstack-flex gateway descriptors (`deepseek:*`, `minimax:*`) also always route through the external launcher in a Codex parent; they are never `spawn_agent` lanes. ## Claude built-in skills pstack references diff --git a/plugins/pstack/skills/poteto-mode/scripts/bun.lock b/plugins/pstack/skills/poteto-mode/scripts/bun.lock index b46f3ea9..56c665fd 100644 --- a/plugins/pstack/skills/poteto-mode/scripts/bun.lock +++ b/plugins/pstack/skills/poteto-mode/scripts/bun.lock @@ -3,7 +3,7 @@ "configVersion": 1, "workspaces": { "": { - "name": "@open-pstack/poteto-mode-tools", + "name": "@pstack-flex/poteto-mode-tools", "dependencies": { "commander": "14.0.0", }, diff --git a/plugins/pstack/skills/poteto-mode/scripts/package.json b/plugins/pstack/skills/poteto-mode/scripts/package.json index 069d0bc4..a63c436a 100644 --- a/plugins/pstack/skills/poteto-mode/scripts/package.json +++ b/plugins/pstack/skills/poteto-mode/scripts/package.json @@ -1,5 +1,5 @@ { - "name": "@open-pstack/poteto-mode-tools", + "name": "@pstack-flex/poteto-mode-tools", "private": true, "type": "module", "scripts": { diff --git a/scripts/check.sh b/scripts/check.sh new file mode 100755 index 00000000..fa873ce7 --- /dev/null +++ b/scripts/check.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Runs every local check a pull request needs before review: install, +# tests, strict typecheck, manifest parse, static +# invariants, and Claude plugin validation when the claude CLI is present. +# This is the local half of the gate. The live half is docs/LIVE-GATE.md. +set -uo pipefail + +repo="$(cd "$(dirname "$0")/.." && pwd)" +failed=() + +step() { + local name="$1"; shift + printf '\n== %s\n' "$name" + if "$@"; then + printf 'ok: %s\n' "$name" + else + printf 'FAIL: %s\n' "$name" + failed+=("$name") + fi +} + +in_dir() { (cd "$1" && shift && "$@"); } + +pkg=plugins/pstack/skills/poteto-mode/scripts +step "install" in_dir "$repo/$pkg" bun install --frozen-lockfile +step "test" in_dir "$repo/$pkg" bun run test +step "typecheck" in_dir "$repo/$pkg" bun run typecheck + +manifests=( + .claude-plugin/marketplace.json + .agents/plugins/marketplace.json + plugins/pstack/.claude-plugin/plugin.json + plugins/pstack/.codex-plugin/plugin.json +) +parse_manifests() { + local path + for path in "${manifests[@]}"; do + bun -e "JSON.parse(await Bun.file('$repo/$path').text())" || { echo "invalid JSON: $path"; return 1; } + done +} +step "manifests parse" parse_manifests +step "static invariants" env PSTACK_STATIC_ONLY=1 bash "$repo/tests/skill-collision-repro.sh" + +if command -v claude >/dev/null 2>&1; then + for target in . plugins/pstack; do + step "claude plugin validate $target" claude plugin validate "$repo/$target" + done +else + printf '\nskip: claude plugin validate (claude CLI not installed)\n' +fi + +if [ "$(id -u)" = "0" ]; then + printf '\nnote: running as root. Two runner tests that make a file unreadable with chmod fail under root; CI runs as a normal user.\n' +fi + +printf '\n' +if [ "${#failed[@]}" -eq 0 ]; then + echo "local gate: all checks passed" +else + echo "local gate: ${#failed[@]} failed" + printf ' - %s\n' "${failed[@]}" + exit 1 +fi