From f721e2e75332b198f66655db96d7c6446fc36a0e Mon Sep 17 00:00:00 2001 From: Akshay Dodeja Date: Mon, 28 Sep 2026 17:54:38 -0700 Subject: [PATCH 1/5] feat(pstack): configure models by active harness and runner --- pstack/README.md | 4 +- pstack/docs/model-routing.md | 86 +++++++++++++ pstack/skills/architect/SKILL.md | 2 +- pstack/skills/arena/SKILL.md | 13 +- pstack/skills/how/SKILL.md | 2 +- pstack/skills/interrogate/SKILL.md | 9 +- pstack/skills/poteto-mode/SKILL.md | 8 +- pstack/skills/reflect/SKILL.md | 6 +- pstack/skills/setup-pstack/SKILL.md | 183 ++++++++++++++++++---------- pstack/skills/swarm/SKILL.md | 4 +- pstack/skills/why/SKILL.md | 2 +- 11 files changed, 238 insertions(+), 81 deletions(-) create mode 100644 pstack/docs/model-routing.md diff --git a/pstack/README.md b/pstack/README.md index 6314039f9..7ec9594c8 100644 --- a/pstack/README.md +++ b/pstack/README.md @@ -8,7 +8,7 @@ there's a growing sense that ai writes too much slop code. i agree. i don't want **pstack gives you fearless parallelism.** when you can go deep on one agent and trust it to write good, verifiable code, you can truly parallelize with confidence. start multiple agents up with `poteto-mode` and trust that they'll apply rigorous engineering principles to their work. -**cursor gives you the best of all worlds.** every frontier model has its strengths and weaknesses. use any model with pstack. in fact, many of my skills use multi-model workflows to take advantage of each model's unique strengths. +**use the models your harness can actually run.** every frontier and open model has its strengths and weaknesses. pstack uses native subagents where the active harness exposes them, and confirmed external runners for read-only cross-family review when it does not. [`/setup-pstack`](./skills/setup-pstack/SKILL.md) detects that boundary instead of assuming cursor's catalog is the whole model set. fork it. improve it. make it yours. PRs are welcome! @@ -258,7 +258,7 @@ cursor already has a great plan mode which works great with pstack. but personal type [`/automate-me`](./skills/automate-me/SKILL.md). it mines your recent transcripts, drafts a `-mode` skill from how you've actually worked, and routes through pstack underneath. you keep pstack as the base and end up with your own routing skill alongside `poteto-mode`. -models are configurable too. type [`/setup-pstack`](./skills/setup-pstack/SKILL.md). it detects the models you have access to and writes a small always-applied rule mapping each role (code, judgment, the review panels) to a model. every skill reads it and falls back to sensible defaults when the rule is absent, so you override only what you want. +models are configurable too. type [`/setup-pstack`](./skills/setup-pstack/SKILL.md). it detects the active harness, confirms runnable models and runners, and writes a [harness profile](./docs/model-routing.md) mapping each role to a runner, model, and effort. every skill reads the matching profile and falls back to its existing defaults when one is absent. the cursor rule remains a compatibility export. when a default changes, a rule written before the change still pins the old default. delete those role lines, or delete the file, then run `/setup-pstack` again. a rerun keeps any role whose model differs from the default. diff --git a/pstack/docs/model-routing.md b/pstack/docs/model-routing.md new file mode 100644 index 000000000..c725e844e --- /dev/null +++ b/pstack/docs/model-routing.md @@ -0,0 +1,86 @@ +# Harness-aware model routing + +Pstack reads `~/.config/pstack/models.json` at the start of a workflow. Select the +profile for the **active harness**, identified from the tools in this session +(for example Cursor `Task`, Claude Code `Task`, Codex `spawn_agent`, or OpenCode +agents). A CLI installed on the machine does not make it the active harness. +When no matching profile exists, use the legacy Cursor rule +(`~/.cursor/rules/pstack-models.mdc`) and skill defaults **only in Cursor**. +In another harness, use native `inherit-parent` entries until setup confirms +models for that harness. Never feed Cursor model slugs to a different harness +merely because the legacy rule exists. + +The profile is a JSON object with `schemaVersion: 1` and `profiles` keyed by +`cursor`, `claude-code`, `codex`, or `opencode`. Each profile has a `budget`, a +native `fallback`, and `roles`. Every role value is an ordered array, including +single-model roles. An entry has `runner`, `model`, and `effort` fields: + +```json +{ + "schemaVersion": 1, + "profiles": { + "codex": { + "budget": "medium", + "fallback": { "runner": "native", "model": "inherit-parent", "effort": null }, + "roles": { + "feature, refactoring": [ + { "runner": "native", "model": "gpt-6-sol", "effort": "high" } + ], + "interrogate reviewers": [ + { "runner": "native", "model": "gpt-6-astra", "effort": "high" }, + { "runner": "claude-cli", "model": "opus", "effort": "high" } + ] + } + } + } +} +``` + +The example illustrates the format; setup must verify each real model and +runner before writing it. `inherit-parent` and `auto` are always valid **native** +models and omit the model override. A panel role runs one reviewer per entry; +`arena cross-judge pool` instead selects one entry, preferring a family different +from the parent when available. `swarm workers` is one default entry unless a +race explicitly names other arms. + +## Resolve an entry + +1. Prefer `native` when this harness's subagent tool accepts the chosen model. + Pass model and effort using that tool's actual schema. Codex has separate + `model` and `reasoning_effort` inputs; do not invent an effort-suffixed slug. + Cursor may encode effort in a model variant. Omit unsupported effort fields. + The consuming skills' `Task` examples may contain Cursor-only options such + as `subagent_type`, `readonly`, `environment`, and `run_in_background`; + translate their intent to the active tool's schema rather than passing + unsupported fields. +2. `claude-cli`, `codex-cli`, `cursor-cli`, and `opencode-cli` are external runners. + Use them for read-only review, investigation, or adversarial work only when + the CLI is authenticated, the model is confirmed runnable, and a read-only + mode is available. Check the installed CLI's `--help` before invoking it: + Claude Code supports print mode and plan permissions; Codex supports + `exec --sandbox read-only`; Cursor Agent supports print and plan modes; + OpenCode supports `run --agent plan`. Set model and effort/variant only with + options that CLI actually supports. Capture the result in a local artifact, + report tool failures, and do not put credentials or private data in command + arguments or logs. + Give an external reviewer only source and context approved for that provider + under the project's data rules. If a native tool cannot enforce read-only + access, use a confirmed read-only external runner or verify its checkout + remained unchanged after an explicitly no-edit native review. +3. Open-source models can use a native subagent, an authenticated OpenCode + provider, or a loaded local Codex/Ollama/LM Studio provider. A catalog entry + alone does not prove access. Record the runner that actually accepts it. +4. Code-writing roles use `native` by default. An external writer needs explicit + user selection, an isolated checkout, and a documented write boundary. + Never run multiple writers against one checkout. +5. If a configured runner or model is unavailable, say which entry failed and + use the profile's confirmed native fallback. Do not silently substitute a + different model family or claim a cross-family review occurred. + +For Codex, favor confirmed GPT models for implementation and use a confirmed +Claude, Grok, or other family for read-only review when it has a runnable entry. +For Claude Code, favor confirmed Claude models for implementation and use a +confirmed GPT, Grok, or other family for review. Cursor and OpenCode select +their native primary family from the active session. When the native subagent +tool exposes all desired families, use it for the whole panel; external CLIs +are a fallback for families absent from that tool. diff --git a/pstack/skills/architect/SKILL.md b/pstack/skills/architect/SKILL.md index 88e23ca10..e286fa44a 100644 --- a/pstack/skills/architect/SKILL.md +++ b/pstack/skills/architect/SKILL.md @@ -28,7 +28,7 @@ Skip Phase A only when the work is genuinely greenfield with no surrounding syst Run the **arena** skill with the design-sketch task and the Phase A grounding artifacts. Pass `references/runner-prompt.md` as each runner's prompt. -Take the runners from the `architect runners` line in the `pstack-models.mdc` rule, in place of the `arena runners` line. If the rule or that line is missing, use `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast`. Alias and rejected entries follow the runner rules in the **arena** skill's Phase A. +Take runners from the matching harness profile's `architect runners` entries using [model routing](../../docs/model-routing.md), in place of `arena runners`. Without a profile, use the legacy `pstack-models.mdc` line or `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast` in Cursor; in another harness use native `inherit-parent` seats. Native aliases and rejected entries follow **arena** Phase A; external writers require the same explicit selection and separate checkout. Design it twice. Require at least two structurally distinct candidates before synthesis, even when the first looks sufficient. This is the **exhaust-the-design-space** principle skill made concrete. Whole-shape alternatives, not point fixes inside one shape. diff --git a/pstack/skills/arena/SKILL.md b/pstack/skills/arena/SKILL.md index b198b9e42..72756d790 100644 --- a/pstack/skills/arena/SKILL.md +++ b/pstack/skills/arena/SKILL.md @@ -13,19 +13,22 @@ Open a todolist with one entry per phase (Frame, Fan out, Cross-judge, Pick, Gra Every candidate gets the same prompt, so the prompt is the contract. 1. State the artifact each candidate is producing. -2. Derive the rubric, 3-6 concrete gradeable criteria for what success looks like on *this* task. It is the picker's tool in Phase D. Candidates only see the task. -3. Pick the runners. Use the `arena runners` line in `~/.cursor/rules/pstack-models.mdc`. If the rule or that line is missing, default to one each on `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast`. An `auto` or `inherit-parent` entry in this line or the cross-judge line means the parent model, so omit `model` for it. If the Task tool rejects a configured entry, run that seat on its family's default and say so. Families go by prefix: `claude-*`, and `grok-*` with `cursor-grok-*` and `composer-*`. A refused `composer-*` entry runs on `grok-4.7-xhigh-fast`. With no family match, use `claude-opus-5-5-xhigh`. If it rejects a default, use the closest valid slug of the same family from its error message. Spawn more runners when the arena covers multiple design directions. Use the same model N times when the work is generation-bound rather than judgment-sensitive. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. -4. Give each candidate its own output location (a git worktree where possible, otherwise `/tmp/arena-/candidate-/`), per the **separate-before-serializing-shared-state** principle skill. +2. Derive the rubric. State what success looks like for *this* task, then turn it into 3-6 concrete gradeable criteria. The rubric is the picker's tool in Phase D. Candidates only see the task. +3. Pick the runners. First read [model routing](../../docs/model-routing.md) and use the matching harness profile's `arena runners` entries. Code-writing candidates use native subagents unless an external writer was explicitly selected with a separate checkout. With no profile, use the legacy `arena runners` line or one each on `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast` in Cursor; in another harness use native `inherit-parent` seats. An `auto` or `inherit-parent` entry omits native `model`. If a slug is rejected, report it and use a confirmed fallback. Spawn more when the arena covers multiple design directions; use the same model N times when generation matters more than independent judgment. + +Pick each subagent's reasoning level and speed for the job using the confirmed controls from the matching harness profile, per the Subagents section of **poteto-mode**. + +4. Assign output paths. Each candidate writes to its own location (a git worktree where possible, otherwise `/tmp/arena-/candidate-/`), per the **separate-before-serializing-shared-state** principle skill. ## Phase B: Fan out -Spawn all N subagents in one message with `run_in_background: true`, each with the task, the path to the shared grounding, its own output path, and instructions to produce the artifact and a short rationale naming the alternatives it considered and what it rejected. +Spawn native candidates with the active harness's subagent tool (in Cursor, one message with `run_in_background: true`). Give each the task, the path to shared grounding, its own output path, and instructions to produce both the artifact and a short rationale. Dispatch explicitly configured external candidates through their confirmed runner in separate checkouts, then drain all candidates before judging. If a candidate produces no output, proceed with N-1 and note the dropout. ## Phase C: Cross-judge -After all Phase B candidates complete, choose one model from the `arena cross-judge pool` line in `~/.cursor/rules/pstack-models.mdc`. If the rule or that line is missing, choose from `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast`. Prefer a different model family from the parent's. Spawn one readonly judge subagent on that model. It sees the rubric and the candidates by path label, scores each criterion, and recommends a base with rationale. It runs in parallel with your reading in Phase D. Don't spawn it while candidates are still writing. +After all Phase B candidates complete, choose one confirmed entry from the matching profile's `arena cross-judge pool` using [model routing](../../docs/model-routing.md), preferably a different family from the parent's. A native entry uses a readonly subagent; a confirmed external entry uses its read-only runner. With no profile, use the legacy rule or `claude-opus-5-5-xhigh` and `grok-4.7-xhigh-fast` in Cursor; in another harness use a native `inherit-parent` judge and report the lack of cross-family review. The judge sees the rubric and candidates by path label, scores each criterion, and recommends a base with rationale. It runs in parallel with the parent's reading in Phase D, not with the candidates. Don't launch it while candidates are still writing. ## Phase D: Pick a base diff --git a/pstack/skills/how/SKILL.md b/pstack/skills/how/SKILL.md index 67edc340d..1a2ac87a3 100644 --- a/pstack/skills/how/SKILL.md +++ b/pstack/skills/how/SKILL.md @@ -8,7 +8,7 @@ disable-model-invocation: true Explore the codebase to answer "how does X work?" questions. Produce architectural explanations at the level of a senior engineer onboarding onto a subsystem, enough to build a working mental model, not so much that it reads like annotated source code. -Every spawn is a Task subagent with `subagent_type: generalPurpose` and `readonly: true`. Explorers use the `how explorer` line in the `pstack-models.mdc` rule (default `grok-4.7-xhigh-fast`), and every explainer uses the `how explainer` line (default `claude-opus-5-5-xhigh`). Set `model` to that line's value, or to the default if the rule or the line is missing. Leave `model` unset when the value is `auto` or `inherit-parent`. If the Task tool rejects a slug, use the default and say so. If it rejects the default, use the closest valid slug of the same family from its error message. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. +First read [model routing](../../docs/model-routing.md) and use the matching harness profile in `~/.config/pstack/models.json` when present. A profile entry specifies runner, model, and effort; do not pass an external CLI model to Task. Without a profile, use `pstack-models.mdc` or the defaults below in Cursor; in another harness use native `inherit-parent`. Omit native `model` for `auto` or `inherit-parent`. Report rejected slugs and choose a confirmed fallback of the same family. ## 1. Assess complexity diff --git a/pstack/skills/interrogate/SKILL.md b/pstack/skills/interrogate/SKILL.md index 94946d22d..189fe54e0 100644 --- a/pstack/skills/interrogate/SKILL.md +++ b/pstack/skills/interrogate/SKILL.md @@ -24,16 +24,19 @@ Before spawning reviewers, state the intent in one clear paragraph from the user ## Step 3, Spawn Reviewers -Launch all reviewers in a single message with the Task tool, one per entry on the `interrogate reviewers` line in `~/.cursor/rules/pstack-models.mdc`, labeled Reviewer A, B, and so on to match the entry count. If the rule or that line is missing, use the table defaults. +Read [model routing](../../docs/model-routing.md) and the matching harness profile's `interrogate reviewers` entries. Use one reviewer per entry, extending or shrinking the Reviewer A/B/C labels below. Launch native reviewers together through this session's subagent tool; confirmed external reviewers use their read-only CLI runner with the same brief and rubric. Drain them together before synthesis. With no profile, use the legacy rule or table defaults through Task in Cursor; in another harness use native `inherit-parent` reviewers and report that the review is not cross-family. | Subagent | Default model | |----------|---------------| | Reviewer A | `claude-opus-5-5-xhigh` | | Reviewer B | `grok-4.7-xhigh-fast` | -Each reviewer gets `subagent_type: generalPurpose`, `readonly: true`, and `model` set to its configured entry, or its table default when there is no configured line. Omit `model` for an `auto` or `inherit-parent` entry, so that reviewer runs on the parent model. +For each legacy Cursor Task reviewer (or the active tool's equivalent): +- `subagent_type`: `generalPurpose` +- `model`: the configured `interrogate reviewers` entry, or the table default with no configured line. For an `auto` or `inherit-parent` entry, omit `model` so that reviewer runs on the parent model. +- `readonly`: `true` -If the Task tool rejects a configured entry, run that reviewer on its family's table default and say so. Families go by prefix: `claude-*`, and `grok-*` with `cursor-grok-*` and `composer-*`. A refused `composer-*` entry runs on Reviewer B's default. With no family match, use Reviewer A's default. If it rejects a table default, spawn with the closest equivalent from the valid slugs in its error message (prefer the same family and reasoning tier), and open a separate PR to update the default table. Do not block the review on the slug issue. Never treat an alias entry as a rejected slug or apply either fallback to it. +If a configured runner or model is rejected, report which seat failed and use the matching profile's confirmed fallback. With no profile, choose a confirmed Task slug of the same family from the tool's error message. Do not silently claim a different-family review occurred. Never treat `auto` or `inherit-parent` as rejected slugs. Read `references/reviewer-prompt.md` and fill in the same template for every reviewer with the stated intent, the diff or file contents, the rubric from `references/rubric.md`, and the code-quality lens from `references/code-quality-review.md`. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. diff --git a/pstack/skills/poteto-mode/SKILL.md b/pstack/skills/poteto-mode/SKILL.md index ac3d64ff0..4c2219b37 100644 --- a/pstack/skills/poteto-mode/SKILL.md +++ b/pstack/skills/poteto-mode/SKILL.md @@ -92,9 +92,13 @@ Read the leaf skill in full for any principle you apply. Each entry names when i **Use `subagent_type: "poteto-agent"` for any subagent you spawn inside a playbook step** (code-writing delegates, ad-hoc helpers). The chat that receives `/poteto-mode` runs the playbook. Never spawn a `poteto-agent` to run the playbook itself. Routed workflow skills (`how`, `why`, `interrogate`, `reflect`, `swarm`) set their own `subagent_type` for diverse-model review. Respect what the skill prescribes, don't override to `poteto-agent`. -**Defaults for every `Task` call.** `run_in_background: true`, agent mode (readonly strips MCP), file pointers not inlined context, explicit model per role (configurable via `/setup-pstack`. Defaults `grok-4.7-xhigh-fast` for code, `claude-opus-5-5-xhigh` for prose and judgment). Code delegates tier by difficulty. The hardest changes (cross-cutting design, gnarly concurrency, subtle algorithms) go to your strongest judgment model (`claude-opus-5-5-xhigh`), whether the task needs judgment on vague intent or is a precisely specified sequence of steps to execute to the letter. Trivial mechanical edits go to your fast code model. Per-role lines in the `/setup-pstack` rule override these defaults and the model choices in the routed skills (`how`, `why`, `arena`, `swarm`, `architect`, `interrogate`, `reflect`). A role with no line keeps its default, and a role line of `inherit-parent` or `auto` runs that role on the parent chat model (omit Task `model`). Each code playbook's configured model comes from its line (`feature, refactoring`, `bug-fix`, `perf-issue`, or `hillclimb`), and the hardest changes read `hardest tasks`. Prose and judgment read `judgment and prose`. +**Model routing.** Before choosing any delegate, read [model routing](../../docs/model-routing.md) and the matching harness profile in `~/.config/pstack/models.json`. A configured native entry uses this session's subagent tool and its actual model/effort schema; a confirmed external read-only entry is limited to review or investigation. Code-writing delegates stay native unless the user explicitly selected an isolated external writer. With no matching profile, use the legacy `pstack-models.mdc` rule and defaults below in Cursor; in another harness use native `inherit-parent` until configured. -**Match the model to the job.** Before each spawn, start from the role's line or default and pick the reasoning level and speed the job needs. The `/setup-pstack` budget sets each role's starting level, xhigh by default. Raise it one step, up to max, for the hardest or subtlest work. Lower it one step for judgment and two or more steps for routine work. Use fast mode only when the job is urgent, meaning CI or trunk is red or a person is blocked on the result right now. Otherwise use standard speed, the same slug without `-fast`. Verification is the exception and stays on the `swarm workers` model and speed (`grok-4.7-xhigh-fast` by default). Change only the effort level and whether the slug is fast, and keep the family the role names, so a diverse panel stays diverse. If the family has no slug at that level and speed, use its nearest slug. A role on `auto` or `inherit-parent` stays on the parent model. If the Task tool rejects the adjusted slug, do not try another adjusted slug. Use the role's line or default and say so. +**Legacy Task defaults.** `run_in_background: true`, agent mode (readonly strips MCP), file pointers not inlined context, `grok-4.7-xhigh-fast` for code, and `claude-opus-5-5-xhigh` for prose and judgment. Code delegates tier by difficulty. The hardest changes (cross-cutting design, gnarly concurrency, subtle algorithms) go to the strongest judgment model, whether the task needs judgment on vague intent or is a precisely specified sequence to execute. Trivial mechanical edits go to the fast code model. A legacy role line overrides its default; `inherit-parent` or `auto` omits Task `model`. Code playbooks read `feature, refactoring`, `bug-fix`, `perf-issue`, or `hillclimb`; the hardest changes read `hardest tasks`, and prose/judgment read `judgment and prose`. + +**Match the model to the job.** For a harness profile, use only the runner's confirmed effort and speed controls. Keep effort separate from the model ID when the tool has separate fields. The slug rules in the following paragraph apply only to legacy Cursor Task entries. + +Before each spawn, start from the role's line or default and pick the reasoning level and speed the job needs. The `/setup-pstack` budget sets each role's starting level, xhigh by default. Raise it one step, up to max, for the hardest or subtlest work. Lower it one step for judgment and two or more steps for routine work. Use fast mode only when the job is urgent, meaning CI or trunk is red or a person is blocked on the result right now. Otherwise use standard speed, the same slug without `-fast`. Verification is the exception and stays on the `swarm workers` model and speed (`grok-4.7-xhigh-fast` by default). Change only the effort level and whether the slug is fast, and keep the family the role names, so a diverse panel stays diverse. If the family has no slug at that level and speed, use its nearest slug. A role on `auto` or `inherit-parent` stays on the parent model. If the Task tool rejects the adjusted slug, do not try another adjusted slug. Use the role's line or default and say so. You own every subagent's work. Review the diff and write your own summary, don't pass through what it said. A second opinion is the same prompt against a different model. Agreement is high-signal. diff --git a/pstack/skills/reflect/SKILL.md b/pstack/skills/reflect/SKILL.md index 998ae6530..a883119a4 100644 --- a/pstack/skills/reflect/SKILL.md +++ b/pstack/skills/reflect/SKILL.md @@ -24,7 +24,9 @@ That covers the legacy flat (`.jsonl`), current nested (`/.jsonl`), One message, three `Task` calls, `subagent_type: generalPurpose`, agent mode (`readonly: false`). Reviewers need MCP access to look up the tickets, chat threads, and observability traces the transcript references, and readonly strips MCPs. -Each reviewer and the synthesizer name a role line in the `pstack-models.mdc` rule and a default. Set `model` to that line's value, or to the default if the rule or the line is missing. Leave `model` unset when the value is `auto` or `inherit-parent`. If the Task tool rejects a slug, use the default and say so. If it rejects the default, use the closest valid slug of the same family from its error message. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. +First read [model routing](../../docs/model-routing.md) and the matching harness profile. Native reviewers can launch together through this session's subagent tool. Reviewers need MCP access for context lookups (tickets, chat threads, observability traces referenced in the transcript); use an external runner only if its context is complete or the same tools are available. Otherwise use the profile's confirmed native fallback. With no profile, use the legacy three `Task` calls in Cursor; in another harness use three native `inherit-parent` reviewers. Use agent mode when readonly strips MCPs. + +Each reviewer and the synthesizer use the matching profile's role entry. Without a profile, use the legacy rule or table default in Cursor; in another harness use native `inherit-parent`. Leave native `model` unset for `auto` or `inherit-parent`. Report a rejected runner or model and use a confirmed fallback. | Lens | Role line | Default `model` | Prompt template | |---|---|---|---| @@ -36,7 +38,7 @@ Pass each template verbatim, substituting the transcript path or digest where ma ## 3. Synthesize -One `Task` call, `subagent_type: generalPurpose`, `model` from the `reflect judgment, divergent, synthesizer` line (default `claude-opus-5-5-xhigh`), agent mode (`readonly: false`). It spot-verifies citations through MCP, and readonly strips MCPs. Pass `references/synthesizer.md` verbatim, with each reviewer's full output inlined where marked. It returns an Accepted / Rejected / Backlog list. +Run one synthesizer using the matching profile's `reflect judgment, divergent, synthesizer` entry. With no profile, use the legacy Task line/default `claude-opus-5-5-xhigh` in Cursor or native `inherit-parent` elsewhere. Its quality check includes spot-verifying citations, which can require MCP access; use an external runner only with equivalent context, else the confirmed native fallback. Use `references/synthesizer.md` verbatim, with each reviewer's full output inlined where marked. The synthesizer returns a structured Accepted / Rejected / Backlog list. ## 4. Structural enforcement check diff --git a/pstack/skills/setup-pstack/SKILL.md b/pstack/skills/setup-pstack/SKILL.md index 90a9e5753..05726531c 100644 --- a/pstack/skills/setup-pstack/SKILL.md +++ b/pstack/skills/setup-pstack/SKILL.md @@ -1,74 +1,133 @@ --- name: setup-pstack -description: Configure which models pstack uses per role and at what reasoning budget. Detects your available models and writes an always-applied rule that overrides the skill defaults. Use for /setup-pstack, "configure pstack models", "pstack budget", or changing pstack's model choices. +description: Configure pstack models and reasoning budgets by active harness, including native subagents and confirmed external review runners. Use for /setup-pstack, model choices, or pstack budgets. --- # Setup pstack -Write `~/.cursor/rules/pstack-models.mdc`, an always-applied rule that sets pstack's model per role. - -## Steps - -### 1. Detect available models - -Enumerate the model slugs you can pass to a `Task` subagent in this session. That is the dependable source. If Cursor also exposes a models API or CLI that lists the user's entitled models, prefer it for completeness. If you cannot detect any, ask the user to paste the slugs they have access to. Never write a real slug you have not confirmed is available. The aliases `inherit-parent` and `auto` are always valid even though they are not detected slugs. - -### 2. Load current state - -The default role-to-model mapping is the rule shape shown in step 5 below. If `~/.cursor/rules/pstack-models.mdc` already exists, read it and treat its `# budget` line and its role values as the current choices. Otherwise start from those defaults. A line whose role is not in step 5, such as `how critics`, is from a retired role. Drop it. - -### 3. Budget, map, and confirm - -**(a) Ask for a budget.** Prefer AskQuestion over free text. Offer these four options with these exact labels, and name the current budget when the rule records one. With no rule, say that `large` matches the skill defaults. +Write a harness profile to `~/.config/pstack/models.json`. Pstack skills read +the profile matching the current harness using +[`docs/model-routing.md`](../../docs/model-routing.md). Cursor's existing +`~/.cursor/rules/pstack-models.mdc` remains a compatibility export, not the +source of truth for other harnesses. + +## 1. Detect the harness and runnable models + +Identify the active harness from the tools **available in this session**, not +from installed binaries: Cursor or Claude Code `Task`, Codex `spawn_agent`, +OpenCode agents, or another documented subagent tool. Read its tool schema for +accepted model IDs and effort inputs. If the harness is unclear, ask. + +Inventory models by **runner**, then **family** (Claude, GPT, Grok, open-source, +or another family). Prefer a native subagent when it supports the model. Check +external runners independently: + +- Cursor Agent: `cursor-agent models` when authenticated. Its list describes + Cursor access; it is not the only model source. +- Claude Code: check `claude auth status` and its current model configuration. + Confirm a selected alias through the active Task tool, a user confirmation, + or an explicitly authorized small probe; authentication alone is not proof + that every Claude alias is runnable. +- Codex: use this session's subagent tool model schema when in Codex. Else + check CLI authentication and confirm a selected CLI model before writing it. + Codex's `model` and reasoning effort are separate inputs. +- OpenCode: check `opencode auth list` and `opencode models`. The catalog is + broader than configured provider access; confirm the selected provider and + model with a user confirmation or an authorized probe. +- Local open-source: check loaded models through Ollama, LM Studio, or the + configured local provider when available. A binary or downloaded catalog is + not proof that a model is loaded and runnable. + +Classify each candidate as **confirmed native**, **confirmed external**, or +**catalog-only/unverified**. Only confirmed models may be written. The native +aliases `inherit-parent` and `auto` are always valid. Never expose credentials +while discovering models, and do not send a model prompt just to list models. + +## 2. Load current choices + +Read the matching harness profile in `~/.config/pstack/models.json`, if any. +Preserve profiles for other harnesses. If this profile does not exist, read the +legacy Cursor rule when present and treat its role values as candidates, not +proof that those models work in this harness. Drop retired roles such as +`how critics` and report them. + +## 3. Choose a budget + +Ask the user to select one of these exact labels, naming the current budget +when one exists: - `unlimited — max reasoning` - `large — xhigh reasoning` - `medium — high reasoning` - `small — medium reasoning` -**(b) Apply it.** Build the working table from the skill defaults, and on a re-run keep any role you changed by family, list, or alias (`inherit-parent`, `auto`). `unlimited`, `large`, `medium`, and `small` set the effort token of every real slug, panel entries included, to `max`, `xhigh`, `high`, or `medium`. The effort token is the last token, or the one before a trailing `fast`, on the ladder `max` > `xhigh` > `high` > `medium` > `low`. If the result is not a detected slug, use the same family's detected slug with the highest effort at or below the target, else mark the role as needing a choice. `inherit-parent` and `auto` do not change. So `unlimited` turns `claude-opus-5-5-xhigh` into `claude-opus-5-5-max`. Grok slugs top out at `xhigh`, so under `unlimited` the fallback puts Grok at `xhigh` and keeps `grok-4.7-xhigh-fast` as it is. `large` keeps both defaults. `small` turns them into `claude-opus-5-5-medium` and `grok-4.7-medium-fast`. - -**(c) Show the roles and confirm.** Show every role with its model, marking any real slug not in the detected set as needing a choice. Also list each line step 2 dropped. Ask whether to accept as-is or change specific roles, offering the detected models plus `inherit-parent` and `auto` (both mean: this role runs on the parent chat model, which is how Auto users stay on Auto) as the options. Prefer AskQuestion over free text. For panel roles (arena runners, architect runners, interrogate reviewers) the value is a list, and one subagent runs per entry, alias entries included, so the list length sets the count. `arena cross-judge pool` is also a list, but Arena selects one value from it whose model family differs from the parent's when possible. `swarm workers` is the default model for every worker unless a race or comparison assigns another model per arm. - -### 4. Validate - -Every real slug written must be in the detected set. `inherit-parent` and `auto` always pass. If a chosen real slug is not available, stop and ask again. - -### 5. Write the rule - -Write `~/.cursor/rules/pstack-models.mdc` with `alwaysApply: true`, a `# budget` line with the chosen label and its target effort, and one line per role, using the same labels poteto-mode uses. Overwrite the whole file so re-runs stay idempotent. Shape: - -``` ---- -description: pstack per-role model choices (overrides skill defaults) -alwaysApply: true ---- -# pstack model configuration. One line per role. Delete a line to fall back to the skill default. -# `inherit-parent` or `auto` as a value: the role runs on the parent chat model (omit Task `model`). Alias entries in a panel list still count toward its fan-out. -# budget: large (xhigh) -feature, refactoring: grok-4.7-xhigh-fast -bug-fix: grok-4.7-xhigh-fast -perf-issue: grok-4.7-xhigh-fast -hillclimb: grok-4.7-xhigh-fast -judgment and prose: claude-opus-5-5-xhigh -hardest tasks: claude-opus-5-5-xhigh -how explorer: grok-4.7-xhigh-fast -how explainer: claude-opus-5-5-xhigh -why investigators: grok-4.7-xhigh-fast -why synthesizer: claude-opus-5-5-xhigh -reflect tooling: grok-4.7-xhigh-fast -reflect judgment, divergent, synthesizer: claude-opus-5-5-xhigh -arena runners: claude-opus-5-5-xhigh, grok-4.7-xhigh-fast -arena cross-judge pool: claude-opus-5-5-xhigh, grok-4.7-xhigh-fast -swarm workers: grok-4.7-xhigh-fast -architect runners: claude-opus-5-5-xhigh, grok-4.7-xhigh-fast -interrogate reviewers: claude-opus-5-5-xhigh, grok-4.7-xhigh-fast -``` - -### 6. Confirm - -Tell the user the rule was written and that it applies to new sessions. Re-running this skill updates it. - -### 7. Offer a verification skill (optional) - -Check whether the project has a way to drive the real app for proof (a `verify-*` skill, or an existing harness). If not, offer once: "want a project-local verification skill, so agents can drive the app the way a user does and prove changes work? I can generate one with /create-verification-skill." On yes, invoke `/create-verification-skill` (resolves wherever pstack is installed: workspace, user, or plugin). On no, move on without pushing. +Budget targets apply to each runner's actual effort control, not by blindly +appending a suffix to a model name. For a native tool with a separate effort +field, keep the model ID and set that field. For effort-encoded variants, choose +the highest confirmed variant at or below the target. For a CLI with a variant +or effort option, use only confirmed options. If a runner has no effort +control, mark its entry unbudgeted in the preview and ask whether to keep it. +`inherit-parent` and `auto` keep the parent model and effort. + +## 4. Build a harness-aware proposal + +Primary coding roles favor the **active harness's native model family** unless +the user chose otherwise. On Codex, prefer confirmed GPT models for primary +work; on Claude Code, confirmed Claude models; on Cursor or OpenCode, the +confirmed family selected for that session. Use a confirmed different family +for review and adversarial roles when it is runnable. If the native subagent +tool exposes all desired families, use it. Otherwise use a confirmed external +read-only runner for review, as described in `docs/model-routing.md`. Never +present a catalog-only model as an available reviewer. + +Use these exact role labels. Single-model roles get one entry; panel roles get +one entry per reviewer. The `arena cross-judge pool` lists candidates from +which Arena selects **one** different-family judge when possible. + +| Role group | Labels | +| --- | --- | +| Coding | `feature, refactoring`; `bug-fix`; `perf-issue`; `hillclimb`; `swarm workers` | +| Judgment | `judgment and prose`; `hardest tasks`; `how explainer`; `why synthesizer`; `reflect judgment, divergent, synthesizer` | +| Investigation | `how explorer`; `why investigators`; `reflect tooling` | +| Panels | `arena runners`; `arena cross-judge pool`; `architect runners`; `interrogate reviewers` | + +Write-capable roles use native subagents by default. External writers require +explicit user selection and an isolated checkout. Respect an existing +confirmed custom family, list length, or alias on a re-run. Do not replace it +merely because another family's default changed. + +## 5. Show, confirm, and validate + +Show **every role** with runner, model, effort, family, and detection evidence. +Show panel entries individually so the fan-out count is clear. Mark every +unverified entry as needing a choice, list retired lines dropped, and ask the +user to accept or change specific roles. Offer confirmed native and external +models plus `inherit-parent` and `auto`. Prefer structured questions over an +open-ended prompt. + +Before writing, validate that every real model is confirmed for its runner, +every external reviewer has a read-only invocation path, every effort value is +supported, and the user's budget and role choices are recorded. If anything +fails, keep the existing configuration and ask for the missing choice. + +## 6. Write the profile + +Write or update **only this harness** in `~/.config/pstack/models.json` using +the schema in `docs/model-routing.md`; preserve other profiles. Validate the +result with a JSON parser and read it back. If the active harness is Cursor, +also write `~/.cursor/rules/pstack-models.mdc` with `alwaysApply: true`, a +`# budget` line, and the same role labels. Put confirmed native Task model +slugs there; represent external-only entries with the safe native fallback and +note that the portable profile supplies the external runner. Never write an +unverified slug to either file. + +Tell the user which profile was written, the selected budget, runner families, +and what will happen if a reviewer is unavailable. The profile applies to new +sessions; re-running `/setup-pstack` updates it. + +## 7. Optional verification skill + +If the project has no existing way to drive the real app for proof (such as a +`verify-*` skill or browser harness), offer once to create a project-local +verification skill with `/create-verification-skill`. If one already exists, +skip the offer. diff --git a/pstack/skills/swarm/SKILL.md b/pstack/skills/swarm/SKILL.md index ed99acb98..0b7e1e6a8 100644 --- a/pstack/skills/swarm/SKILL.md +++ b/pstack/skills/swarm/SKILL.md @@ -22,12 +22,12 @@ Open a todolist with one entry per phase before launching anything. 1. State the done predicate and the artifact or report the swarm must return. 2. Choose the shape. Partition into slices, race N workers on identical briefs, or mix both. For a race or mixed shape, declare `first pass`, `rank all`, or `best-of` before spawning. 3. Set N from the user or derive it from the shape. N is total workers, not the cloud concurrency limit. -4. Pick the worker model from the `swarm workers` line in `~/.cursor/rules/pstack-models.mdc`. If the rule or that line is missing, use `grok-4.7-xhigh-fast`. For `auto` or `inherit-parent`, omit `model` so the workers run on the parent model. If the Task tool rejects a slug, use the default and say so. If it rejects the default, use the closest valid slug of the same family from its error message. For a model race, name each arm's model up front. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. +4. Pick the worker entry from the matching harness profile using [model routing](../../docs/model-routing.md). Writers use native subagents unless the user explicitly selected isolated external writers. With no profile, use the legacy `swarm workers` line or `grok-4.7-xhigh-fast` in Cursor; in another harness use native `inherit-parent`. For `auto` or `inherit-parent`, omit native `model`. Report rejected slugs and use a confirmed fallback. For a model race, name each arm's runner and model up front. 5. Give each worker its own writable output when it writes. When workers verify or measure commits, each brief names the exact SHAs. A measurement brief also names the method (sample count, what one sample is, order). The worker records both in its result. ## Phase B: Fan out -Spawn all N workers in one message with `subagent_type: generalPurpose`, `environment: "cloud"`, `run_in_background: true`, and the step 4 model, left unset for `auto` or `inherit-parent`. Use `environment: "local"` only when the worker needs access to something on the user's computer. +Spawn native workers with the active harness's subagent tool. In Cursor, use one message with `subagent_type: generalPurpose`, `environment: "cloud"`, and `run_in_background: true`, leaving `model` unset for `auto` or `inherit-parent`; use `environment: "local"` only when computer access is needed. An explicitly selected external worker uses its confirmed runner and its own checkout; drain it with the native workers before ranking results. When a worker must start from a non-default pushed branch, pass `cloud_base_branch`. diff --git a/pstack/skills/why/SKILL.md b/pstack/skills/why/SKILL.md index b5fe93f8b..b678d1185 100644 --- a/pstack/skills/why/SKILL.md +++ b/pstack/skills/why/SKILL.md @@ -10,7 +10,7 @@ Investigate the motivation and intent behind code. The companion `how` skill ans Each spawn below names a role line in the `pstack-models.mdc` rule and a default. Set `model` to that line's value, or to the default if the rule or the line is missing. Leave `model` unset when the value is `auto` or `inherit-parent`. If the Task tool rejects a slug, use the default and say so. If it rejects the default, use the closest valid slug of the same family from its error message. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. -Every spawn is `generalPurpose` with `readonly: false` (agent mode). **Do not use readonly/Ask mode.** It strips MCP access, which disables the MCP-backed investigators and the synthesizer's citation spot-checks. Investigators still shouldn't write anything. +First read [model routing](../../docs/model-routing.md) and use the matching harness profile in `~/.config/pstack/models.json` when present. A profile entry specifies runner, model, and effort; do not pass an external CLI model to Task. Without a profile, use `pstack-models.mdc` or the defaults below in Cursor; in another harness use native `inherit-parent`. Omit native `model` for `auto` or `inherit-parent`. Report rejected slugs and choose a confirmed fallback of the same family. ## Operating Posture From d4d1e656b0668d67ea5d42efcd8e61e042f24079 Mon Sep 17 00:00:00 2001 From: Sirine Jnayeh Date: Wed, 14 Oct 2026 20:59:24 +0400 Subject: [PATCH 2/5] feat(pstack): support Claude Code as a harness Package pstack as a Claude Code plugin and make the skills work there without changing Cursor behavior. Cursor fields, paths, and agent names stay as written; a single Harness reference in docs/model-routing.md translates them for other harnesses (subagent fields, agent frontmatter, plugin and skill paths, transcript locations and slugs). - Add pstack/.claude-plugin/plugin.json and a pstack marketplace entry. - poteto-agent: add background: true and the Claude Code plugin root; poteto-mode passes delegates the absolute SKILL.md path. - Point transcript, skill-path, and subagent-field instructions at the Harness reference. - worktree-audit.sh also reads Claude Code transcripts. - README: Claude Code install and /pstack: prefix; benny stays Cursor-only. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 5 ++ pstack/.claude-plugin/plugin.json | 21 +++++++ pstack/README.md | 11 +++- pstack/agents/poteto-agent.md | 3 +- pstack/docs/model-routing.md | 61 ++++++++++++++++++- pstack/skills/arena/SKILL.md | 2 +- pstack/skills/automate-me/SKILL.md | 6 +- .../skills/create-verification-skill/SKILL.md | 2 +- pstack/skills/interrogate/SKILL.md | 2 +- .../maintain-verification-skill/SKILL.md | 2 +- pstack/skills/no-comments/SKILL.md | 2 +- pstack/skills/poteto-help/SKILL.md | 4 +- pstack/skills/poteto-mode/SKILL.md | 2 +- pstack/skills/poteto-mode/playbooks/eval.md | 2 +- .../poteto-mode/playbooks/multi-phase-plan.md | 2 +- .../poteto-mode/playbooks/orchestrate.md | 2 +- .../poteto-mode/playbooks/session-pickup.md | 2 +- .../poteto-mode/scripts/worktree-audit.sh | 14 +++-- pstack/skills/recall/SKILL.md | 2 +- pstack/skills/reflect/SKILL.md | 4 +- .../reflect/references/divergent-reviewer.md | 2 +- .../reflect/references/judgment-reviewer.md | 2 +- .../reflect/references/tooling-reviewer.md | 2 +- pstack/skills/show-me-your-work/SKILL.md | 2 +- pstack/skills/swarm/SKILL.md | 2 +- pstack/skills/why/SKILL.md | 2 +- 26 files changed, 130 insertions(+), 33 deletions(-) create mode 100644 pstack/.claude-plugin/plugin.json diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 8d18083d7..d1562a0db 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,6 +9,11 @@ "name": "origin-apps", "source": "./origin-apps", "description": "Skills for building on the Cursor Origin API. Fetch the live spec first, then follow the Origin rules for credentials, scopes, webhooks, paging, and errors. Includes a skill that plans the port of an existing GitHub App." + }, + { + "name": "pstack", + "source": "./pstack", + "description": "if you want to go fast, go deep first. pstack helps you write less, but higher quality code. rigorous agent workflows you can parallelize with confidence." } ] } diff --git a/pstack/.claude-plugin/plugin.json b/pstack/.claude-plugin/plugin.json new file mode 100644 index 000000000..fa6c5d408 --- /dev/null +++ b/pstack/.claude-plugin/plugin.json @@ -0,0 +1,21 @@ +{ + "name": "pstack", + "description": "if you want to go fast, go deep first. pstack helps you write less, but higher quality code. rigorous agent workflows you can parallelize with confidence.", + "version": "0.15.23", + "author": { + "name": "Lauren Tan" + }, + "homepage": "https://github.com/cursor/plugins/tree/main/pstack", + "repository": "https://github.com/cursor/plugins", + "license": "MIT", + "keywords": [ + "pstack", + "poteto-mode", + "workflow", + "principles", + "agent-style", + "subagents", + "unslop" + ], + "skills": "./skills/" +} diff --git a/pstack/README.md b/pstack/README.md index 7ec9594c8..dea2d710a 100644 --- a/pstack/README.md +++ b/pstack/README.md @@ -18,6 +18,15 @@ fork it. improve it. make it yours. PRs are welcome! /add-plugin pstack ``` +in claude code: + +```bash +/plugin marketplace add cursor/plugins +/plugin install pstack@cursor-plugins +``` + +claude code prefixes plugin commands and agents, so `/poteto-mode` is `/pstack:poteto-mode`. the [harness reference](./docs/model-routing.md#harness-reference) lists every other difference. + ## get started two steps: @@ -266,7 +275,7 @@ when a default changes, a rule written before the change still pins the old defa pstack also ships a dormant [benny automation pack](./automations/benny/). benny triages slack issue reports, then reproduces and fixes confirmed bugs with real ui evidence. its files are not registered as slash skills. -to set it up, point cursor at [`FOR_AGENTS.md`](./automations/benny/FOR_AGENTS.md). setup copies the pack into the target repository at `.cursor/automations/benny/`, enables pstack there for shared skills, and keeps user configuration outside the copied pack. +to set it up, point cursor at [`FOR_AGENTS.md`](./automations/benny/FOR_AGENTS.md). setup copies the pack into the target repository at `.cursor/automations/benny/`, enables pstack there for shared skills, and keeps user configuration outside the copied pack. benny runs on cursor automations, so it is cursor-only. ## license diff --git a/pstack/agents/poteto-agent.md b/pstack/agents/poteto-agent.md index e1d2df2e8..5a0fc6a9e 100644 --- a/pstack/agents/poteto-agent.md +++ b/pstack/agents/poteto-agent.md @@ -2,8 +2,9 @@ name: poteto-agent description: Delegate subagent for code-writing and helper tasks spawned during a `/poteto-mode` run. Use for delegates, not as the runner for `/poteto-mode` itself. Spawn a fresh `poteto-agent` for each new task, and resume one only in the strict cases that poteto-mode's Subagents section names. Reads the `poteto-mode` skill's `SKILL.md` in full before any work, including its inline Principles index. Substituting `generalPurpose` skips that read and drifts. is_background: true +background: true --- # Poteto subagent -You are operating as poteto-mode's full agent style. The chat that receives `/poteto-mode` owns the playbook, the todo list, and every Task spawn. You are one of its delegates. Read the `poteto-mode` skill's `SKILL.md` in full before doing any work, including its inline Principles index. Use the absolute path your parent gave you. With no path, before any other work, search `~/.cursor/plugins/` for a file whose path ends in `skills/poteto-mode/SKILL.md`. If more than one file matches, use the copy whose `.cursor-plugin/plugin.json` has the highest `version`. Your skill catalog hides this skill, so a missing catalog entry does not mean pstack is absent. If no such file exists, stop and tell your parent. Navigate to a leaf `principle-*` skill whenever you apply that principle. +You are operating as poteto-mode's full agent style. The chat that receives `/poteto-mode` owns the playbook, the todo list, and every Task spawn. You are one of its delegates. Read the `poteto-mode` skill's `SKILL.md` in full before doing any work, including its inline Principles index. Use the absolute path your parent gave you. With no path, before any other work, search `~/.cursor/plugins/` for a file whose path ends in `skills/poteto-mode/SKILL.md`. If more than one file matches, use the copy whose `.cursor-plugin/plugin.json` has the highest `version`. In another harness, search that harness's plugin install root and manifest from the Harness reference in pstack's `docs/model-routing.md` instead (Claude Code: `~/.claude/plugins/` and `.claude-plugin/plugin.json`). Your skill catalog hides this skill, so a missing catalog entry does not mean pstack is absent. If no such file exists, stop and tell your parent. Navigate to a leaf `principle-*` skill whenever you apply that principle. diff --git a/pstack/docs/model-routing.md b/pstack/docs/model-routing.md index c725e844e..1720ecb37 100644 --- a/pstack/docs/model-routing.md +++ b/pstack/docs/model-routing.md @@ -50,9 +50,10 @@ race explicitly names other arms. `model` and `reasoning_effort` inputs; do not invent an effort-suffixed slug. Cursor may encode effort in a model variant. Omit unsupported effort fields. The consuming skills' `Task` examples may contain Cursor-only options such - as `subagent_type`, `readonly`, `environment`, and `run_in_background`; - translate their intent to the active tool's schema rather than passing - unsupported fields. + as `subagent_type`, `readonly`, `environment`, and `run_in_background`. + In Cursor, pass them as written. In another harness, translate them with + [Harness reference](#harness-reference) rather than passing unsupported + fields. 2. `claude-cli`, `codex-cli`, `cursor-cli`, and `opencode-cli` are external runners. Use them for read-only review, investigation, or adversarial work only when the CLI is authenticated, the model is confirmed runnable, and a read-only @@ -84,3 +85,57 @@ confirmed GPT, Grok, or other family for review. Cursor and OpenCode select their native primary family from the active session. When the native subagent tool exposes all desired families, use it for the whole panel; external CLIs are a fallback for families absent from that tool. + +## Harness reference + +Skills and agents are written with Cursor's names, fields, and paths. In +Cursor, use them exactly as written. In another harness, translate each one +with the tables below. Drop a field with no row here and say you dropped it; +never invent a field or value the active tool's schema does not accept. + +### Subagent fields + +| Cursor | Claude Code | +| --- | --- | +| `subagent_type: generalPurpose` | `subagent_type: "general-purpose"` | +| `subagent_type: poteto-agent`, `comment-sicko`, or another pstack agent | Prefix the plugin name: `pstack:poteto-agent`, `pstack:comment-sicko` | +| `readonly: true` | `subagent_type: "Explore"`. It denies `Write` and `Edit` but keeps shell access, so also instruct no edits and confirm the checkout is unchanged afterward. | +| `readonly: false` (for MCP access) | `general-purpose`, which inherits the session's MCP servers | +| `environment: "cloud"` | `isolation: "remote"` when the tool offers it, else `isolation: "worktree"`. A worktree branches from the default branch, not the parent's `HEAD`, so tell the subagent which branch or commit to check out. | +| `environment: "local"` | Omit the field. | +| `run_in_background: true` | Omit the field. Claude Code runs subagents in the background in interactive sessions. | +| Effort-suffixed model slug, such as `claude-opus-5-5-xhigh` | Separate `model` and `effort` (`low` through `max`). The call's `model` accepts only the aliases `opus`, `sonnet`, `haiku`, and `fable`. | +| `inherit-parent` or `auto` | Omit `model`. Never pass `inherit` on a call; only agent frontmatter accepts it. | + +### Agent frontmatter + +Claude Code ignores frontmatter keys it does not recognize, so an agent file +carries both harnesses' keys side by side. + +| Cursor | Claude Code | +| --- | --- | +| `is_background: true` | `background: true` | +| `readonly: true` | `disallowedTools: Write, Edit`. Plugin agents ignore `permissionMode`. | +| `model: inherit` | `model: inherit` | + +### Paths and names + +| | Cursor | Claude Code | +| --- | --- | --- | +| Plugin install root | `~/.cursor/plugins/` | `~/.claude/plugins/` | +| Installed plugin manifest | `.cursor-plugin/plugin.json` | `.claude-plugin/plugin.json` | +| Project skills | `.cursor/skills/` | `.claude/skills/` | +| User skills | `~/.cursor/skills/` | `~/.claude/skills/` | +| Slash command | `/poteto-mode` | `/pstack:poteto-mode` | +| Transcript directory | `~/.cursor/projects//agent-transcripts/`, named in the system prompt | `~/.claude/projects//`, not named in the system prompt | +| Transcript file | `/.jsonl` | `.jsonl`; subagents under `/subagents/agent-.jsonl` | +| Workspace slug | Workspace path without the leading `/`, with each `/` turned into `-` | Workspace path with each `/` and `.` turned into `-`, keeping the leading `-` | +| Slug example for `/Users/you/proj` | `Users-you-proj` | `-Users-you-proj` | + +In Claude Code, the current session's transcript is the most recently modified +`.jsonl` directly under the workspace's project directory. Claude Code deletes +transcripts after `cleanupPeriodDays` (30 days by default). As in Cursor, read +only the active workspace's directory; never glob across every project. + +Cursor Automations (`automations/`) have no Claude Code equivalent and stay +Cursor-only. diff --git a/pstack/skills/arena/SKILL.md b/pstack/skills/arena/SKILL.md index 72756d790..1d888b927 100644 --- a/pstack/skills/arena/SKILL.md +++ b/pstack/skills/arena/SKILL.md @@ -22,7 +22,7 @@ Pick each subagent's reasoning level and speed for the job using the confirmed c ## Phase B: Fan out -Spawn native candidates with the active harness's subagent tool (in Cursor, one message with `run_in_background: true`). Give each the task, the path to shared grounding, its own output path, and instructions to produce both the artifact and a short rationale. Dispatch explicitly configured external candidates through their confirmed runner in separate checkouts, then drain all candidates before judging. +Spawn native candidates with the active harness's subagent tool (in Cursor, one message with `run_in_background: true`; in another harness, translate per the Harness reference in [model routing](../../docs/model-routing.md#harness-reference)). Give each the task, the path to shared grounding, its own output path, and instructions to produce both the artifact and a short rationale. Dispatch explicitly configured external candidates through their confirmed runner in separate checkouts, then drain all candidates before judging. If a candidate produces no output, proceed with N-1 and note the dropout. diff --git a/pstack/skills/automate-me/SKILL.md b/pstack/skills/automate-me/SKILL.md index 50971b894..16ae73fd1 100644 --- a/pstack/skills/automate-me/SKILL.md +++ b/pstack/skills/automate-me/SKILL.md @@ -14,7 +14,7 @@ This skill orchestrates three others: an inline mining pass (see step 1), Cursor ### 0. Check for an existing skill -Look recursively for `.cursor/skills/**/*-mode/SKILL.md` and `~/.cursor/skills/*-mode/SKILL.md` matching the user's handle. Mode skills can live in a personal category directory (`.cursor/skills//`), not only at the top level. If one exists, confirm intent with `AskQuestion` (unless they already said "update my skill" or similar): +Look recursively for `.cursor/skills/**/*-mode/SKILL.md` and `~/.cursor/skills/*-mode/SKILL.md` matching the user's handle. Mode skills can live in a personal category directory (`.cursor/skills//`), not only at the top level. In another harness, search that harness's project and user skill directories from the Harness reference in [model routing](../../docs/model-routing.md#harness-reference) (Claude Code: `.claude/skills/` and `~/.claude/skills/`). If one exists, confirm intent with `AskQuestion` (unless they already said "update my skill" or similar): - Update the existing skill (default for repeat runs) - Start fresh (rare, ask why before doing it) @@ -26,7 +26,7 @@ Update mode changes the rest of the flow: ### 1. Mine their history -Locate the active workspace's transcripts before fanning out. The system prompt names the workspace's `agent-transcripts/` directory. Use only that path. Don't glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. +Locate the active workspace's transcripts before fanning out. The system prompt names the workspace's `agent-transcripts/` directory. Use only that path. Don't glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. In a harness whose system prompt names no transcript directory, locate it with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference), under the same rule. Survey recent agent conversations within that scope for recurring patterns. Run multiple parallel subagents across slices of history (e.g. last 2-4 weeks, split into 3 slices so each has enough material). Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. Each slice mining subagent reads transcripts from the workspace-scoped path the parent provides, looks for the signals below, and returns a short structured list of patterns it saw with evidence pointers. Default signals worth hunting: @@ -66,7 +66,7 @@ The **poteto-mode** skill shows the shape. Read it for granularity. Don't copy i Use Cursor's built-in `create-skill` skill to author the skill. Placement: -- Path: preserve an existing mode skill's category. For a new mode, use `.cursor/skills//-mode/SKILL.md` when the repo has an established personal category for that handle. Otherwise default to `.cursor/skills/-mode/SKILL.md` in the project (or `~/.cursor/skills/-mode/` if the user prefers a personal skill). +- Path: preserve an existing mode skill's category. For a new mode, use `.cursor/skills//-mode/SKILL.md` when the repo has an established personal category for that handle. Otherwise default to `.cursor/skills/-mode/SKILL.md` in the project (or `~/.cursor/skills/-mode/` if the user prefers a personal skill). In another harness, use its skill directories in place of `.cursor/skills/` and `~/.cursor/skills/`. - Handle: the user's first name or chosen identifier. - Frontmatter `description`: trigger on their name + `/-mode` + "work in their style", not on generic keywords like "write code" or "review PR". - Frontmatter formatting: follow `create-skill`'s YAML rules. Keep `description` as one YAML scalar. Quote it or use `description: >-` with indented continuation lines when punctuation or wrapping requires it. diff --git a/pstack/skills/create-verification-skill/SKILL.md b/pstack/skills/create-verification-skill/SKILL.md index 140d033a0..72e491ef4 100644 --- a/pstack/skills/create-verification-skill/SKILL.md +++ b/pstack/skills/create-verification-skill/SKILL.md @@ -22,7 +22,7 @@ If the checkout doesn't build or start as-is, fix that first (or report it preci ## 2. Generate the skill -Write `.cursor/skills/verify-/SKILL.md` with YAML frontmatter (`name: verify-` and a `description` that names the app, the surface, and when to reach for it — without frontmatter the skill never registers) and these sections, each grounded in what the interview actually found (no placeholders left): +Write `.cursor/skills/verify-/SKILL.md` with YAML frontmatter (`name: verify-` and a `description` that names the app, the surface, and when to reach for it — without frontmatter the skill never registers) and these sections, each grounded in what the interview actually found (no placeholders left). In another harness, write under its project skill directory from the Harness reference in [model routing](../../docs/model-routing.md#harness-reference) (Claude Code: `.claude/skills/verify-/`) here and in every `.cursor/skills/verify-/` path below: - **Launch:** the exact command that starts the app for verification, and how to tell it's ready (a log line, a prompt). Launch must reach a usable state from an empty data dir, including any migrations and seed data. Ready means usable, not just that a process answers. A database health check can pass while its init scripts are still running. Include teardown. For a short-lived CLI or TUI there is no server to keep alive: launch means build the binary (or install deps) once, then start each drive in its own isolated PTY or tmux session. - **Doctor:** one read-only check that answers "is this instance worth driving?" — process up, right version/build, port owned by us, auth valid. An agent runs this first whenever anything looks off. diff --git a/pstack/skills/interrogate/SKILL.md b/pstack/skills/interrogate/SKILL.md index 189fe54e0..8839c65c0 100644 --- a/pstack/skills/interrogate/SKILL.md +++ b/pstack/skills/interrogate/SKILL.md @@ -31,7 +31,7 @@ Read [model routing](../../docs/model-routing.md) and the matching harness profi | Reviewer A | `claude-opus-5-5-xhigh` | | Reviewer B | `grok-4.7-xhigh-fast` | -For each legacy Cursor Task reviewer (or the active tool's equivalent): +For each legacy Cursor Task reviewer (in another harness, translate these fields with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference)): - `subagent_type`: `generalPurpose` - `model`: the configured `interrogate reviewers` entry, or the table default with no configured line. For an `auto` or `inherit-parent` entry, omit `model` so that reviewer runs on the parent model. - `readonly`: `true` diff --git a/pstack/skills/maintain-verification-skill/SKILL.md b/pstack/skills/maintain-verification-skill/SKILL.md index a2680b91f..d8732c09d 100644 --- a/pstack/skills/maintain-verification-skill/SKILL.md +++ b/pstack/skills/maintain-verification-skill/SKILL.md @@ -22,7 +22,7 @@ Only edit the verification skill's own directory (its SKILL.md, features/, and a ## Pass -0. **Locate the target.** Find the verification skill to maintain: the project-local skill whose body has launch/drive sections and a feature map (usually `.cursor/skills/verify-*/`). Several candidates → ask which one; none → stop and point at `/create-verification-skill` instead of inventing a target. +0. **Locate the target.** Find the verification skill to maintain: the project-local skill whose body has launch/drive sections and a feature map (usually `.cursor/skills/verify-*/`; in another harness, its project skill directory from the Harness reference in [model routing](../../docs/model-routing.md#harness-reference), such as `.claude/skills/verify-*/` in Claude Code). Several candidates → ask which one; none → stop and point at `/create-verification-skill` instead of inventing a target. 1. **Index hygiene.** Read the feature map README and glob its sibling files. Fix missing, extra, duplicate, or dead entries. Lightweight; no generated inventory. diff --git a/pstack/skills/no-comments/SKILL.md b/pstack/skills/no-comments/SKILL.md index a07ce9dfc..f5b326513 100644 --- a/pstack/skills/no-comments/SKILL.md +++ b/pstack/skills/no-comments/SKILL.md @@ -16,7 +16,7 @@ Use the caller's files or diff. Otherwise use the current diff against the base ## Steps -1. Spawn `Task` with `subagent_type: "comment-sicko"`. Pass the scope. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. Do not restate its rules. +1. Spawn `Task` with `subagent_type: "comment-sicko"` (in another harness, its name per the Harness reference in [model routing](../../docs/model-routing.md#harness-reference); Claude Code: `pstack:comment-sicko`). Pass the scope. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. Do not restate its rules. 2. Inspect its report and diff. Reject application-code edits, scope escapes, exception-protected deletions, misstated `MUST KILL` reasons, and flags that treat kept intentional code as guilty. Reshape flags on our-code surprises stay actionable. Do not restore those comments. A keep survives only with proof it is about something we cannot change. Audit missed scoped lint and TypeScript suppressions. Correctness or safety suppressions stay actionable `MUST KILL`s. Restore deletions only with exact exceptions and scoped proof. Before accepting thin `IMPORTANT` or `do not remove` kills or keeps, run `/how` or `/why` on their symbol. If a kill is ambiguous, do not restore. If a keep is refuted or still ambiguous, delete it. Revert and rerun one rejected report with the failure named. Reject a second, report it open, and fail `/no-comments`. 3. Fix trivial accepted flags directly by deleting a dead path, dropping a parameter, or using the real API. If any fix needs a shape, run `/architect` once for the accepted set and surrounding code. Stop at the sketch. Architect shapes. Step 4 implements. 4. Implement the smallest root-cause fix in scope. Remove every named workaround. If the root cause is out of scope, land the smallest in-scope fix and report the rest open. The **principle-fix-root-causes** and **principle-redesign-from-first-principles** skills guide intent only. Neither authorizes widening the fence nor fixing instances outside it. Never bolt on symptom guards. diff --git a/pstack/skills/poteto-help/SKILL.md b/pstack/skills/poteto-help/SKILL.md index cbe18c83c..5d77c1871 100644 --- a/pstack/skills/poteto-help/SKILL.md +++ b/pstack/skills/poteto-help/SKILL.md @@ -24,7 +24,7 @@ Infer the need from the message and the conversation. A named situation, such as Check the state that changes the answer, and mention it only when it does: -- No `~/.cursor/rules/pstack-models.mdc` means `/setup-pstack` hasn't run for this user, so every role uses its default model. +- No `~/.cursor/rules/pstack-models.mdc` means `/setup-pstack` hasn't run for this user, so every role uses its default model. Outside Cursor, check for a profile matching the active harness in `~/.config/pstack/models.json` instead. - No `verify-*` skill or other app harness in the project means agents have no scripted way to drive the app. Mention `/create-verification-skill` when the question is about proving a change works. When the model rule is missing and it matters, ask whether the user wants to pick a model for each role and a reasoning budget now. It matters when the user is new, the question is about setup or cost, or the answer depends on which models run. Ask at most once per chat. If the need is also unclear, ask both questions together. Offer two choices: @@ -54,7 +54,7 @@ Whether `/poteto-mode` stays on depends on how the user starts it: - Option+Enter on Mac or Alt+Enter on Windows, or Use as Mode from the skill entry, makes it a Custom Mode. It stays in context every turn until the user exits the mode, and it stays out of casual turns. - Cursor's docs list Custom Modes in the Agents Window and the CLI. Elsewhere, start each new task with `/poteto-mode`. -Link [Cursor's skills docs](https://cursor.com/docs/skills) when this comes up. Mid-chat, "new task" makes the mode match a fresh playbook. `/poteto-mode` already uses `poteto-agent` for the subagents its playbook steps spawn. To get the same style from a subagent of your own, spawn it with `subagent_type: "poteto-agent"`. +Link [Cursor's skills docs](https://cursor.com/docs/skills) when this comes up. Mid-chat, "new task" makes the mode match a fresh playbook. `/poteto-mode` already uses `poteto-agent` for the subagents its playbook steps spawn. To get the same style from a subagent of your own, spawn it with `subagent_type: "poteto-agent"`. In Claude Code, slash commands and agents carry the plugin prefix, `/pstack:poteto-mode` and `pstack:poteto-agent`; the Harness reference in [model routing](../../docs/model-routing.md#harness-reference) lists every harness difference. ## Pick a skill diff --git a/pstack/skills/poteto-mode/SKILL.md b/pstack/skills/poteto-mode/SKILL.md index 4c2219b37..5d77eefbd 100644 --- a/pstack/skills/poteto-mode/SKILL.md +++ b/pstack/skills/poteto-mode/SKILL.md @@ -90,7 +90,7 @@ Read the leaf skill in full for any principle you apply. Each entry names when i ## Subagents -**Use `subagent_type: "poteto-agent"` for any subagent you spawn inside a playbook step** (code-writing delegates, ad-hoc helpers). The chat that receives `/poteto-mode` runs the playbook. Never spawn a `poteto-agent` to run the playbook itself. Routed workflow skills (`how`, `why`, `interrogate`, `reflect`, `swarm`) set their own `subagent_type` for diverse-model review. Respect what the skill prescribes, don't override to `poteto-agent`. +**Use `subagent_type: "poteto-agent"` for any subagent you spawn inside a playbook step** (code-writing delegates, ad-hoc helpers). The chat that receives `/poteto-mode` runs the playbook. Never spawn a `poteto-agent` to run the playbook itself. Routed workflow skills (`how`, `why`, `interrogate`, `reflect`, `swarm`) set their own `subagent_type` for diverse-model review. Respect what the skill prescribes, don't override to `poteto-agent`. Pass each `poteto-agent` the absolute path of this `SKILL.md`. In another harness, use that harness's name for this agent and its fields per the Harness reference in [model routing](../../docs/model-routing.md) (Claude Code: `pstack:poteto-agent`). **Model routing.** Before choosing any delegate, read [model routing](../../docs/model-routing.md) and the matching harness profile in `~/.config/pstack/models.json`. A configured native entry uses this session's subagent tool and its actual model/effort schema; a confirmed external read-only entry is limited to review or investigation. Code-writing delegates stay native unless the user explicitly selected an isolated external writer. With no matching profile, use the legacy `pstack-models.mdc` rule and defaults below in Cursor; in another harness use native `inherit-parent` until configured. diff --git a/pstack/skills/poteto-mode/playbooks/eval.md b/pstack/skills/poteto-mode/playbooks/eval.md index 768a894e2..f1bb8e5d3 100644 --- a/pstack/skills/poteto-mode/playbooks/eval.md +++ b/pstack/skills/poteto-mode/playbooks/eval.md @@ -19,7 +19,7 @@ 3. **Author one organic prompt.** What a user would type. No leakage of what's being measured. 4. **Spawn N parallel candidates** on different models per the **arena** skill's Phase B. Each works in its own sanitized dir. Same prompt to each. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. 5. **Spawn one blinded judge** on a different model family per the **arena** skill's Phase C. Judge sees outputs by sanitized label and the rubric, never a model name. -6. **Verify the chain from transcripts, not self-report.** Read each candidate's local transcript under the active workspace's `agent-transcripts/` directory (the system prompt names this path). Do not glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. Look at which files each candidate actually opened. Grade chain-following from the files it really read plus the shape of the code, never from the candidate's own claims. +6. **Verify the chain from transcripts, not self-report.** Read each candidate's local transcript under the active workspace's `agent-transcripts/` directory (the system prompt names this path). Do not glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. Where the system prompt names none, locate it with the Harness reference in [model routing](../../../docs/model-routing.md#harness-reference). Look at which files each candidate actually opened. Grade chain-following from the files it really read plus the shape of the code, never from the candidate's own claims. 7. **Read every candidate output yourself** end to end. Compare to the judge's verdict. Disagreement means a model is biased or the rubric is ambiguous. Synthesize. **Reply:** variant under test, rubric, per-candidate notes, judge's verdict, your synthesis, and a recommendation for whether to promote the variant. diff --git a/pstack/skills/poteto-mode/playbooks/multi-phase-plan.md b/pstack/skills/poteto-mode/playbooks/multi-phase-plan.md index 27e99947b..214743b6f 100644 --- a/pstack/skills/poteto-mode/playbooks/multi-phase-plan.md +++ b/pstack/skills/poteto-mode/playbooks/multi-phase-plan.md @@ -4,7 +4,7 @@ 1. When the change is one or two files with an obvious approach, skip the plan. Say so and stop. 2. Settle open questions by prototype before you write. Run `playbooks/prototype.md` for each. Keep the branch, the SHA, and the screenshots for Appendix A. Ask the operator only about a product or preference call that no run can settle. Give options (the **never-block-on-the-human** principle skill). -3. Explore in subagents with `subagent_type: "poteto-agent"` and an explicit model per the Subagents section (the **guard-the-context-window** principle skill). Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. Each returns file pointers, conventions, test commands, and entry points. No inlined dumps. +3. Explore in subagents with `subagent_type: "poteto-agent"` (in another harness, its name per the Subagents section) and an explicit model per the Subagents section (the **guard-the-context-window** principle skill). Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. Each returns file pointers, conventions, test commands, and entry points. No inlined dumps. 4. Copy the skeleton below into the plan file and fill every placeholder. Unless the operator names a path, write the file under the agent store's `docs/`. Keep every heading and every sub-block in the order shown. One section per PR. One PR is one change with its own evidence (the **sequence-verifiable-units** principle skill). Name the execution playbook in **How to read this**. Pick between `playbooks/autopilot-full.md` and `playbooks/autopilot-stack.md` per the rule at the end of `playbooks/autopilot-stack.md`. A standing program takes `playbooks/orchestrate.md`. 5. Write under `/technical-writing` in full, then `/unslop`. The body is one Diátaxis mode, how-to. Appendices hold explanation and reference. Each heading states the task or the finding. No long dashes. No mid-sentence colons. 6. Run `node pstack/skills/poteto-mode/scripts/check-plan.mjs ` and fix every line it prints (the **encode-lessons-in-structure** principle skill). diff --git a/pstack/skills/poteto-mode/playbooks/orchestrate.md b/pstack/skills/poteto-mode/playbooks/orchestrate.md index 4ccb24d76..f4789df6d 100644 --- a/pstack/skills/poteto-mode/playbooks/orchestrate.md +++ b/pstack/skills/poteto-mode/playbooks/orchestrate.md @@ -14,7 +14,7 @@ Three rules carry the rest. - **Coordinator (this chat).** Local. Frames, authors briefs, drains the inbox, owns the human report, makes judgment calls. It never authors or edits code. Conflicted merges, chain rebases, and code changes are always tasks. Mechanically landing a verified unit (fast-forward or clean cherry-pick of a worker's commit, then push) is bookkeeping the coordinator may do itself on repos where local git is cheap. Queueing finished work behind an idle stacker is how a deadline harvests nothing. The loop is agentic end to end. Agents are spawned, resumed, and drained only through the Task tool. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. State reads and writes go through `scripts/orch/orch.ts` at drain points, one command in and one line out. The CLI never spawns, waits, or wakes anything. - **Sub-coordinator.** Always local, durable, one per track, and only when the program exceeds what one coordinator's drains can manage. A track the coordinator can drain itself needs no middle layer. Each nested layer re-pays a full orientation preamble, and a blocking sub-coordinator hides its children while the parent idles. Owns its track's units and boards, authors its workers' briefs, spawns its own workers and verifiers (nesting works to depth 3, and a nested spawn has the full Task schema including `environment`). Rolls up aggregates at wave boundaries. Never forwards raw child reports. Cap in-flight children at what one drain can process, roughly ten, as a rolling window. Never as blocking batches, which cost the slowest child of every batch. -- **Worker / verifier.** Always `environment: "cloud"` unless the task needs this machine: `control-ui` or `control-cli` runtime verification (from `cursor-team-kit`). Reading local transcripts under `agent-transcripts/`. Simulators and local IDE state. Auth that exists only here. Cloud agents cannot read the local store, so their briefs inline what they need or point at repo paths. Prefer fewer, broader workers. One writer per worktree or branch (principle-separate-before-serializing-shared-state). Run a unit's verifier on a different model family from its worker. +- **Worker / verifier.** Always `environment: "cloud"` (in another harness, its translation per the Harness reference in [model routing](../../../docs/model-routing.md#harness-reference)) unless the task needs this machine: `control-ui` or `control-cli` runtime verification (from `cursor-team-kit`). Reading local transcripts under `agent-transcripts/`. Simulators and local IDE state. Auth that exists only here. Cloud agents cannot read the local store, so their briefs inline what they need or point at repo paths. Prefer fewer, broader workers. One writer per worktree or branch (principle-separate-before-serializing-shared-state). Run a unit's verifier on a different model family from its worker. Depth stays at coordinator, track, worker. Author the track decomposition per project (build, landing, and verification are common cuts, not a required shape). Hard-coded swarm trees were tried and parked as too rigid. diff --git a/pstack/skills/poteto-mode/playbooks/session-pickup.md b/pstack/skills/poteto-mode/playbooks/session-pickup.md index 876b14338..513bff3b0 100644 --- a/pstack/skills/poteto-mode/playbooks/session-pickup.md +++ b/pstack/skills/poteto-mode/playbooks/session-pickup.md @@ -2,7 +2,7 @@ **You own the resume point. Read the prior trail, don't redo it.** -1. Locate the prior trail. A local transcript under the active workspace's `agent-transcripts/` directory (the system prompt names the path. Do not glob across `~/.cursor/projects/*/`, that crosses workspace boundaries and reads private chats from unrelated projects), a cloud-agent URL, or a pushed branch. Read the metadata overview and last messages first, then scan back for the decision points. Parse a long transcript in a subagent and keep the reduced timeline in the main thread (the **principle-guard-the-context-window** skill). Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. +1. Locate the prior trail. A local transcript under the active workspace's `agent-transcripts/` directory (the system prompt names the path. Do not glob across `~/.cursor/projects/*/`, that crosses workspace boundaries and reads private chats from unrelated projects; where the system prompt names none, locate it with the Harness reference in [model routing](../../../docs/model-routing.md#harness-reference)), a cloud-agent URL, or a pushed branch. Read the metadata overview and last messages first, then scan back for the decision points. Parse a long transcript in a subagent and keep the reduced timeline in the main thread (the **principle-guard-the-context-window** skill). Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section. 2. Reconstruct operational state. The branch and worktree, what already landed (`git log`, `git diff` against the base), the open todos, the decisions made. The prior trail is authoritative input. Resist the bias to re-derive it. 3. Diff done vs pending. Compare what shipped against what was planned, name the resume point, do not re-run the prior repro or redo completed work. A "let me verify from scratch" pass means you're treating the trail as untrustworthy when it's authoritative. 4. Route the remaining work to the matching playbook and pick the verdict: continue the execution, ship a finished recommendation, ratify or override a prior conclusion, or postmortem a failed run. The pickup playbook ends here. The routed playbook owns the rest. diff --git a/pstack/skills/poteto-mode/scripts/worktree-audit.sh b/pstack/skills/poteto-mode/scripts/worktree-audit.sh index 743c4e925..e52fcae05 100755 --- a/pstack/skills/poteto-mode/scripts/worktree-audit.sh +++ b/pstack/skills/poteto-mode/scripts/worktree-audit.sh @@ -61,9 +61,15 @@ elif raw=$(gh pr list --author "@me" --state all --limit 1000 \ fi [ -s "$prs" ] || echo "[]" > "$prs" -# Transcripts dir: ~/.cursor/projects//agent-transcripts. +# Transcripts dirs: Cursor's ~/.cursor/projects//agent-transcripts +# and Claude Code's ~/.claude/projects/. The slug rules +# differ; see the Harness reference in pstack's docs/model-routing.md. slug=$(printf '%s' "$main_wt" | sed 's#^/##; s#/#-#g') -transcripts="$HOME/.cursor/projects/$slug/agent-transcripts" +claude_slug=$(printf '%s' "$main_wt" | sed 's#[/.]#-#g') +transcripts=() +for d in "$HOME/.cursor/projects/$slug/agent-transcripts" "$HOME/.claude/projects/$claude_slug"; do + [ -d "$d" ] && transcripts+=("$d") +done now=$(date +%s) echo "# base: $base" @@ -103,8 +109,8 @@ git worktree list --porcelain | awk '/^worktree /{print $2}' | while read -r wt; # Most recent chat whose transcript operated in this worktree. Match path # followed by "/" or a quote so glint-482 does not match glint-482-r37. last="-"; last_ts=0 - if [ -d "$transcripts" ]; then - f=$(rg -l -e "${wt}/" -e "${wt}\"" "$transcripts" 2>/dev/null \ + if [ "${#transcripts[@]}" -gt 0 ]; then + f=$(rg -l -e "${wt}/" -e "${wt}\"" "${transcripts[@]}" 2>/dev/null \ | xargs stat -f '%m %N' 2>/dev/null | sort -rn | head -1) if [ -n "$f" ]; then last_ts=$(echo "$f" | awk '{print $1}') last=$(date -r "$last_ts" '+%Y-%m-%d' 2>/dev/null); fi diff --git a/pstack/skills/recall/SKILL.md b/pstack/skills/recall/SKILL.md index cd8cc2079..897c60609 100644 --- a/pstack/skills/recall/SKILL.md +++ b/pstack/skills/recall/SKILL.md @@ -12,7 +12,7 @@ Keep it tight and on-topic. Read only what the in-scope threads need, then stop. Your context lives in two records. Your own chat history holds what you did and decided. The shared record holds everything that happened around the same code under other names: the symptoms users keep reporting, the fixes that shipped and got reverted, the errors still firing in prod. That second record is what the **why** skill searches, across source control, the issue tracker, chat and issue channels, long-form docs, and error tracking. A feature with a long bug tail keeps most of its story there, so don't reconstruct it from your transcripts alone. -Transcripts live at `~/.cursor/projects//agent-transcripts//.jsonl`, where `` is the workspace path with the leading slash dropped and each "/" turned into "-" (so `/Users/you/proj` becomes `Users-you-proj`). Every line is one chat message. +Transcripts live at `~/.cursor/projects//agent-transcripts//.jsonl`, where `` is the workspace path with the leading slash dropped and each "/" turned into "-" (so `/Users/you/proj` becomes `Users-you-proj`). In another harness, take the transcript directory, file layout, and slug rule from the Harness reference in [model routing](../../docs/model-routing.md#harness-reference) (Claude Code: `~/.claude/projects/-Users-you-proj/.jsonl`). Every line is one chat message. 1. Classify, then route. One specific prior chat to resume is the `session-pickup` playbook, not this. Turning habits into a durable skill is `automate-me`. A human-readable summary of your work is a different task. Recall loads working context across recent chats before you act. If the user already gave you a full state capsule (paths, branch, the change), use it and skip the mining. 2. Lock the scope before searching. Pin the window ("recent" is a real range, default the last 7 days), the topic if named, and the workspace (default the active one. Never read another project's transcripts without being asked). State the scope back. Never quietly turn "all" into "recent N". diff --git a/pstack/skills/reflect/SKILL.md b/pstack/skills/reflect/SKILL.md index a883119a4..e8af26072 100644 --- a/pstack/skills/reflect/SKILL.md +++ b/pstack/skills/reflect/SKILL.md @@ -12,7 +12,7 @@ Invoke when the user says "reflect" or "/reflect". Skip when the conversation is ## 1. Locate the active transcript -Before fanning out, find this conversation's transcript in the `agent-transcripts/` directory the system prompt names. Do not glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. +Before fanning out, find this conversation's transcript in the `agent-transcripts/` directory the system prompt names. Do not glob across `~/.cursor/projects/*/`. That crosses workspace boundaries and reads private chats from unrelated projects. In a harness whose system prompt names no transcript directory, locate it with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference), under the same rule. ```bash ls -t /*.jsonl /*/*.jsonl /*/subagents/*.jsonl 2>/dev/null | head -10 @@ -22,7 +22,7 @@ That covers the legacy flat (`.jsonl`), current nested (`/.jsonl`), ## 2. Spawn three reviewers in parallel -One message, three `Task` calls, `subagent_type: generalPurpose`, agent mode (`readonly: false`). Reviewers need MCP access to look up the tickets, chat threads, and observability traces the transcript references, and readonly strips MCPs. +One message, three `Task` calls, `subagent_type: generalPurpose`, agent mode (`readonly: false`). Reviewers need MCP access to look up the tickets, chat threads, and observability traces the transcript references, and readonly strips MCPs. In another harness, translate these fields with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference). First read [model routing](../../docs/model-routing.md) and the matching harness profile. Native reviewers can launch together through this session's subagent tool. Reviewers need MCP access for context lookups (tickets, chat threads, observability traces referenced in the transcript); use an external runner only if its context is complete or the same tools are available. Otherwise use the profile's confirmed native fallback. With no profile, use the legacy three `Task` calls in Cursor; in another harness use three native `inherit-parent` reviewers. Use agent mode when readonly strips MCPs. diff --git a/pstack/skills/reflect/references/divergent-reviewer.md b/pstack/skills/reflect/references/divergent-reviewer.md index 1e070a2a3..d4c698064 100644 --- a/pstack/skills/reflect/references/divergent-reviewer.md +++ b/pstack/skills/reflect/references/divergent-reviewer.md @@ -18,7 +18,7 @@ Scan for: ## Scope to skills and tools the session actually used -Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. +Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`, or the matching `.claude/` paths in Claude Code), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. Two finding shapes are valid: - The parent invoked the skill and you found a real gap in its body. Route to the skill's relevant section. diff --git a/pstack/skills/reflect/references/judgment-reviewer.md b/pstack/skills/reflect/references/judgment-reviewer.md index 61d15d76f..fb394df75 100644 --- a/pstack/skills/reflect/references/judgment-reviewer.md +++ b/pstack/skills/reflect/references/judgment-reviewer.md @@ -17,7 +17,7 @@ Scan for: ## Scope to skills and tools the session actually used -Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. +Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`, or the matching `.claude/` paths in Claude Code), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. Two finding shapes are valid: - The parent invoked the skill and you found a real gap in its body. Route to the skill's relevant section. diff --git a/pstack/skills/reflect/references/tooling-reviewer.md b/pstack/skills/reflect/references/tooling-reviewer.md index a839db431..4a20b136c 100644 --- a/pstack/skills/reflect/references/tooling-reviewer.md +++ b/pstack/skills/reflect/references/tooling-reviewer.md @@ -28,7 +28,7 @@ Scan for: ## Scope to skills and tools the session actually used -Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. +Route findings only to skills, tools, or MCPs this transcript used. A skill counts as used when the transcript shows a `Read` of its `SKILL.md` (under `.cursor/skills/`, `~/.cursor/skills/`, or `~/.cursor/plugins/`, or the matching `.claude/` paths in Claude Code), a `Task` prompt naming its path, or a tool call (Shell, Grep, MCP, etc.) matching its documented commands. Speculative routings to skills the parent never opened do not count. Two finding shapes are valid: - The parent invoked the skill and you found a real gap in its body. Route to the skill's relevant section. diff --git a/pstack/skills/show-me-your-work/SKILL.md b/pstack/skills/show-me-your-work/SKILL.md index ada1bba1e..59aff6737 100644 --- a/pstack/skills/show-me-your-work/SKILL.md +++ b/pstack/skills/show-me-your-work/SKILL.md @@ -54,7 +54,7 @@ Commit it only when the work is ambitious enough that a reviewer needs the trail ## Audit the log against the transcript -At the end of the run, before handing back, check the log told the truth. Read this run's transcript under the active workspace's `agent-transcripts/` directory (the system prompt names the path). Don't glob across `~/.cursor/projects/*/`. That reads unrelated private chats. Walk this run's rows against what actually happened. Each stretch of them begins at one of this run's `start` rows, or at the first row if this run created the log, and ends at the next `start` row of another run: +At the end of the run, before handing back, check the log told the truth. Read this run's transcript under the active workspace's `agent-transcripts/` directory (the system prompt names the path). Don't glob across `~/.cursor/projects/*/`. That reads unrelated private chats. In a harness whose system prompt names no transcript directory, locate it with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference), under the same rule. Walk this run's rows against what actually happened. Each stretch of them begins at one of this run's `start` rows, or at the first row if this run created the log, and ends at the next `start` row of another run: - Check that every row maps to a real decision or action. - Check that each row's evidence resolves and shows what the row claims. diff --git a/pstack/skills/swarm/SKILL.md b/pstack/skills/swarm/SKILL.md index 0b7e1e6a8..78834bd1f 100644 --- a/pstack/skills/swarm/SKILL.md +++ b/pstack/skills/swarm/SKILL.md @@ -27,7 +27,7 @@ Open a todolist with one entry per phase before launching anything. ## Phase B: Fan out -Spawn native workers with the active harness's subagent tool. In Cursor, use one message with `subagent_type: generalPurpose`, `environment: "cloud"`, and `run_in_background: true`, leaving `model` unset for `auto` or `inherit-parent`; use `environment: "local"` only when computer access is needed. An explicitly selected external worker uses its confirmed runner and its own checkout; drain it with the native workers before ranking results. +Spawn native workers with the active harness's subagent tool. In Cursor, use one message with `subagent_type: generalPurpose`, `environment: "cloud"`, and `run_in_background: true`, leaving `model` unset for `auto` or `inherit-parent`; use `environment: "local"` only when computer access is needed. In another harness, translate these fields with the Harness reference in [model routing](../../docs/model-routing.md#harness-reference). An explicitly selected external worker uses its confirmed runner and its own checkout; drain it with the native workers before ranking results. When a worker must start from a non-default pushed branch, pass `cloud_base_branch`. diff --git a/pstack/skills/why/SKILL.md b/pstack/skills/why/SKILL.md index b678d1185..4903a3ff4 100644 --- a/pstack/skills/why/SKILL.md +++ b/pstack/skills/why/SKILL.md @@ -32,7 +32,7 @@ Before spawning investigators, build the seed context inline: file paths and lin ### Discovery -Before spawning investigators, list the available MCPs from the Cursor environment. Use the available-tools map when present. Otherwise inspect the `mcps/` directory Cursor exposes for enabled MCP servers. +Before spawning investigators, list the available MCPs from the Cursor environment. Use the available-tools map when present. Otherwise inspect the `mcps/` directory Cursor exposes for enabled MCP servers. In another harness, list the MCP tools this session exposes. Map each available MCP to one evidence category: From 8543ac8d1d8ee98012b8d34a783b0e916756594d Mon Sep 17 00:00:00 2001 From: Sirine Jnayeh Date: Wed, 14 Oct 2026 20:59:24 +0400 Subject: [PATCH 3/5] ci: validate Claude Code manifests and manifest version sync - validate-plugins.mjs checks Claude marketplace entries and that every manifest of a plugin carries the same version. - The workflow runs `claude plugin validate .` and triggers on the Claude marketplace, the validator, and the workflow itself. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/validate-plugins.yml | 6 +++ scripts/validate-plugins.mjs | 58 +++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index 03e8e1928..c4326e911 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -4,8 +4,11 @@ on: pull_request: paths: - ".cursor-plugin/marketplace.json" + - ".claude-plugin/marketplace.json" - "**/plugin.json" - "schemas/**" + - "scripts/validate-plugins.mjs" + - ".github/workflows/validate-plugins.yml" jobs: validate: @@ -22,3 +25,6 @@ jobs: - name: Validate plugin definitions run: node scripts/validate-plugins.mjs + + - name: Validate Claude Code plugin definitions + run: npx --yes @anthropic-ai/claude-code@2.1.299 plugin validate . diff --git a/scripts/validate-plugins.mjs b/scripts/validate-plugins.mjs index 6a7870854..12c563a4b 100644 --- a/scripts/validate-plugins.mjs +++ b/scripts/validate-plugins.mjs @@ -92,7 +92,63 @@ for (const entry of marketplace.plugins ?? []) { } } -// 3. Report results +// 3. Validate the Claude Code marketplace entries. `claude plugin validate` +// checks the manifest schema in CI; this checks what it cannot see. +const claudeMarketplacePath = resolve(root, ".claude-plugin/marketplace.json"); +const claudeMarketplace = existsSync(claudeMarketplacePath) + ? loadJSON(claudeMarketplacePath) + : { plugins: [] }; + +for (const entry of claudeMarketplace.plugins ?? []) { + const pluginDir = resolve(root, entry.source); + const pluginJsonPath = resolve(pluginDir, ".claude-plugin/plugin.json"); + + if (!existsSync(pluginJsonPath)) { + fail( + `Plugin "${entry.name}": missing .claude-plugin/plugin.json in "${entry.source}"` + ); + continue; + } + + const pluginJson = loadJSON(pluginJsonPath); + if (pluginJson.name && pluginJson.name !== entry.name) { + fail( + `Plugin "${entry.name}": Claude marketplace name does not match .claude-plugin/plugin.json name "${pluginJson.name}"` + ); + } +} + +// 4. Check that every manifest of a plugin carries the same version, so a +// bump never reaches one harness and misses another. +const manifestPaths = [ + ".cursor-plugin/plugin.json", + ".claude-plugin/plugin.json", + "plugin.json", +]; +const sources = new Map(); +for (const entry of [ + ...(marketplace.plugins ?? []), + ...(claudeMarketplace.plugins ?? []), +]) { + sources.set(resolve(root, entry.source), entry.name); +} + +for (const [pluginDir, name] of sources) { + const versions = manifestPaths + .map((path) => resolve(pluginDir, path)) + .filter((path) => existsSync(path)) + .map((path) => ({ path, version: loadJSON(path).version })) + .filter(({ version }) => version !== undefined); + + if (new Set(versions.map(({ version }) => version)).size > 1) { + fail(`Plugin "${name}": manifest versions differ:`); + for (const { path, version } of versions) { + console.error(` ${path.slice(root.length + 1)}: ${version}`); + } + } +} + +// 5. Report results if (errors > 0) { console.error(`\nValidation failed with ${errors} error(s).`); process.exit(1); From 200c7fea1e04102d4d8e32d2b6d38fb8bf6e7566 Mon Sep 17 00:00:00 2001 From: Sirine Jnayeh Date: Thu, 15 Oct 2026 17:32:26 +0400 Subject: [PATCH 4/5] fix(pstack): restore Task contracts and budget rules dropped in #455 - how: restore the spawn contract (generalPurpose, readonly: true, explorer and explainer roles, rule lines and defaults). - why: restore the rule-line fallback and the readonly: false contract ahead of the per-spawn model lines. - setup-pstack: rebuild roles from defaults before applying the budget, overlay only family, list, or alias customizations, and write `# budget: