poteto's rigorous engineering skills (poteto-mode, how/why, architect, verification), ported from Cursor and kept in sync with upstream

i'm poteto. i'm not a president or ceo, but i've worked with millions of lines of code at Meta, Netflix, and Cursor. i'm also on the react core team where i help build and maintain react compiler.
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 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.
fork it. improve it. make it yours. PRs are welcome!
/add-plugin pstack
two steps:
/setup-pstack, pick a reasoning budget, and choose which models you want./poteto-mode whenever you're doing anything that requires rigor.new here? the pstack guide 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.
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 changes any of it.
use /poteto-mode at the start of a task. it reads your request, picks from a set of playbooks, and runs the other skills as the steps need them.
/poteto-modethis skill is the main shortcut. i use it whenever i need the agent to do rigorous engineering work. it comes with twenty-three playbooks:
/poteto-mode this pr has a subtle bug where the scroll drifts every 750ms even when idle. repro
first, then fix and verify.
/poteto-mode i'm going to bed. land the stack even if ci flakes. i want everything merged by
morning.
| playbook | for |
|---|---|
| investigation | a read-only question. how does x work, why was y built this way, are we sure. |
| bug fix | reproduce a defect, root-cause it, and fix with runtime evidence. |
| perf | trace a measured slowness and improve it against a baseline. |
| hillclimb | sustained, scientific improvement of one metric against a target, looping hypotheses with before/after measurement and one commit per accepted win. |
| runtime forensics | diagnose a live symptom (leak, idle-cpu spin, glitch) from instrumentation. |
| trace forensics | diagnose a captured profiling artifact (cpuprofile, trace, spindump, heap snapshot). |
| feature | new or changed behavior, built from a named data shape. |
| refactoring | a behavior-preserving change to structure or shape. |
| prototype | a throwaway sketch to make a design or behavioral decision cheaply, or to settle an empirical fork by observing it. |
| visual parity | pixel-exact ui equivalence between two implementations. |
| authoring a skill | writing or editing a SKILL.md. |
| eval | test how a skill or prompt change affects agent behavior, blinded. |
| babysit | drive a pr or a stack to merge-ready: conflicts, review threads, ci. |
| shipping | independently verify a green stack, then land the contiguous verified run bottom-up through github by default or origin when available. |
| autonomous run | drive a long task to completion without stopping. |
| orchestrate | a standing project handed to one coordinator chat: multi-day, many stacked prs, fleets of subagents. |
| autopilot-full | 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-stack | build and verify one linear base-branch stack for the operator to review and land. |
| session pickup | resume or take over a prior agent's in-flight work. |
| pause safely | suspend in-flight work cleanly so it can be resumed later. |
| multi-phase plan | work that spans phases or stacked PRs. |
| worktree cleanup | reclaim disk by pruning merged or abandoned worktrees and stale ios simulators, safety-gated. |
| opening a pr | open a ready pr from small ordered commits with a conventional commits title and a briefing-style body. invoked at the end of every other playbook. |
when invoked it:
the full rules and playbooks live in skills/poteto-mode/SKILL.md.
to keep /poteto-mode 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, 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.
/poteto-mode works extremely well with cursor's /loop command. you can make cursor work for many hours without sacrificing rigor.
/poteto-mode runs most of these for you when a step needs them (how, why, architect, arena, swarm, interrogate, unslop, no-comments, technical-writing, tdd, and the principles). the table below is for when you want one directly:
/how do we cancel runs? do we have an n+1 when we look up every run to cancel?
/interrogate review this pr.
| skill | use it when |
|---|---|
/poteto-mode | default entry point for any non-trivial task. |
/poteto-help | you're new to pstack, or unsure which skill, playbook, or principle fits. finds out what you're trying to do, answers that part, and hands you a prompt to type. runs only when you type /poteto-help. |
/how | you want a walkthrough of how a subsystem works. |
/why | you want to know why something was built this way. discovers available MCPs at run time and queries each evidence category in parallel (source control, issue tracker, long-form docs, real-time chat, infra observability, error tracking, analytics warehouse). |
/recall | you're starting or resuming work and want your recent context on a topic rebuilt from your own chat history and the shared record, handed back as a tight current-state brief. |
/blast-radius | you have a small-looking change and want to know what else it could break, with the one fact it's safe because of proven by running code, not asserted. |
/architect | you're about to write code that crosses a function boundary and want the caller's usage, types, and module shape settled first. |
/arena | you want N parallel attempts at the same thing, then to grab the best parts of each. |
/swarm | you want N parallel workers across different slices or races, then one aggregated report. |
/interrogate | you have a diff and want different models to try to break it, including a strict code-quality lens. |
/automate-me | you want your own -mode skill, drafted from how you've actually worked. |
/make-bot-ui | you want a page or dashboard whose buttons wake a Grok Bot over a webhook, including the sender-key handoff and Tailscale. |
/setup-pstack | you want to pick which models pstack uses per role. detects your models and writes a config rule. |
/reflect | a long task landed and you want the recipe captured as a skill edit. |
/correct | you keep correcting agents for the same mistakes. mines history for mistake classes, fixes each at the highest level that works (architecture, then types, lint, and ci, then tests, with docs last), and keeps a table pairing each rule with what enforces it. |
/teach | you want to actually understand a change or subsystem, not just have it summarized. runs how + why and weaves one plain explanation, built up diagram by diagram. |
/tdd | you're fixing a bug and there's a cheap local test path. write the failing test first, then the fix. |
/benchmark-checklist | you ran a benchmark or measured a speedup or regression. vets the number (limiter, tuning, errors, repeat runs, end-to-end relevance) before you report or act on it. |
/no-comments | strip comments before review; spawns Comment Sicko, fixes accepted findings, offers encodings for claimed constraints. |
/typescript-best-practices | you're reading or editing typescript. grounds the type-system-discipline principle in syntax. |
/figure-it-out | no bundled playbook fits. designs a rigorous, auditable playbook for the task. |
/show-me-your-work | you want a reviewable decision trail. logs decisions to a tsv you can commit. |
/create-verification-skill | your project has no scripted way to prove app behavior. generates a project-local verify skill with a feature map, for any language or platform. |
/maintain-verification-skill | your verify skill's feature map has drifted from the app. source wave + one live pass, at most one PR of proven corrections. |
/unslop | you're cleaning up writing. removes AI tells. |
/bro | you want the last message restated in plain human language, no jargon. |
/technical-writing | layered doc standard (Diátaxis + Google developer style + STE + Global English) for docs, RFCs, readmes, PR descriptions, commit messages. |
mostly i type /poteto-mode at the start of a task and let it route to a playbook. the other skills fire as the steps need them. a few i reach for directly.
bug fix: /poteto-mode this pr has a subtle bug where the scroll drifts every 750ms even
when idle. repro first, then fix and verify.
perf: /poteto-mode a big list takes a second or two to load even though we virtualize.
run a cpu trace and tell me why.
feature: /poteto-mode build a small feature behind a feature flag. verify it really works.
prototype: /poteto-mode build two prototypes of the markdown renderer so we can compare.
spawn an agent for each.
multi-phase: /poteto-mode open source these skills as a plugin. nothing internal leaks, work
in a temp dir, show me the dependency graph first.
overnight run: /poteto-mode i'm going to bed. land the stack even if ci flakes. i want
everything merged by morning.
babysit: /poteto-mode check on pr 123. anything outstanding?
visual parity: /poteto-mode the row spacing is too tall when this flag is on. the second image
is correct. repro and fix until it matches.
figure it out: /poteto-mode i'm stepping away. migrate every caller from the synchronous store
to the new async one, keeping behavior identical. i want to trust it was done
right when i'm back.
how: /how do we cancel runs? do we have an n+1 when we look up every run to cancel?
why: /why is this feature flag not on yet?
architect: design this instrumentation to be high signal with no false positives. /architect
this first.
arena: /arena take my prompt to the arena verbatim. i want to compare their proposals
with yours.
swarm: /swarm check every package under packages/ against its check.sh. one worker per
package. one report.
interrogate: /interrogate review this pr.
tdd: /tdd implement
unslop: can we unslop and tighten the new changes?
reflect: /reflect that took too long. capture what we learned so the next run doesn't
repeat it.
correct: /correct
show-me-your-work: /show-me-your-work keep a decision trail i can review when i'm back.
automate-me: /automate-me
help: /poteto-help which skill should i use to review this branch?
poteto-agent and Comment Sicko subagentspstack also ships a subagent that runs my style end to end. spawn it from a parent agent via subagent_type: "poteto-agent". it reads poteto-mode in full, including its inline principles index, before doing any work. substituting generalPurpose skips that read and drifts.
/poteto-mode and subagent_type: "poteto-agent" route through the same wrapper.
pstack also ships Comment Sicko, a read-only comment reviewer available as subagent_type: "Comment Sicko". usually invoke it through /no-comments, not directly.
twenty-four short skills, one principle each. poteto-mode indexes them inline and reads that index at task start. the standalone files are there so other skills can reference a principle by name, and so the index can point at the full rule for each.
| principle | group | rule |
|---|---|---|
| laziness-protocol | core | Bias toward deletion and the smallest change that solves the problem. |
| foundational-thinking | core | Apply before writing logic: choosing core types and data structures, sequencing scaffold-vs-feature work, asking what concurrent actors share. Get the data structures right so downstream code becomes obvious. |
| redesign-from-first-principles | core | Redesign as if the requirement had been a foundational assumption from day one, instead of bolting it on. |
| attack-the-premise | core | Apply when two or more fixes that share one premise have failed the same gate. Take a census of which actors hold the imbalance before the next fix, then question the premise instead of writing another fix that assumes it. |
| subtract-before-you-add | core | Remove dead weight, redundant validators, and stub references first, then build on the simpler base. |
| minimize-reader-load | core | Count layers between question and answer, and hidden state in the reader's head; collapse one-caller wrappers and shrink mutable scope. |
| outcome-oriented-execution | core | Apply during planned rewrites and migrations with explicit phase boundaries. Converge on the target architecture; don't preserve smooth intermediate states with throwaway compatibility code. |
| experience-first | core | Choose user delight over implementation convenience; ship fewer polished features over more rough ones. |
| exhaust-the-design-space | core | Build 2-3 competing prototypes and compare side by side before committing. |
| build-the-lever | core | Apply to any non-trivial work, not just bulk work: edits, migrations, analyses, checks. Build the tool that does it or proves it (codemod, script, generator, or a skill your subagents follow) instead of working by hand. The tool is the artifact a reviewer can rerun. |
| model-the-domain | architecture | Encode the domain in a structure instead of scattered conditionals. |
| boundary-discipline | architecture | Concentrate guards at system boundaries (CLI, config, network, external APIs); trust internal types and keep business logic in pure functions. |
| type-system-discipline | architecture | Make illegal states unrepresentable, brand semantic primitives, parse external data at boundaries, refuse to lie to the compiler, exhaust variants, derive from authoritative schemas. |
| make-operations-idempotent | architecture | Converge to the same end state regardless of partial prior runs. |
| migrate-callers-then-delete-legacy-apis | architecture | Migrate callers and delete the old API in the same wave instead of preserving compatibility layers. |
| separate-before-serializing-shared-state | architecture | Eliminate the sharing first; serialize structurally only when one shared writer is a real invariant. |
| prove-it-works | verification | Apply after completing a task, before declaring done. Verify against the real artifact (run the feature, read the actual value, inspect the diff), not a proxy, self-report, or 'it compiles.'. |
| fix-root-causes | verification | Trace each symptom to its root cause and fix it there; reproduce first, ask why until you reach it, resist nil-check guards that silence crashes. |
| sequence-verifiable-units | verification | Apply to multi-step work (sweeps, migrations, runs of similar edits) and to how you stack commits and PRs. Break work into small units that each end in a verifiable state, check each before the next, and order delivery so the sequence proves itself to a reviewer. |
| test-behavior-not-implementation | verification | Apply when you write, change, or keep a test. Call the code the way its users do and assert the result they observe against a literal expected value. If the test would still pass when every imported function returns undefined, rewrite the assertion or delete the test. |
| explain-the-number | verification | Apply before you trust, report, or act on a number you measured: a speedup, a regression, a throughput, a latency, or an eval result. Find what limits it, and rule out that it measured something other than the work you think. |
| guard-the-context-window | delegation | Route bulk to subagents; keep summaries in the main thread, not raw payloads. |
| never-block-on-the-human | delegation | Proceed, present the result, let the human course-correct after the fact; reserve confirmation for irreversible actions. |
| encode-lessons-in-structure | meta | Encode the rule as a lint, metadata flag, runtime check, or script instead of more text. |
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 supersedes it for pr-status requests.install cursor-team-kit alongside pstack if you want the full set.
cursor already has a great plan mode which works great with pstack. but personally, i don't believe in planning. the best spec is code. if you do want to make a plan, /poteto-mode covers it, but it's not a default.
poteto-mode is my style. you may not want exactly that.
type /automate-me. it mines your recent transcripts, drafts a <your-name>-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. 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.
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 diff
hooks/register.tsx 334 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { PstackLoaded, PstackSkill } from '../types'
5import { descriptionFrom, grouped } from './catalog'
6import { POTETO_OFF, potetoSection, storeKey } from './poteto'
7import { agentModel, agentType, harnessNote, modelsFrom } from './translate'
8
9// The org's security plugin can bypass user-tier skill.prompt hooks, so the note rides prompt.submit and Read instead
10const PSTACK_COMMAND = /^\/pstack:(\S+)/
11const PANE = 'pstack'
12const HIDDEN_KEY = 'hidden'
13const LOADED_TAB = 'Loaded'
14const LOADED_NOTES: Record<PstackLoaded['via'], string> = {
15 read: 'read this session',
16 run: 'run this session',
17 skill: 'loaded by Claude this session',
18}
19const WORDMARK =['█▀█ █▀ ▀█▀ ▄▀█ █▀▀ █▄▀', '█▀▀ ▄█ █ █▀█ █▄▄ █ █']
20
21const poteto = atom({ plugin: 'pstack', key: 'poteto' } as const, false)
22const skills = atom({ plugin: 'pstack', key: 'skills' } as const, [])
23const hidden = atom({ plugin: 'pstack', key: 'hidden' } as const, [])
24const group = atom({ plugin: 'pstack', key: 'group' } as const, '')
25const loaded = atom({ plugin: 'pstack', key: 'loaded' } as const, [])
26const pinned = atom({ plugin: 'pstack', key: 'pinned' } as const, false)
27
28// Mirrors the project's stored choice into session state, which prompt.submit reads
29async function loadPoteto($: EngineInterface, isDefault: boolean): Promise<boolean> {
30 const stored = await $.store.get(storeKey(await $.session.root()))
31 const isOn = typeof stored === 'boolean' ? stored : isDefault
32 await update($, poteto, () => isOn)
33
34 return isOn
35}
36
37async function togglePoteto($: EngineInterface, isDefault: boolean): Promise<void> {
38 const isOn = !(await loadPoteto($, isDefault))
39 await $.store.set(storeKey(await $.session.root()), isOn)
40 await update($, poteto, () => isOn)
41 $.ui.toast(isOn ? 'poteto mode on' : 'poteto mode off')
42}
43
44// Every folder under skills/ with its frontmatter description, read once per session
45async function loadSkills($: EngineInterface): Promise<void> {
46 const entries = await $.fs.list(`${$.plugin.root}/skills`).catch(() => [])
47 const found: PstackSkill[] = await Promise.all(
48 entries
49 .filter(entry => entry.kind === 'dir')
50 .map(async entry => ({
51 name: entry.name,
52 description: descriptionFrom(String(await $.fs.read(`${$.plugin.root}/skills/${entry.name}/SKILL.md`).catch(() => ''))),
53 })),
54 )
55 await update($, skills, () => found)
56
57 const stored = await $.store.get(HIDDEN_KEY)
58 await update($, hidden, () => (Array.isArray(stored) ? stored.filter(name => typeof name === 'string') : []))
59}
60
61// Only the pane header shows it, so a manifest that does not parse must not stop session.start
62function versionFrom(manifest: string): string {
63 try {
64 const version: unknown = JSON.parse(manifest).version
65
66 return typeof version === 'string' ? version : ''
67 } catch {
68 return ''
69 }
70}
71
72async function markLoaded($: EngineInterface, name: string, via: PstackLoaded['via']): Promise<void> {
73 await update($, loaded, list => (list.some(one => one.name === name) ? list : [...list, { name, via }]))
74}
75
76async function toggleHidden($: EngineInterface, name: string): Promise<void> {
77 const next = await update($, hidden, names => (names.includes(name) ? names.filter(one => one !== name) : [...names, name]))
78 await $.store.set(HIDDEN_KEY, next)
79 $.ui.invalidate('command.describe')
80}
81
82export const register: Register = (on, options) => {
83 const models = modelsFrom(options)
84 const isPotetoDefault = options.poteto_default === true
85 // Loops (main is '') that already carry the note this turn
86 const noted = new Set<string>()
87 let potetoSkill = ''
88 let version = ''
89
90 on('session.start', async ($, e, next) => {
91 potetoSkill = String(await $.fs.read(`${$.plugin.root}/skills/poteto-mode/SKILL.md`).catch(() => ''))
92 version = versionFrom(String(await $.fs.read(`${$.plugin.root}/.claude-plugin/plugin.json`).catch(() => '')))
93 await update($, loaded, () => [])
94 await update($, pinned, () => false)
95 await $.command.register({ name: 'poteto', description: 'Toggle poteto mode for this project' })
96 await $.command.register({ name: 'pstack', description: 'Browse, run and hide pstack skills' })
97 await loadPoteto($, isPotetoDefault)
98 await loadSkills($)
99
100 return next(e)
101 })
102
103 on('command.run', { command: 'poteto' }, async $ => {
104 await togglePoteto($, isPotetoDefault)
105
106 return {}
107 })
108
109 on('command.run', { command: 'pstack' }, async $ => {
110 await $.ui.open({ id: PANE, title: 'pstack', closeOnEscape: true })
111
112 return { text: 'pstack pane opened' }
113 })
114
115 on('command.describe', async ($, e, next) => {
116 const name = e.command.startsWith('pstack:') ? e.command.slice('pstack:'.length) : undefined
117
118 if (name === undefined || !(await read($, hidden)).includes(name)) {
119 return next(e)
120 }
121
122 return next({ ...e, isHidden: true })
123 })
124
125 on('turn.start', ($, e, next) => {
126 noted.clear()
127
128 return next(e)
129 })
130
131 on('prompt.submit', async ($, e, next) => {
132 const command = e.text.match(PSTACK_COMMAND)?.[1]
133 const context = [...(e.context ?? [])]
134
135 if (command !== undefined) {
136 noted.add('')
137 await markLoaded($, command, 'run')
138 context.push(harnessNote($.plugin.root, models))
139 }
140
141 // The conversation catches up with the toggle on the next prompt the model reads
142 if (command !== undefined || !e.text.startsWith('/')) {
143 const isOn = await read($, poteto)
144
145 if (isOn !== (await read($, pinned))) {
146 context.push(isOn ? potetoSection($.plugin.root, potetoSkill, harnessNote($.plugin.root, models)) : POTETO_OFF)
147 await update($, pinned, () => isOn)
148 }
149 }
150
151 return next(context.length === (e.context ?? []).length ? e : { ...e, context })
152 })
153
154 on('tool.call', { tool: 'Read' }, async ($, e, next) => {
155 const result = await next(e)
156 const loop = e.agentId ?? ''
157 const skillsDir = `${$.plugin.root}/skills/`
158 const isPstackFile = e.file_path.startsWith(skillsDir) || e.file_path.startsWith(`${$.plugin.root}/agents/`)
159
160 // A subagent's reads sit in its own context, not the conversation the pane reports on
161 if (e.file_path.startsWith(skillsDir) && result.deny === undefined && e.agentId === undefined) {
162 await markLoaded($, e.file_path.slice(skillsDir.length).split('/')[0] ?? '', 'read')
163 }
164
165 if (!isPstackFile || result.deny !== undefined || noted.has(loop)) {
166 return result
167 }
168
169 noted.add(loop)
170
171 return { ...result, context: [...(result.context ?? []), harnessNote($.plugin.root, models)] }
172 })
173
174 on('tool.call', { tool: 'Skill' }, async ($, e, next) => {
175 const result = await next(e)
176 const name = e.skill.match(/^pstack:(principle-[a-z-]+)$/)?.[1]
177
178 if (name !== undefined && result.deny === undefined && e.agentId === undefined) {
179 await markLoaded($, name, 'skill')
180 }
181
182 return result
183 })
184
185 on('session.compact', async ($, e, next) => {
186 const result = await next(e)
187
188 if (e.agentId === undefined && e.trigger !== 'precompute' && !('skip' in result)) {
189 await update($, loaded, () => [])
190 await update($, pinned, () => false)
191 }
192
193 return result
194 })
195
196 on('agent.spawn', ($, e, next) =>
197 next({ ...e, subagentType: agentType(e.subagentType), model: agentModel(e.model, models) }),
198 )
199
200 // Draws the footer's modes itself: the desktop skips plain mode labels, and the poteto one is a toggle
201 on('ui.render', { component: 'SessionMode' }, async ($, e) => {
202 const { Box, Button, Text } = $.ui.resolve(e)
203 const isOn = await read($, poteto)
204
205 return (
206 <Box flexDirection="row">
207 {e.props.modes.map(mode => (
208 <Text key={mode} dimColor>
209 {mode} &{' '}
210 </Text>
211 ))}
212 <Button
213 key="poteto"
214 variant="primary"
215 dimColor={!isOn}
216 label="poteto"
217 onPress={() => void togglePoteto($, isPotetoDefault)}
218 />
219 <Text color={isOn ? 'success' : undefined} dimColor={!isOn}>
220 {isOn ? ' ♛ on' : ' ♛ off'}
221 </Text>
222 </Box>
223 )
224 })
225
226 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
227 const { Box, Button, Text } = $.ui.resolve(e)
228 const all = await read($, skills)
229 const hiddenNames = await read($, hidden)
230 const isOn = await read($, poteto)
231
232 if (all.length === 0) {
233 return <Text dimColor>No pstack skills found under {$.plugin.root}/skills.</Text>
234 }
235
236 const isPinned = await read($, pinned)
237 const pinnedRows = isPinned ? [{ name: 'poteto-mode', note: 'in context while poteto is on' }] : []
238 const sessionLoaded = (await read($, loaded))
239 .filter(one => !(isPinned && one.name === 'poteto-mode'))
240 .map(one => ({ name: one.name, note: LOADED_NOTES[one.via] }))
241 const loadedRows = [...pinnedRows, ...sessionLoaded]
242 const loadedNames = new Set(loadedRows.map(one => one.name))
243
244 const groups = grouped(all).slice(0, 8)
245 const tabs = [...groups.map(one => ({ title: one.title, label: one.title })), { title: LOADED_TAB, label: `${LOADED_TAB} ${loadedRows.length}` }]
246 const chosen = await read($, group)
247 const selected = tabs.find(one => one.title === chosen) ?? tabs[0]
248 const rows =
249 selected?.title === LOADED_TAB
250 ? loadedRows.map(one => ({ name: one.name, description: one.note }))
251 : (groups.find(one => one.title === selected?.title)?.skills ?? [])
252
253 return (
254 <Box flexDirection="column">
255 <Box flexDirection="column">
256 {WORDMARK.map((line, index) => (
257 <Text key={`wordmark-${index}`} color="warning">
258 {line}
259 </Text>
260 ))}
261 <Text color={isOn ? 'success' : undefined} dimColor={!isOn} wrap="truncate-end">
262 {isOn ? '♛ poteto on: poteto-mode rides the conversation, every task gets the playbooks' : '♛ poteto off: /poteto or the footer toggle pins poteto-mode'}
263 </Text>
264 <Text dimColor wrap="truncate-end">
265 new here? press 1, then /poteto-help
266 </Text>
267 <Text dimColor wrap="truncate-end">
268 {`${loadedRows.length} loaded · ${hiddenNames.length} hidden · ${all.length} skills${version === '' ? '' : ` · v${version}`}`}
269 </Text>
270 </Box>
271 <Box flexDirection="row" flexWrap="wrap" columnGap={2} marginTop={1}>
272 {tabs.map((tab, index) => {
273 const isSelected = tab.title === selected?.title
274 const hotkey = String(index + 1)
275 // The terminal draws a plain Button with a hotkey as `1: label`
276 const width = hotkey.length + 2 + tab.label.length
277
278 return (
279 <Box key={`tab-${tab.title}`} flexDirection="column">
280 <Button
281 key={`group-${tab.title}`}
282 plain
283 hotkey={hotkey}
284 dimColor={!isSelected}
285 label={tab.label}
286 onPress={() => void update($, group, () => tab.title)}
287 />
288 <Text color={isSelected ? 'suggestion' : undefined} dimColor={!isSelected}>
289 {(isSelected ? '━' : '─').repeat(width)}
290 </Text>
291 </Box>
292 )
293 })}
294 </Box>
295 <Box flexDirection="column" marginTop={1}>
296 {rows.length === 0 && <Text dimColor>No pstack skill is in the context yet.</Text>}
297 {rows.map(skill => {
298 const isHidden = hiddenNames.includes(skill.name)
299 const isLoaded = loadedNames.has(skill.name)
300
301 return (
302 <Box key={skill.name} flexDirection="row" gap={1}>
303 <Text color={isLoaded ? 'success' : undefined}>{isLoaded ? '●' : ' '}</Text>
304 <Button
305 key={`run-${skill.name}`}
306 plain
307 dimColor={isHidden}
308 label={`/${skill.name}`}
309 onPress={() => void $.prompt.fill({ text: `/pstack:${skill.name} `, mode: 'replace' })}
310 />
311 <Box flexGrow={1} flexShrink={1} overflow="hidden">
312 <Text dimColor wrap="truncate-end">
313 {skill.description}
314 </Text>
315 </Box>
316 <Button
317 key={`hide-${skill.name}`}
318 plain
319 dimColor
320 label={isHidden ? 'show' : 'hide'}
321 onPress={() => void toggleHidden($, skill.name)}
322 />
323 </Box>
324 )
325 })}
326 </Box>
327 <Box marginTop={1}>
328 <Text dimColor>Press a skill to put it in the prompt · 1-9 switch tabs · hidden skills stay out of the / menu but still run when typed</Text>
329 </Box>
330 </Box>
331 )
332 })
333}
334hooks/catalog.ts 47 lines1// The /pstack pane's grouping of upstream skills; a skill upstream adds later lands in Other until it is placed here
2
3import type { PstackSkill } from '../types'
4
5const GROUPS: ReadonlyArray<readonly [string, readonly string[]]> = [
6 ['Start here', ['poteto-mode', 'poteto-help']],
7 ['Understand', ['how', 'why', 'teach', 'recall', 'blast-radius', 'bro']],
8 ['Design', ['architect', 'arena', 'interrogate', 'figure-it-out']],
9 [
10 'Build and verify',
11 ['tdd', 'swarm', 'create-verification-skill', 'maintain-verification-skill', 'benchmark-checklist', 'show-me-your-work'],
12 ],
13 ['Clean and write', ['unslop', 'no-comments', 'technical-writing', 'typescript-best-practices']],
14 ['Improve the setup', ['correct', 'reflect', 'automate-me']],
15]
16
17export type Group = { title: string; skills: PstackSkill[] }
18
19export function descriptionFrom(skill: string): string {
20 const frontmatter = skill.match(/^---\n([\s\S]*?)\n---/)?.[1] ?? ''
21 const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim() ?? ''
22
23 return description.replace(/^(["'])(.*)\1$/, '$2')
24}
25
26function groupOf(name: string): string {
27 if (name.startsWith('principle-')) {
28 return 'Principles'
29 }
30
31 return GROUPS.find(([, names]) => names.includes(name))?.[0] ?? 'Other'
32}
33
34export function grouped(skills: readonly PstackSkill[]): Group[] {
35 const titles = [...GROUPS.map(([title]) => title), 'Principles', 'Other']
36 const order = (name: string) => GROUPS.flatMap(([, names]) => names).indexOf(name)
37
38 return titles
39 .map(title => ({
40 title,
41 skills: skills
42 .filter(skill => groupOf(skill.name) === title)
43 .sort((a, b) => order(a.name) - order(b.name) || a.name.localeCompare(b.name)),
44 }))
45 .filter(group => group.skills.length > 0)
46}
47hooks/poteto.ts 18 lines1// Cursor pins poteto mode's SKILL.md as a Custom Mode. Desktop sessions raise no prompt.compose, so here it rides a prompt's context once
2
3export function potetoSection(root: string, skill: string, note: string): string {
4 const body = skill.replace(/^---\n[\s\S]*?\n---\n*/, '').trim()
5
6 return [
7 `Poteto mode is on for this project. Follow the poteto-mode skill below on every turn until a later note says poteto mode is off; no Read of its SKILL.md needed. Its playbooks and references live under \`${root}/skills/poteto-mode/\`.`,
8 note,
9 body,
10 ].join('\n\n')
11}
12
13export const POTETO_OFF = 'Poteto mode is now off for this project. Stop following the poteto-mode skill given earlier in this conversation and work in your normal style.'
14
15export function storeKey(projectRoot: string): string {
16 return `poteto:${projectRoot}`
17}
18hooks/translate.ts 57 lines1// Pure mapping from upstream's Cursor vocabulary to Claude Code, kept free of `$` so tests can call it directly
2
3export type Models = {
4 search: string
5 code: string
6 judgment: string
7}
8
9const AGENT_TYPES: Record<string, string> = {
10 generalPurpose: 'general-purpose',
11 'poteto-agent': 'pstack:poteto-agent',
12 'Comment Sicko': 'pstack:Comment Sicko',
13}
14
15const INHERIT = new Set(['inherit', 'inherit-parent', 'auto'])
16
17export function modelsFrom(options: Readonly<Record<string, unknown>>): Models {
18 const pick = (key: string, fallback: string) => (typeof options[key] === 'string' ? (options[key] as string) : fallback)
19
20 return {
21 search: pick('search_model', 'haiku'),
22 code: pick('code_model', 'sonnet'),
23 judgment: pick('judgment_model', 'opus'),
24 }
25}
26
27export function agentType(type: string): string {
28 return AGENT_TYPES[type] ?? type
29}
30
31// undefined means omit `model`, so the subagent runs on its own or the parent's model
32export function agentModel(model: string | undefined, models: Models): string | undefined {
33 if (model === undefined || INHERIT.has(model)) {
34 return undefined
35 }
36
37 const mapped = model.startsWith('grok-') ? models.code : model.startsWith('claude-opus-') ? models.judgment : model
38
39 return INHERIT.has(mapped) ? undefined : mapped
40}
41
42function named(model: string): string {
43 return INHERIT.has(model) ? 'the parent model (omit `model`)' : `\`${model}\``
44}
45
46export function harnessNote(root: string, models: Models): string {
47 return [
48 'pstack was written for Cursor. You are in Claude Code, so translate its instructions as you follow them:',
49 `- Another pstack skill: Read \`${root}/skills/<name>/SKILL.md\` and follow it. Principles are the exception: load one with the Skill tool as \`pstack:principle-<slug>\`. The Skill tool refuses every other pstack skill. Read pstack files one per Read call, in parallel when there are several, never through \`cat\`, \`sed\` or \`head\` in Bash.`,
50 '- `Task` tool or call: the `Agent` tool. Subagent types: `generalPurpose` is `general-purpose`, `poteto-agent` is `pstack:poteto-agent`, `Comment Sicko` is `pstack:Comment Sicko`. Readonly agent mode: the `Explore` agent. `environment: "cloud"`: `isolation: "worktree"`.',
51 '- `AskQuestion`: `AskUserQuestion`.',
52 `- Models: \`~/.cursor/rules/pstack-models.mdc\` and \`/setup-pstack\` do not exist here, so use the defaults below. Grok slugs mean ${named(models.code)}. \`claude-opus-*\` slugs mean ${named(models.judgment)}. Fast searches (the recall fan-out, readonly exploration) use ${named(models.search)}. \`inherit\`, \`inherit-parent\` and \`auto\` mean omit \`model\`. A panel of Opus and Grok is one judgment-model and one code-model agent.`,
53 '- Not available: cursor-team-kit (`deslop`, `control-ui`, `control-cli`), `/make-bot-ui`, and Cursor\'s `create-skill` (use `skill-creator` if installed). Use the project\'s own verification skill or browser tools instead, and say what you skipped.',
54 "- The user's CLAUDE.md files and rules win over pstack's Autonomy guidance. If they say never commit, do not commit.",
55 ].join('\n')
56}
57types/index.d.ts 26 lines1// Whether poteto mode is on for the session's project, mirrored from $.store
2export type PstackPoteto = boolean
3
4// One skill folder under skills/, as the /pstack pane lists it
5export type PstackSkill = { name: string; description: string }
6
7// A pstack skill whose text sits in the main conversation: its files read, or typed as /pstack:<name>
8export type PstackLoaded = { name: string; via: 'read' | 'run' | 'skill' }
9
10declare module 'claude-code' {
11 interface PluginState {
12 pstack: {
13 poteto: PstackPoteto
14 skills: PstackSkill[]
15 // Skill names hidden from the / menu, mirrored from $.store
16 hidden: string[]
17 // The group the /pstack pane shows on the right; '' is the first group
18 group: string
19 // Cleared at compaction and at session start; the pinned poteto-mode is derived from poteto instead
20 loaded: PstackLoaded[]
21 // Whether the conversation holds the poteto-mode text; cleared at compaction and session start
22 pinned: boolean
23 }
24 }
25}
26