diff --git a/harness/pstack/claude-code/README.md b/harness/pstack/claude-code/README.md index ef18f941d..8f9af1baa 100644 --- a/harness/pstack/claude-code/README.md +++ b/harness/pstack/claude-code/README.md @@ -4,7 +4,7 @@ i'm [poteto](https://x.com/poteto). i'm not a president or ceo, but i've worked there's a growing sense that ai writes too much slop code. i agree. i don't want to ship like a team of twenty slop artists. throughput without quality is not a goal i aspire to. if you want to go fast, go deep first. -**pstack is my answer.** these are the same skills i use everyday to ship high quality code at Cursor. this turns cursor into a real engineering team. the goal is not to maximize loc, in fact it's the opposite. pstack helps you write less, but higher quality code. +**pstack is my answer.** these are the same skills i use every day to ship high quality code at Cursor. this turns cursor into a real engineering team. the goal is not to maximize loc, in fact it's the opposite. pstack helps you write less, but higher quality code. **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. @@ -27,7 +27,7 @@ in claude code: claude code prefixes plugin commands and agents, so `/poteto-mode` is `/pstack:poteto-mode`. the [claude code adapter](./docs/harness/claude-code.md) maps every other cursor name. in claude code, `/pstack:setup-pstack` writes your model choices to `~/.claude/rules/pstack-models.md`, and a step that needs a cursor-only feature, such as bugbot or automations, is skipped with a one-line note. -claude code installs a generated copy of pstack from [`harness/pstack/`](https://github.com/cursor/plugins/tree/main/harness/pstack) at the repository root. after changing `skills/`, `agents/`, `docs/guide/`, `docs/harness/claude-code.md`, this readme, or `plugin.json`, run `node scripts/generate-pstack-harness-trees.mjs` from the repository root and commit the result. ci fails until you do. +claude code installs a generated copy of pstack, including this readme and the guide, from [`harness/pstack/`](https://github.com/cursor/plugins/tree/main/harness/pstack) at the repository root. after you change pstack, run `node scripts/generate-pstack-harness-trees.mjs` from the repository root and commit the result. ci fails while the generated copy is out of date. ## get started @@ -38,7 +38,7 @@ two steps: new here? the [pstack guide](./docs/guide/README.md) walks you through a first real task, from setup and prompting through verification and overnight runs. stuck, or unsure which skill fits? ask [`/poteto-help`](./skills/poteto-help/SKILL.md). -that's it. the other skills are situational; the mode skill uses them for you as needed. out of the box the mode splits work by model strength: code delegates (feature, refactoring, bug fix, perf, hillclimb) go to grok, while the hardest changes, prose, and judgment go to opus 5.5. the default panel is opus 5.5 / grok. [`/setup-pstack`](./skills/setup-pstack/SKILL.md) changes any of it. +that's it. the other skills are situational, and the mode skill uses them for you as needed. out of the box the mode splits work by model strength: code delegates (feature, refactoring, bug fix, perf, hillclimb) go to grok, while the hardest changes, prose, and judgment go to opus 5.5. the default panel is opus 5.5 / grok. [`/setup-pstack`](./skills/setup-pstack/SKILL.md) changes any of it. ## usage @@ -81,7 +81,7 @@ morning. | [shipping](./skills/poteto-mode/playbooks/shipping.md) | independently verify a green stack, then land the contiguous verified run bottom-up through github by default or origin when available. | | [autonomous run](./skills/poteto-mode/playbooks/autonomous-run.md) | drive a long task to completion without stopping. | | [orchestrate](./skills/poteto-mode/playbooks/orchestrate.md) | a standing project handed to one coordinator chat: multi-day, many stacked prs, fleets of subagents. | -| [autopilot-full](./skills/poteto-mode/playbooks/autopilot-full.md) | run independent prs to merged with one owner per pr and a root swarm verdict on each round, from the code-ready head on. | +| [autopilot-full](./skills/poteto-mode/playbooks/autopilot-full.md) | run independent prs to merged with one owner per pr. a swarm verifies each code-ready head, and every later change to the patch gets a fresh check. | | [autopilot-stack](./skills/poteto-mode/playbooks/autopilot-stack.md) | build and verify one linear base-branch stack for the operator to review and land. | | [session pickup](./skills/poteto-mode/playbooks/session-pickup.md) | resume or take over a prior agent's in-flight work. | | [pause safely](./skills/poteto-mode/playbooks/pause-safely.md) | suspend in-flight work cleanly so it can be resumed later. | @@ -101,7 +101,7 @@ when invoked it: the full rules and playbooks live in [`skills/poteto-mode/SKILL.md`](./skills/poteto-mode/SKILL.md). -to keep [`/poteto-mode`](./skills/poteto-mode/SKILL.md) on across turns, pick it from the `/` menu and press option+enter (mac) or alt+enter (windows) instead of enter. that makes it a [custom mode](https://cursor.com/docs/skills), which cursor offers in the agents window and the cli. it stays in context every turn, applies itself when a playbook matches or the task needs rigor, and stays out of the way otherwise. plain enter attaches it to one message only. say so to opt out, or exit the mode to turn it off. +to keep [`/poteto-mode`](./skills/poteto-mode/SKILL.md) on across turns, pick it from the `/` menu and press option+enter (mac) or alt+enter (windows) instead of enter. that makes it a [custom mode](https://cursor.com/docs/skills#using-a-skill-as-a-custom-mode), which cursor offers in the agents window and the cli. it stays in context every turn until you exit the mode. plain enter attaches it to one message only. [`/poteto-mode`](./skills/poteto-mode/SKILL.md) works extremely well with cursor's `/loop` command. you can make cursor work for many hours without sacrificing rigor. @@ -256,7 +256,7 @@ a few things `poteto-mode` references but doesn't bundle: - `/deslop` and the `deslop` skill ship in the `cursor-team-kit` plugin. - `control-cli` (for CLIs and TUIs) and `control-ui` (for browser, Electron, web) ship in `cursor-team-kit` too. -- `/create-skill` is a cursor built-in. cursor also ships a built-in `/babysit`; inside `poteto-mode`, the [babysit playbook](./skills/poteto-mode/playbooks/babysit.md) supersedes it for pr-status requests. +- `/create-skill` is a cursor built-in. cursor also ships a built-in `/autopilot` that watches a pr. inside `poteto-mode`, pr-status requests go to the [babysit playbook](./skills/poteto-mode/playbooks/babysit.md) instead. install `cursor-team-kit` alongside pstack if you want the full set. diff --git a/harness/pstack/claude-code/docs/guide/01-setup.md b/harness/pstack/claude-code/docs/guide/01-setup.md index 62420df82..e28f5cbab 100644 --- a/harness/pstack/claude-code/docs/guide/01-setup.md +++ b/harness/pstack/claude-code/docs/guide/01-setup.md @@ -57,6 +57,6 @@ Pick something real but small, and describe it the way you'd describe it to a co Watch the todo list. Its first items are the matched playbook's steps copied in, the Feature playbook for this prompt. If `/poteto-mode` skips a step, the step stays in the list with `skip: `, so you can see what it chose not to do. -From here you can type normal follow-ups. To keep `/poteto-mode` on for the whole chat, pick it from the `/` menu with Option+Enter (Mac) or Alt+Enter (Windows) instead of Enter. That makes it a [Custom Mode](https://cursor.com/docs/skills), which stays in context on every turn until you exit it. Custom Modes are available in the Agents Window and the CLI. Plain Enter attaches the skill to one message, and it fades as the chat moves on. +From here you can type normal follow-ups. To keep `/poteto-mode` on for the whole chat, pick it from the `/` menu with Option+Enter (Mac) or Alt+Enter (Windows) instead of Enter. That makes it a [Custom Mode](https://cursor.com/docs/skills#using-a-skill-as-a-custom-mode), which stays in context on every turn until you exit it. Custom Modes are available in the Agents Window and the CLI. Plain Enter attaches the skill to one message, and it fades as the chat moves on. Next: [Route work through `/poteto-mode`](./02-poteto-mode.md). diff --git a/harness/pstack/claude-code/docs/guide/02-poteto-mode.md b/harness/pstack/claude-code/docs/guide/02-poteto-mode.md index 8341604ae..0e6568e17 100644 --- a/harness/pstack/claude-code/docs/guide/02-poteto-mode.md +++ b/harness/pstack/claude-code/docs/guide/02-poteto-mode.md @@ -25,7 +25,7 @@ flowchart TD J --> K ``` -The diagram shows the common routes. There are also playbooks for hillclimbing a metric, diagnosing runtime symptoms and captured traces, prototypes, visual parity, authoring and evaluating skills, autonomous runs, babysitting a PR or stack to merge-ready, shipping a verified stack, running a PR queue on autopilot, orchestrating project-scale programs, session pickup, pausing safely, multi-phase plans, and worktree cleanup. The [playbook directory](../../skills/poteto-mode/playbooks/) has the full set. +The diagram shows the common routes. There are also playbooks for hillclimbing a metric, diagnosing runtime symptoms and captured traces, prototypes, visual parity, authoring and evaluating skills, autonomous runs, babysitting a PR or stack to merge-ready, shipping a verified stack, running a PR queue or a stack on autopilot, orchestrating project-scale programs, session pickup, pausing safely, multi-phase plans, and worktree cleanup. The [playbook directory](../../skills/poteto-mode/playbooks/) has the full set. ## Say the goal, not the ceremony diff --git a/harness/pstack/claude-code/docs/guide/03-understand.md b/harness/pstack/claude-code/docs/guide/03-understand.md index e15bea052..e26661f91 100644 --- a/harness/pstack/claude-code/docs/guide/03-understand.md +++ b/harness/pstack/claude-code/docs/guide/03-understand.md @@ -30,9 +30,9 @@ Ask the question you actually have. [`/how`](../../skills/how/SKILL.md) reads th /why was the retry limit set to five? does the reason still hold? ``` -[`/why`](../../skills/why/SKILL.md) works like a detective on a cold case. It starts from source control, then queries whatever evidence categories your MCPs expose, such as the issue tracker, long-form docs, team chat, observability, error tracking, and analytics, all in parallel. The report cites everything, separates direct evidence from inference, and says "appears to" when the record is thin. A null result gets reported too, because "nobody wrote down why" is itself an answer. +[`/why`](../../skills/why/SKILL.md) starts from source control, then queries whatever evidence categories your MCPs expose, such as the issue tracker, long-form docs, team chat, observability, error tracking, and analytics, all in parallel. The report cites everything, separates direct evidence from inference, and says "appears to" when the record is thin. A null result gets reported too, because "nobody wrote down why" is itself an answer. -The two compose naturally. `do why first then how` is a perfectly good prompt when you suspect the history explains the mess. +The two compose naturally. `do why first then how` is a good prompt when you suspect the history explains the mess. ## Actually understand it with `/teach` @@ -40,7 +40,7 @@ The two compose naturally. `do why first then how` is a perfectly good prompt wh /teach me how this PR changes retries. convince me it fixes the cause and not the symptom. ``` -[`/teach`](../../skills/teach/SKILL.md) is for when a summary isn't enough. It runs `/how` and `/why`, for a small change maybe just one of them, and weaves the findings into a plain explanation that builds up diagram by diagram. The "convince me" framing is worth stealing. It turns the explanation into an argument you can poke at instead of a tour. +[`/teach`](../../skills/teach/SKILL.md) is for when a summary isn't enough. It runs `/how` and `/why`, for a small change maybe just one of them, and weaves the findings into a plain explanation that builds up diagram by diagram. The "convince me" framing is worth reusing. It turns the explanation into an argument you can test instead of a tour. It works on the agent's own choices too: diff --git a/harness/pstack/claude-code/docs/guide/04-design.md b/harness/pstack/claude-code/docs/guide/04-design.md index 61d5bbb59..65862086a 100644 --- a/harness/pstack/claude-code/docs/guide/04-design.md +++ b/harness/pstack/claude-code/docs/guide/04-design.md @@ -2,7 +2,7 @@ One attempt at a hard design locks in the first shape the model thought of. `/architect` settles types and boundaries before implementation. `/arena` runs several attempts at the same brief and merges the best parts. `/interrogate` has other models try to break the result. When the job is coverage rather than design synthesis, `/swarm` fans out slices or races and aggregates their results. -The two most common design mistakes are taking the agent's first design and polishing a plan that no code has tested. This page fixes both. You plan through code: prototypes answer the open questions, a README or tutorial sets the target, and the written plan comes last. +The two most common design mistakes are taking the agent's first design and polishing a plan that no code has tested. This page fixes both. You plan through code. Prototypes answer the open questions, a README or tutorial sets the target, and the written plan comes last. ![Three robots draft competing bridge models at their own tables under /architect, /arena, and /interrogate panels, while a judge robot with a clipboard inspects skeptically.](./images/design.jpg) diff --git a/harness/pstack/claude-code/docs/guide/05-build-and-clean.md b/harness/pstack/claude-code/docs/guide/05-build-and-clean.md index fc48a46df..dbadc3d41 100644 --- a/harness/pstack/claude-code/docs/guide/05-build-and-clean.md +++ b/harness/pstack/claude-code/docs/guide/05-build-and-clean.md @@ -1,6 +1,6 @@ # Build the change and clean the diff -The build playbooks share one discipline. Say what you observed, let the playbook demand the evidence. This page shows what to put in the prompt for each common build task, then the cleanup habit that keeps diffs reviewable. +The build playbooks share one discipline. Say what you observed, and let the playbook demand the evidence. This page shows what to put in the prompt for each common build task, then the cleanup habit that keeps diffs reviewable. ## Prompt each build playbook with what you know @@ -22,7 +22,7 @@ A refactoring prompt pins behavior before structure moves: /poteto-mode move parsing into one module, zero behavior change. record the current output first and prove it's unchanged after. ``` -A perf prompt states the measurement, not a vibe: +A perf prompt states the measurement, not an impression: ```text /poteto-mode startup takes 1.8s on this fixture. trace it, fix the measured cause, show me before and after. diff --git a/harness/pstack/claude-code/docs/guide/06-verify-and-ship.md b/harness/pstack/claude-code/docs/guide/06-verify-and-ship.md index 007ea2cab..2fa0c8d8f 100644 --- a/harness/pstack/claude-code/docs/guide/06-verify-and-ship.md +++ b/harness/pstack/claude-code/docs/guide/06-verify-and-ship.md @@ -14,7 +14,7 @@ Put what done means in the first prompt, in whatever words fit: /poteto-mode add json output to this command. text output stays byte-identical, the json parses, both run against the sample project. show me the evidence. ``` -Now the agent has three checks it can run, not a mood to satisfy. When the reply comes back, it should carry the exact commands and outputs. If a check couldn't run, a good reply says "inconclusive", and you should treat a confident reply without evidence as a red flag. +Now the agent has three checks it can run, not a mood to satisfy. When the reply comes back, it should carry the exact commands and outputs. If a check couldn't run, a good reply says "inconclusive". A confident reply without evidence is a warning sign. Match the check to the change: @@ -26,7 +26,7 @@ Match the check to the change: Ask for the proof as an artifact you can inspect yourself: the failing test and then the passing one, a before-and-after video, the trace, the screenshot. If the fix already merged, ask for the same check again on main. An artifact beats a plausible explanation, because you can challenge it without replaying the whole run. -For a small diff you don't fully trust, [`/blast-radius`](../../skills/blast-radius/SKILL.md) finds what it could break elsewhere. It picks the one fact the change is safe because of and proves it by running code instead of writing an essay about it. +For a small diff you don't fully trust, [`/blast-radius`](../../skills/blast-radius/SKILL.md) finds what it could break elsewhere. It finds the one fact that makes the change safe and proves that fact by running code, not by arguing for it. ## Vet a measured number with `/benchmark-checklist` @@ -85,13 +85,13 @@ While you're there, make the dev setup repeatable too: seeded data, test users, ## Keep the verification skill honest -Apps change and feature maps rot. Run this at least once a day, ideally from a scheduled automation so nobody has to remember: +Apps change, and feature maps go out of date. Run this at least once a day, ideally from a scheduled automation so nobody has to remember: ```text /maintain-verification-skill ``` -[`/maintain-verification-skill`](../../skills/maintain-verification-skill/SKILL.md) audits the generated skill: one read-only source reader per feature in parallel, then one live pass that drives every mapped feature. It ends in exactly one of three outcomes. `clean` means full coverage and nothing to ship. `changed` means one PR of proven corrections, confined to the verification skill's own directory. `blocked` names the blocker. It never edits product code. If the live pass catches a product regression, it reports the regression instead of papering over it in docs. +[`/maintain-verification-skill`](../../skills/maintain-verification-skill/SKILL.md) audits the generated skill: one read-only source reader per feature in parallel, then one live pass that drives every mapped feature. It ends in exactly one of three outcomes. `clean` means full coverage and nothing to ship. `changed` means one PR of proven corrections, confined to the verification skill's own directory. `blocked` names the blocker. It never edits product code. If the live pass catches a product regression, it reports the regression instead of hiding it with a doc edit. ## Open the PR diff --git a/harness/pstack/claude-code/docs/guide/07-overnight.md b/harness/pstack/claude-code/docs/guide/07-overnight.md index 623cff349..043ea5197 100644 --- a/harness/pstack/claude-code/docs/guide/07-overnight.md +++ b/harness/pstack/claude-code/docs/guide/07-overnight.md @@ -71,7 +71,7 @@ Before the skill hands back its summary, it spawns a reviewer on a different mod The contract above drives one task to one finish condition. Some nights hold more, a queue of independent changes or a whole program. Three playbooks scale the same trust up. -[Autopilot-full](../../skills/poteto-mode/playbooks/autopilot-full.md) runs a queue of independent PRs to merged. Each PR gets one owner agent that carries it from build through merge, and no owner merges on its own verdict. A swarm of fresh verifiers starts a round at the owner's code-ready head and again at every later push that changes the patch. Only a clean verdict on the patch that merges authorizes the merge: +[Autopilot-full](../../skills/poteto-mode/playbooks/autopilot-full.md) runs a queue of independent PRs to merged. Each PR gets one owner agent that carries it from build through merge, and no owner merges on its own verdict. A swarm of fresh verifiers checks the owner's code-ready head. A later rebase or minor fix gets one fresh verifier, and only new behavior or a large new diff calls the full swarm again. Only a clean verdict on the patch that merges authorizes the merge: ```text /poteto-mode full autopilot on this queue. each item is independent. i want them merged by morning. diff --git a/harness/pstack/claude-code/docs/guide/08-principles.md b/harness/pstack/claude-code/docs/guide/08-principles.md index 5b17980e7..d2921500b 100644 --- a/harness/pstack/claude-code/docs/guide/08-principles.md +++ b/harness/pstack/claude-code/docs/guide/08-principles.md @@ -24,7 +24,7 @@ Say two parallel attempts are about to write to the same branch: separate before serializing shared state. give each attempt its own worktree, no locks. ``` -Each phrase lands because the rule behind it is specific. The agent still has to say, in its reply, which decision the rule changed. A principle citation with no decision behind it is the tell that it name-dropped instead of applying. +Each phrase lands because the rule behind it is specific. The agent still has to say, in its reply, which decision the rule changed. A principle citation with no decision behind it means the agent named the rule without applying it. ## The 24, briefly diff --git a/harness/pstack/claude-code/docs/guide/09-make-it-yours.md b/harness/pstack/claude-code/docs/guide/09-make-it-yours.md index 321caaf91..cb3c20188 100644 --- a/harness/pstack/claude-code/docs/guide/09-make-it-yours.md +++ b/harness/pstack/claude-code/docs/guide/09-make-it-yours.md @@ -1,6 +1,6 @@ # Make it yours -poteto-mode is one person's style. The machinery underneath, playbooks, routing, model roles, works just as well wearing yours. This page covers generating a personal mode, capturing lessons from a session, fixing the repo so agents stop repeating mistakes, authoring a focused skill, and testing a skill change before you trust it. +poteto-mode is one person's style. The playbooks, routing, and model roles underneath it work just as well with yours. This page covers generating a personal mode, capturing lessons from a session, fixing the repo so agents stop repeating mistakes, authoring a focused skill, and testing a skill change before you trust it. Start smaller than you think. You don't need many skills on day one, or even this whole plugin. Prompt plainly, watch where agents fail, and add a skill or a check when the same failure shows up twice. @@ -18,7 +18,7 @@ Run it again whenever your habits drift: /automate-me update my mode skill with everything since its last edit ``` -Update mode mines only the history since the skill last changed. It keeps rules you haven't contradicted, revises the ones with new evidence, and adds sections only for genuinely new patterns. +Update mode mines only the history since the skill last changed. It keeps rules you haven't contradicted, revises the ones with new evidence, and adds sections only for new patterns. ## Capture a session's lessons with `/reflect` @@ -69,7 +69,7 @@ Skills aren't the only prose you ship. For docs, RFCs, readmes, PR descriptions, /technical-writing review the readme changes ``` -[`/technical-writing`](../../skills/technical-writing/SKILL.md) applies a layered standard with one goal, prose a tired engineer understands on the first read. It picks the document's mode first (tutorial, how-to, reference, or explanation), then works sentence by sentence: who does what, one thought per sentence, nothing readable two ways. Use it to review what you or an agent just wrote, or name it up front when you ask for a doc. +[`/technical-writing`](../../skills/technical-writing/SKILL.md) applies a layered standard. Its goal is prose that a tired engineer understands on the first read. It picks the document's mode first (tutorial, how-to, reference, or explanation), then works sentence by sentence: who does what, one thought per sentence, nothing readable two ways. Use it to review what you or an agent just wrote, or name it up front when you ask for a doc. ## Test a skill change blind diff --git a/harness/pstack/claude-code/docs/guide/10-recipes-and-pitfalls.md b/harness/pstack/claude-code/docs/guide/10-recipes-and-pitfalls.md index 68751e7c0..6d2ef465c 100644 --- a/harness/pstack/claude-code/docs/guide/10-recipes-and-pitfalls.md +++ b/harness/pstack/claude-code/docs/guide/10-recipes-and-pitfalls.md @@ -42,7 +42,7 @@ Ask only after the design settles. The plan is the deliverable, and it names the ask /arena for a second opinion on this thread and our approach ``` -Your current design becomes one candidate among several, and the synthesis tells you whether the panel found something better or confirmed what you had. Cheap insurance before a costly commitment. +Your current design becomes one candidate among several, and the synthesis tells you whether the panel found something better or confirmed what you had. It costs little next to a design that is expensive to reverse. ## Check independent slices in parallel @@ -141,7 +141,7 @@ That's the whole prompt. [`/bro`](../../skills/bro/SKILL.md) restates the last m - **Leading with your theory of the cause.** The agent searches wherever you pointed. Ask it to restate the problem first, then share your hunch. - **Taking the first design.** One attempt locks in the first shape the model thought of. Ask for prototypes or `/architect` and pick from evidence. - **Polishing an abstract plan.** Adversarial review of a plan with no code behind it invents risks that will never happen. Settle the open questions with prototypes, then review what got built. -- **Parallel agents in one worktree.** They overwrite each other and the diff becomes archaeology. Run them as cloud agents, or say "own worktree per attempt". +- **Parallel agents in one worktree.** They overwrite each other, and nobody can tell which agent changed what. Run them as cloud agents, or say "own worktree per attempt". - **Looping before you trust the loop.** A loop that can't verify its own work only makes unchecked work faster. Get the verification skill working first. - **Trusting an unvetted number.** A warm cache or a skipped code path can fake a speedup. Run `/benchmark-checklist` before the number goes anywhere. - **Correcting the same mistake by hand.** A correction in chat helps one run. `/correct` fixes the repo so no later run repeats it. diff --git a/pstack/README.md b/pstack/README.md index 8a5c5e804..b7ccf6ee0 100644 --- a/pstack/README.md +++ b/pstack/README.md @@ -4,7 +4,7 @@ i'm [poteto](https://x.com/poteto). i'm not a president or ceo, but i've worked there's a growing sense that ai writes too much slop code. i agree. i don't want to ship like a team of twenty slop artists. throughput without quality is not a goal i aspire to. if you want to go fast, go deep first. -**pstack is my answer.** these are the same skills i use everyday to ship high quality code at Cursor. this turns cursor into a real engineering team. the goal is not to maximize loc, in fact it's the opposite. pstack helps you write less, but higher quality code. +**pstack is my answer.** these are the same skills i use every day to ship high quality code at Cursor. this turns cursor into a real engineering team. the goal is not to maximize loc, in fact it's the opposite. pstack helps you write less, but higher quality code. **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. @@ -27,7 +27,7 @@ in claude code: claude code prefixes plugin commands and agents, so `/poteto-mode` is `/pstack:poteto-mode`. the [claude code adapter](./docs/harness/claude-code.md) maps every other cursor name. in claude code, `/pstack:setup-pstack` writes your model choices to `~/.claude/rules/pstack-models.md`, and a step that needs a cursor-only feature, such as bugbot or automations, is skipped with a one-line note. -claude code installs a generated copy of pstack from [`harness/pstack/`](https://github.com/cursor/plugins/tree/main/harness/pstack) at the repository root. after changing `skills/`, `agents/`, `docs/guide/`, `docs/harness/claude-code.md`, this readme, or `plugin.json`, run `node scripts/generate-pstack-harness-trees.mjs` from the repository root and commit the result. ci fails until you do. +claude code installs a generated copy of pstack, including this readme and the guide, from [`harness/pstack/`](https://github.com/cursor/plugins/tree/main/harness/pstack) at the repository root. after you change pstack, run `node scripts/generate-pstack-harness-trees.mjs` from the repository root and commit the result. ci fails while the generated copy is out of date. ## get started @@ -38,7 +38,7 @@ two steps: new here? the [pstack guide](./docs/guide/README.md) walks you through a first real task, from setup and prompting through verification and overnight runs. stuck, or unsure which skill fits? ask [`/poteto-help`](./skills/poteto-help/SKILL.md). -that's it. the other skills are situational; the mode skill uses them for you as needed. out of the box the mode splits work by model strength: code delegates (feature, refactoring, bug fix, perf, hillclimb) go to grok, while the hardest changes, prose, and judgment go to opus 5.5. the default panel is opus 5.5 / grok. [`/setup-pstack`](./skills/setup-pstack/SKILL.md) changes any of it. +that's it. the other skills are situational, and the mode skill uses them for you as needed. out of the box the mode splits work by model strength: code delegates (feature, refactoring, bug fix, perf, hillclimb) go to grok, while the hardest changes, prose, and judgment go to opus 5.5. the default panel is opus 5.5 / grok. [`/setup-pstack`](./skills/setup-pstack/SKILL.md) changes any of it. ## usage @@ -81,7 +81,7 @@ morning. | [shipping](./skills/poteto-mode/playbooks/shipping.md) | independently verify a green stack, then land the contiguous verified run bottom-up through github by default or origin when available. | | [autonomous run](./skills/poteto-mode/playbooks/autonomous-run.md) | drive a long task to completion without stopping. | | [orchestrate](./skills/poteto-mode/playbooks/orchestrate.md) | a standing project handed to one coordinator chat: multi-day, many stacked prs, fleets of subagents. | -| [autopilot-full](./skills/poteto-mode/playbooks/autopilot-full.md) | run independent prs to merged with one owner per pr and a root swarm verdict on each round, from the code-ready head on. | +| [autopilot-full](./skills/poteto-mode/playbooks/autopilot-full.md) | run independent prs to merged with one owner per pr. a swarm verifies each code-ready head, and every later change to the patch gets a fresh check. | | [autopilot-stack](./skills/poteto-mode/playbooks/autopilot-stack.md) | build and verify one linear base-branch stack for the operator to review and land. | | [session pickup](./skills/poteto-mode/playbooks/session-pickup.md) | resume or take over a prior agent's in-flight work. | | [pause safely](./skills/poteto-mode/playbooks/pause-safely.md) | suspend in-flight work cleanly so it can be resumed later. | @@ -101,7 +101,7 @@ when invoked it: the full rules and playbooks live in [`skills/poteto-mode/SKILL.md`](./skills/poteto-mode/SKILL.md). -to keep [`/poteto-mode`](./skills/poteto-mode/SKILL.md) on across turns, pick it from the `/` menu and press option+enter (mac) or alt+enter (windows) instead of enter. that makes it a [custom mode](https://cursor.com/docs/skills), which cursor offers in the agents window and the cli. it stays in context every turn, applies itself when a playbook matches or the task needs rigor, and stays out of the way otherwise. plain enter attaches it to one message only. say so to opt out, or exit the mode to turn it off. +to keep [`/poteto-mode`](./skills/poteto-mode/SKILL.md) on across turns, pick it from the `/` menu and press option+enter (mac) or alt+enter (windows) instead of enter. that makes it a [custom mode](https://cursor.com/docs/skills#using-a-skill-as-a-custom-mode), which cursor offers in the agents window and the cli. it stays in context every turn until you exit the mode. plain enter attaches it to one message only. [`/poteto-mode`](./skills/poteto-mode/SKILL.md) works extremely well with cursor's `/loop` command. you can make cursor work for many hours without sacrificing rigor. @@ -256,7 +256,7 @@ a few things `poteto-mode` references but doesn't bundle: - `/deslop` and the `deslop` skill ship in the `cursor-team-kit` plugin. - `control-cli` (for CLIs and TUIs) and `control-ui` (for browser, Electron, web) ship in `cursor-team-kit` too. -- `/create-skill` is a cursor built-in. cursor also ships a built-in `/babysit`; inside `poteto-mode`, the [babysit playbook](./skills/poteto-mode/playbooks/babysit.md) supersedes it for pr-status requests. +- `/create-skill` is a cursor built-in. cursor also ships a built-in `/autopilot` that watches a pr. inside `poteto-mode`, pr-status requests go to the [babysit playbook](./skills/poteto-mode/playbooks/babysit.md) instead. install `cursor-team-kit` alongside pstack if you want the full set. diff --git a/pstack/docs/guide/01-setup.md b/pstack/docs/guide/01-setup.md index 62420df82..e28f5cbab 100644 --- a/pstack/docs/guide/01-setup.md +++ b/pstack/docs/guide/01-setup.md @@ -57,6 +57,6 @@ Pick something real but small, and describe it the way you'd describe it to a co Watch the todo list. Its first items are the matched playbook's steps copied in, the Feature playbook for this prompt. If `/poteto-mode` skips a step, the step stays in the list with `skip: `, so you can see what it chose not to do. -From here you can type normal follow-ups. To keep `/poteto-mode` on for the whole chat, pick it from the `/` menu with Option+Enter (Mac) or Alt+Enter (Windows) instead of Enter. That makes it a [Custom Mode](https://cursor.com/docs/skills), which stays in context on every turn until you exit it. Custom Modes are available in the Agents Window and the CLI. Plain Enter attaches the skill to one message, and it fades as the chat moves on. +From here you can type normal follow-ups. To keep `/poteto-mode` on for the whole chat, pick it from the `/` menu with Option+Enter (Mac) or Alt+Enter (Windows) instead of Enter. That makes it a [Custom Mode](https://cursor.com/docs/skills#using-a-skill-as-a-custom-mode), which stays in context on every turn until you exit it. Custom Modes are available in the Agents Window and the CLI. Plain Enter attaches the skill to one message, and it fades as the chat moves on. Next: [Route work through `/poteto-mode`](./02-poteto-mode.md). diff --git a/pstack/docs/guide/02-poteto-mode.md b/pstack/docs/guide/02-poteto-mode.md index 8341604ae..0e6568e17 100644 --- a/pstack/docs/guide/02-poteto-mode.md +++ b/pstack/docs/guide/02-poteto-mode.md @@ -25,7 +25,7 @@ flowchart TD J --> K ``` -The diagram shows the common routes. There are also playbooks for hillclimbing a metric, diagnosing runtime symptoms and captured traces, prototypes, visual parity, authoring and evaluating skills, autonomous runs, babysitting a PR or stack to merge-ready, shipping a verified stack, running a PR queue on autopilot, orchestrating project-scale programs, session pickup, pausing safely, multi-phase plans, and worktree cleanup. The [playbook directory](../../skills/poteto-mode/playbooks/) has the full set. +The diagram shows the common routes. There are also playbooks for hillclimbing a metric, diagnosing runtime symptoms and captured traces, prototypes, visual parity, authoring and evaluating skills, autonomous runs, babysitting a PR or stack to merge-ready, shipping a verified stack, running a PR queue or a stack on autopilot, orchestrating project-scale programs, session pickup, pausing safely, multi-phase plans, and worktree cleanup. The [playbook directory](../../skills/poteto-mode/playbooks/) has the full set. ## Say the goal, not the ceremony diff --git a/pstack/docs/guide/03-understand.md b/pstack/docs/guide/03-understand.md index e15bea052..e26661f91 100644 --- a/pstack/docs/guide/03-understand.md +++ b/pstack/docs/guide/03-understand.md @@ -30,9 +30,9 @@ Ask the question you actually have. [`/how`](../../skills/how/SKILL.md) reads th /why was the retry limit set to five? does the reason still hold? ``` -[`/why`](../../skills/why/SKILL.md) works like a detective on a cold case. It starts from source control, then queries whatever evidence categories your MCPs expose, such as the issue tracker, long-form docs, team chat, observability, error tracking, and analytics, all in parallel. The report cites everything, separates direct evidence from inference, and says "appears to" when the record is thin. A null result gets reported too, because "nobody wrote down why" is itself an answer. +[`/why`](../../skills/why/SKILL.md) starts from source control, then queries whatever evidence categories your MCPs expose, such as the issue tracker, long-form docs, team chat, observability, error tracking, and analytics, all in parallel. The report cites everything, separates direct evidence from inference, and says "appears to" when the record is thin. A null result gets reported too, because "nobody wrote down why" is itself an answer. -The two compose naturally. `do why first then how` is a perfectly good prompt when you suspect the history explains the mess. +The two compose naturally. `do why first then how` is a good prompt when you suspect the history explains the mess. ## Actually understand it with `/teach` @@ -40,7 +40,7 @@ The two compose naturally. `do why first then how` is a perfectly good prompt wh /teach me how this PR changes retries. convince me it fixes the cause and not the symptom. ``` -[`/teach`](../../skills/teach/SKILL.md) is for when a summary isn't enough. It runs `/how` and `/why`, for a small change maybe just one of them, and weaves the findings into a plain explanation that builds up diagram by diagram. The "convince me" framing is worth stealing. It turns the explanation into an argument you can poke at instead of a tour. +[`/teach`](../../skills/teach/SKILL.md) is for when a summary isn't enough. It runs `/how` and `/why`, for a small change maybe just one of them, and weaves the findings into a plain explanation that builds up diagram by diagram. The "convince me" framing is worth reusing. It turns the explanation into an argument you can test instead of a tour. It works on the agent's own choices too: diff --git a/pstack/docs/guide/04-design.md b/pstack/docs/guide/04-design.md index 61d5bbb59..65862086a 100644 --- a/pstack/docs/guide/04-design.md +++ b/pstack/docs/guide/04-design.md @@ -2,7 +2,7 @@ One attempt at a hard design locks in the first shape the model thought of. `/architect` settles types and boundaries before implementation. `/arena` runs several attempts at the same brief and merges the best parts. `/interrogate` has other models try to break the result. When the job is coverage rather than design synthesis, `/swarm` fans out slices or races and aggregates their results. -The two most common design mistakes are taking the agent's first design and polishing a plan that no code has tested. This page fixes both. You plan through code: prototypes answer the open questions, a README or tutorial sets the target, and the written plan comes last. +The two most common design mistakes are taking the agent's first design and polishing a plan that no code has tested. This page fixes both. You plan through code. Prototypes answer the open questions, a README or tutorial sets the target, and the written plan comes last. ![Three robots draft competing bridge models at their own tables under /architect, /arena, and /interrogate panels, while a judge robot with a clipboard inspects skeptically.](./images/design.jpg) diff --git a/pstack/docs/guide/05-build-and-clean.md b/pstack/docs/guide/05-build-and-clean.md index fc48a46df..dbadc3d41 100644 --- a/pstack/docs/guide/05-build-and-clean.md +++ b/pstack/docs/guide/05-build-and-clean.md @@ -1,6 +1,6 @@ # Build the change and clean the diff -The build playbooks share one discipline. Say what you observed, let the playbook demand the evidence. This page shows what to put in the prompt for each common build task, then the cleanup habit that keeps diffs reviewable. +The build playbooks share one discipline. Say what you observed, and let the playbook demand the evidence. This page shows what to put in the prompt for each common build task, then the cleanup habit that keeps diffs reviewable. ## Prompt each build playbook with what you know @@ -22,7 +22,7 @@ A refactoring prompt pins behavior before structure moves: /poteto-mode move parsing into one module, zero behavior change. record the current output first and prove it's unchanged after. ``` -A perf prompt states the measurement, not a vibe: +A perf prompt states the measurement, not an impression: ```text /poteto-mode startup takes 1.8s on this fixture. trace it, fix the measured cause, show me before and after. diff --git a/pstack/docs/guide/06-verify-and-ship.md b/pstack/docs/guide/06-verify-and-ship.md index 007ea2cab..2fa0c8d8f 100644 --- a/pstack/docs/guide/06-verify-and-ship.md +++ b/pstack/docs/guide/06-verify-and-ship.md @@ -14,7 +14,7 @@ Put what done means in the first prompt, in whatever words fit: /poteto-mode add json output to this command. text output stays byte-identical, the json parses, both run against the sample project. show me the evidence. ``` -Now the agent has three checks it can run, not a mood to satisfy. When the reply comes back, it should carry the exact commands and outputs. If a check couldn't run, a good reply says "inconclusive", and you should treat a confident reply without evidence as a red flag. +Now the agent has three checks it can run, not a mood to satisfy. When the reply comes back, it should carry the exact commands and outputs. If a check couldn't run, a good reply says "inconclusive". A confident reply without evidence is a warning sign. Match the check to the change: @@ -26,7 +26,7 @@ Match the check to the change: Ask for the proof as an artifact you can inspect yourself: the failing test and then the passing one, a before-and-after video, the trace, the screenshot. If the fix already merged, ask for the same check again on main. An artifact beats a plausible explanation, because you can challenge it without replaying the whole run. -For a small diff you don't fully trust, [`/blast-radius`](../../skills/blast-radius/SKILL.md) finds what it could break elsewhere. It picks the one fact the change is safe because of and proves it by running code instead of writing an essay about it. +For a small diff you don't fully trust, [`/blast-radius`](../../skills/blast-radius/SKILL.md) finds what it could break elsewhere. It finds the one fact that makes the change safe and proves that fact by running code, not by arguing for it. ## Vet a measured number with `/benchmark-checklist` @@ -85,13 +85,13 @@ While you're there, make the dev setup repeatable too: seeded data, test users, ## Keep the verification skill honest -Apps change and feature maps rot. Run this at least once a day, ideally from a scheduled automation so nobody has to remember: +Apps change, and feature maps go out of date. Run this at least once a day, ideally from a scheduled automation so nobody has to remember: ```text /maintain-verification-skill ``` -[`/maintain-verification-skill`](../../skills/maintain-verification-skill/SKILL.md) audits the generated skill: one read-only source reader per feature in parallel, then one live pass that drives every mapped feature. It ends in exactly one of three outcomes. `clean` means full coverage and nothing to ship. `changed` means one PR of proven corrections, confined to the verification skill's own directory. `blocked` names the blocker. It never edits product code. If the live pass catches a product regression, it reports the regression instead of papering over it in docs. +[`/maintain-verification-skill`](../../skills/maintain-verification-skill/SKILL.md) audits the generated skill: one read-only source reader per feature in parallel, then one live pass that drives every mapped feature. It ends in exactly one of three outcomes. `clean` means full coverage and nothing to ship. `changed` means one PR of proven corrections, confined to the verification skill's own directory. `blocked` names the blocker. It never edits product code. If the live pass catches a product regression, it reports the regression instead of hiding it with a doc edit. ## Open the PR diff --git a/pstack/docs/guide/07-overnight.md b/pstack/docs/guide/07-overnight.md index cbad06723..625144b30 100644 --- a/pstack/docs/guide/07-overnight.md +++ b/pstack/docs/guide/07-overnight.md @@ -71,7 +71,7 @@ Before the skill hands back its summary, it spawns a reviewer on a different mod The contract above drives one task to one finish condition. Some nights hold more, a queue of independent changes or a whole program. Three playbooks scale the same trust up. -[Autopilot-full](../../skills/poteto-mode/playbooks/autopilot-full.md) runs a queue of independent PRs to merged. Each PR gets one owner agent that carries it from build through merge, and no owner merges on its own verdict. A swarm of fresh verifiers starts a round at the owner's code-ready head and again at every later push that changes the patch. Only a clean verdict on the patch that merges authorizes the merge: +[Autopilot-full](../../skills/poteto-mode/playbooks/autopilot-full.md) runs a queue of independent PRs to merged. Each PR gets one owner agent that carries it from build through merge, and no owner merges on its own verdict. A swarm of fresh verifiers checks the owner's code-ready head. A later rebase or minor fix gets one fresh verifier, and only new behavior or a large new diff calls the full swarm again. Only a clean verdict on the patch that merges authorizes the merge: ```text /poteto-mode full autopilot on this queue. each item is independent. i want them merged by morning. diff --git a/pstack/docs/guide/08-principles.md b/pstack/docs/guide/08-principles.md index 5b17980e7..d2921500b 100644 --- a/pstack/docs/guide/08-principles.md +++ b/pstack/docs/guide/08-principles.md @@ -24,7 +24,7 @@ Say two parallel attempts are about to write to the same branch: separate before serializing shared state. give each attempt its own worktree, no locks. ``` -Each phrase lands because the rule behind it is specific. The agent still has to say, in its reply, which decision the rule changed. A principle citation with no decision behind it is the tell that it name-dropped instead of applying. +Each phrase lands because the rule behind it is specific. The agent still has to say, in its reply, which decision the rule changed. A principle citation with no decision behind it means the agent named the rule without applying it. ## The 24, briefly diff --git a/pstack/docs/guide/09-make-it-yours.md b/pstack/docs/guide/09-make-it-yours.md index 321caaf91..cb3c20188 100644 --- a/pstack/docs/guide/09-make-it-yours.md +++ b/pstack/docs/guide/09-make-it-yours.md @@ -1,6 +1,6 @@ # Make it yours -poteto-mode is one person's style. The machinery underneath, playbooks, routing, model roles, works just as well wearing yours. This page covers generating a personal mode, capturing lessons from a session, fixing the repo so agents stop repeating mistakes, authoring a focused skill, and testing a skill change before you trust it. +poteto-mode is one person's style. The playbooks, routing, and model roles underneath it work just as well with yours. This page covers generating a personal mode, capturing lessons from a session, fixing the repo so agents stop repeating mistakes, authoring a focused skill, and testing a skill change before you trust it. Start smaller than you think. You don't need many skills on day one, or even this whole plugin. Prompt plainly, watch where agents fail, and add a skill or a check when the same failure shows up twice. @@ -18,7 +18,7 @@ Run it again whenever your habits drift: /automate-me update my mode skill with everything since its last edit ``` -Update mode mines only the history since the skill last changed. It keeps rules you haven't contradicted, revises the ones with new evidence, and adds sections only for genuinely new patterns. +Update mode mines only the history since the skill last changed. It keeps rules you haven't contradicted, revises the ones with new evidence, and adds sections only for new patterns. ## Capture a session's lessons with `/reflect` @@ -69,7 +69,7 @@ Skills aren't the only prose you ship. For docs, RFCs, readmes, PR descriptions, /technical-writing review the readme changes ``` -[`/technical-writing`](../../skills/technical-writing/SKILL.md) applies a layered standard with one goal, prose a tired engineer understands on the first read. It picks the document's mode first (tutorial, how-to, reference, or explanation), then works sentence by sentence: who does what, one thought per sentence, nothing readable two ways. Use it to review what you or an agent just wrote, or name it up front when you ask for a doc. +[`/technical-writing`](../../skills/technical-writing/SKILL.md) applies a layered standard. Its goal is prose that a tired engineer understands on the first read. It picks the document's mode first (tutorial, how-to, reference, or explanation), then works sentence by sentence: who does what, one thought per sentence, nothing readable two ways. Use it to review what you or an agent just wrote, or name it up front when you ask for a doc. ## Test a skill change blind diff --git a/pstack/docs/guide/10-recipes-and-pitfalls.md b/pstack/docs/guide/10-recipes-and-pitfalls.md index 68751e7c0..6d2ef465c 100644 --- a/pstack/docs/guide/10-recipes-and-pitfalls.md +++ b/pstack/docs/guide/10-recipes-and-pitfalls.md @@ -42,7 +42,7 @@ Ask only after the design settles. The plan is the deliverable, and it names the ask /arena for a second opinion on this thread and our approach ``` -Your current design becomes one candidate among several, and the synthesis tells you whether the panel found something better or confirmed what you had. Cheap insurance before a costly commitment. +Your current design becomes one candidate among several, and the synthesis tells you whether the panel found something better or confirmed what you had. It costs little next to a design that is expensive to reverse. ## Check independent slices in parallel @@ -141,7 +141,7 @@ That's the whole prompt. [`/bro`](../../skills/bro/SKILL.md) restates the last m - **Leading with your theory of the cause.** The agent searches wherever you pointed. Ask it to restate the problem first, then share your hunch. - **Taking the first design.** One attempt locks in the first shape the model thought of. Ask for prototypes or `/architect` and pick from evidence. - **Polishing an abstract plan.** Adversarial review of a plan with no code behind it invents risks that will never happen. Settle the open questions with prototypes, then review what got built. -- **Parallel agents in one worktree.** They overwrite each other and the diff becomes archaeology. Run them as cloud agents, or say "own worktree per attempt". +- **Parallel agents in one worktree.** They overwrite each other, and nobody can tell which agent changed what. Run them as cloud agents, or say "own worktree per attempt". - **Looping before you trust the loop.** A loop that can't verify its own work only makes unchecked work faster. Get the verification skill working first. - **Trusting an unvetted number.** A warm cache or a skipped code path can fake a speedup. Run `/benchmark-checklist` before the number goes anywhere. - **Correcting the same mistake by hand.** A correction in chat helps one run. `/correct` fixes the repo so no later run repeats it. diff --git a/scripts/check-pstack-docs.mjs b/scripts/check-pstack-docs.mjs new file mode 100644 index 000000000..6d83163c8 --- /dev/null +++ b/scripts/check-pstack-docs.mjs @@ -0,0 +1,152 @@ +#!/usr/bin/env node + +// Lists pstack's skills, playbooks, and agents from the tree and checks what pstack/README.md and pstack/docs/guide +// say about them: slash commands, relative links and anchors, the README tables, counts, and model names. +// Exits 1 when the docs drift from the tree. + +import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; +import { dirname, join, posix } from "node:path"; +import { fileURLToPath } from "node:url"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const PSTACK = join(ROOT, "pstack"); +const GUIDE = "docs/guide"; +const SETUP = join(PSTACK, "skills", "setup-pstack", "SKILL.md"); + +// Commands that ship with Cursor or Claude Code, not in this repository. Nothing here can verify them, so add a name +// only after a public Cursor or Claude Code doc shows it. +const EXTERNAL = new Set(["add-plugin", "autopilot", "create-skill", "in-cloud", "loop", "plugin"]); +const RENAMED = new Map([["babysit", "autopilot"]]); + +const SMALL = "zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split(" "); +const TENS = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]; +// "The twenty-three playbooks" claims the whole set. "Three playbooks scale it up" names a subset, so it is not checked. +const CLAIM = /\b(?:(all|has|of|ships|the|with) )?(\d+|[a-z]+(?:-[a-z]+)?) (short )?(skills|principles|playbooks|agents)\b/gi; +const SLASH = /(?<=^|[\s`(|"'>])\/(?:pstack:)?([a-z][a-z0-9-]*)(?![\w/<-])/gm; +const LINK = /\]\(]+)>?(?:\s+"[^"]*")?\)/g; +const AGENT = /subagent_type: "([^"]+)"/g; +const MODEL_ID = /\b(?:claude-[a-z]+|grok|gpt)-\d(?:[\w.-]*\w)?/g; +const MODEL_PROSE = /\b(opus|sonnet|grok) (\d+(?:\.\d+)?)\b/gi; + +function names(dir, keep) { + return existsSync(dir) ? readdirSync(dir).filter((name) => keep(join(dir, name))).sort() : []; +} +const isSkill = (path) => existsSync(join(path, "SKILL.md")); +const isMarkdown = (path) => path.endsWith(".md") && statSync(path).isFile(); + +const skills = names(join(PSTACK, "skills"), isSkill); +const principles = skills.filter((name) => name.startsWith("principle-")); +const commands = skills.filter((name) => !name.startsWith("principle-")); +const playbooks = names(join(PSTACK, "skills", "poteto-mode", "playbooks"), isMarkdown).map((name) => name.slice(0, -3)); +const agents = names(join(PSTACK, "agents"), isMarkdown).map((name) => name.slice(0, -3)); +const teamKit = names(join(ROOT, "cursor-team-kit", "skills"), isSkill); +const docs = ["README.md", ...names(join(PSTACK, GUIDE), isMarkdown).map((name) => `${GUIDE}/${name}`)]; +const text = new Map(docs.map((doc) => [doc, readFileSync(join(PSTACK, doc), "utf8")])); +const setup = readFileSync(SETUP, "utf8"); + +const problems = []; +const lineOf = (doc, index) => text.get(doc).slice(0, index).split("\n").length; +const fail = (doc, index, message) => problems.push(`${doc}:${lineOf(doc, index)} ${message}`); + +function toNumber(word) { + if (/^\d+$/.test(word)) return Number(word); + const [tens, unit] = word.toLowerCase().split("-"); + if (unit === undefined && SMALL.includes(tens)) return SMALL.indexOf(tens); + const ones = unit === undefined ? 0 : SMALL.indexOf(unit); + return TENS.indexOf(tens) > 1 && ones >= 0 && ones < 10 ? TENS.indexOf(tens) * 10 + ones : undefined; +} + +function anchors(path) { + const seen = new Map(); + const found = new Set(); + let fenced = false; + for (const line of readFileSync(join(PSTACK, path), "utf8").split("\n")) { + if (/^\s*(```|~~~)/.test(line)) fenced = !fenced; + const heading = !fenced && line.match(/^#{1,6}\s+(.*?)\s*$/); + if (!heading) continue; + const plain = heading[1].replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*]/g, ""); + const slug = plain.trim().toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-"); + const repeat = seen.get(slug) ?? 0; + seen.set(slug, repeat + 1); + found.add(repeat ? `${slug}-${repeat}` : slug); + } + return found; +} + +const expected = { + skills: [skills.length, commands.length], + principles: [principles.length], + playbooks: [playbooks.length], + agents: [agents.length], +}; +const named = new Map(docs.map((doc) => [doc, new Set()])); +let slashes = 0; +let links = 0; + +for (const [doc, body] of text) { + for (const { 0: match, 1: whole, 2: word, 3: short, 4: noun, index } of body.matchAll(CLAIM)) { + const claimed = toNumber(word); + const kind = short ? "principles" : noun.toLowerCase(); + if ((whole || short) && claimed !== undefined && !expected[kind].includes(claimed)) { + fail(doc, index, `says "${match}", but the tree has ${expected[kind].join(" or ")}`); + } + } + for (const { 1: name, index } of body.matchAll(SLASH)) { + slashes++; + if (skills.includes(name)) named.get(doc).add(name); + else if (RENAMED.has(name)) fail(doc, index, `names /${name}, which Cursor now ships as /${RENAMED.get(name)}`); + else if (!teamKit.includes(name) && !EXTERNAL.has(name)) { + fail(doc, index, `names /${name}, which no pstack skill, cursor-team-kit skill, or listed built-in provides`); + } + } + for (const { 1: href, index } of body.matchAll(LINK)) { + if (/^[a-z][a-z0-9+.-]*:/i.test(href)) continue; + links++; + const [target, anchor] = href.split("#"); + const path = target ? posix.normalize(posix.join(posix.dirname(doc), target)).replace(/\/$/, "") : doc; + const skill = path.match(/^skills\/([^/]+)\/SKILL\.md$/); + if (skill) named.get(doc).add(skill[1]); + if (!existsSync(join(PSTACK, path))) fail(doc, index, `links to ${href}, which does not exist`); + else if (anchor && path.endsWith(".md") && !anchors(path).has(anchor)) { + fail(doc, index, `links to ${href}, but ${path} has no heading with that anchor`); + } + } + for (const { 1: name, index } of body.matchAll(AGENT)) { + if (!agents.includes(name)) fail(doc, index, `names subagent_type "${name}", which pstack/agents does not ship`); + } + for (const { 0: id, index } of body.matchAll(MODEL_ID)) { + if (!setup.includes(id)) fail(doc, index, `names model ${id}, which setup-pstack does not use`); + } + for (const { 0: match, 1: family, 2: version, index } of body.matchAll(MODEL_PROSE)) { + const prefix = family.toLowerCase() === "grok" ? `grok-${version}` : `claude-${family.toLowerCase()}-${version.replace(".", "-")}`; + if (!setup.includes(prefix)) fail(doc, index, `says "${match}", but setup-pstack has no ${prefix} default`); + } +} + +const readme = text.get("README.md"); +for (const skill of skills) { + if (!readme.includes(`(./skills/${skill}/SKILL.md)`)) problems.push(`README.md does not list skill ${skill}`); +} +for (const playbook of playbooks) { + if (!readme.includes(`(./skills/poteto-mode/playbooks/${playbook}.md)`)) problems.push(`README.md does not list playbook ${playbook}`); +} +for (const agent of agents) { + if (!readme.includes(`(./agents/${agent}.md)`)) problems.push(`README.md does not link agent ${agent}`); +} + +const inDocs = new Set([...named.values()].flatMap((set) => [...set])); +const inGuide = new Set(docs.filter((doc) => doc !== "README.md").flatMap((doc) => [...named.get(doc)])); +const unnamed = commands.filter((name) => !inGuide.has(name)); +console.log( + `tree: ${skills.length} skills (${commands.length} commands, ${principles.length} principles), ` + + `${playbooks.length} playbooks, ${agents.length} agents`, +); +console.log( + `docs: ${docs.length} files, ${slashes} slash mentions, ${links} relative links, ` + + `${commands.filter((name) => inDocs.has(name)).length} of ${commands.length} commands named, ` + + `${commands.length - unnamed.length} of ${commands.length} in the guide`, +); +if (unnamed.length > 0) console.log(`note: the guide never names ${unnamed.map((name) => `/${name}`).join(", ")}`); +for (const problem of problems) console.log(`FAIL ${problem}`); +console.log(`${problems.length} problems`); +if (problems.length > 0) process.exit(1);