@falentio/opencode-pstack
v1.1.0
Published
OpenCode port of pstack, the rigorous agent workflow skills from Cursor.
Maintainers
Readme
@falentio/opencode-pstack
An OpenCode plugin port of the pstack plugin by Lauren Tan. pstack is a set of rigorous agent workflow skills and subagents from the Cursor plugin ecosystem, ported to run natively inside OpenCode.
Install
This plugin targets OpenCode v2 only (@opencode/plugin 2.x). Add the package
to your opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["@falentio/opencode-pstack"]
}For a local checkout, symlink the package directory under .opencode/plugins/:
mkdir -p .opencode/plugins
ln -s /abs/path/to/your/checkout .opencode/plugins/pstackThe checkout root carries a one-line index.js re-exporting dist/src/index.js
for exactly this case: v2 discovery resolves a package directory to its root
index file and ignores package.json exports. Published npm installs are
unaffected (resolvers prefer exports).
On the next OpenCode start, the plugin registers its skills, its two
subagents, and its poteto_* tools into each session. Skills appear in the
native skill tool. No files are copied anywhere.
Subagents
The plugin registers the two subagents poteto-agent and comment-sicko at
startup, so both are available as subagents with mode: subagent. No files are
copied anywhere.
Get started
Run poteto-mode for full instructions or poteto-mode-compact for the compact
instruction set at the start of a task:
/poteto-mode this pr has a subtle bug where the scroll drifts every 750ms. repro first, then fix and verify.Use /poteto-mode-compact when you want the same playbook routing with the
compact skill.
poteto-mode reads your request, picks from a set of playbooks, and routes to
the other skills as needed. OpenCode subagents always inherit the parent chat
model. OpenCode does not support selecting a different model for an individual
subagent, so every Task call omits Task.model. Parallel subagents provide
independent passes, not model diversity.
New here? The pstack guide walks you through a first real task, from setup and prompting through verification and overnight runs.
How the port works
This plugin is built on the OpenCode v2 plugin API (Plugin.define with an
id and a setup(ctx) entrypoint). setup registers everything through
domain transforms and session hooks:
ctx.skill.transformadds the package'sskills/bundle, so the nativeskilltool serves every skill inside sessions. Plugin-added skills are session-scoped in v2: they never appear inapi skill.list(which shows only the file-discovery layer), and there is nodebug skillcommand. A live session that loadspoteto-modeis the registration proof.ctx.agent.transformupserts both subagents fromagents/at setup (editor.update(id, fn)creates the agent whenidis absent).agents/stays the single source of truth:src/catalog.tsparses and validates each file (description,mode: subagent, prompt body) and the suite enforces it.
The plugin also registers native poteto_* tools through the tool hook, so
playbooks call tools instead of shelling to scripts:
poteto_check_planchecks a multi-phase plan file.poteto_orch_*(20 tools) manages the orchestrate store: init, units, ledger, inbox, gates, frontier, status, standing orders.poteto_watch_pr_status,poteto_watch_pr_stack, andpoteto_watch_pr_classifyread PR state single-shot. Callers re-invoke them to poll.poteto_worktree_auditlists non-main worktrees as TSV.
The transforms only add to the session catalog. They never replace existing
skills or clobber anything. scripts/smoke.mjs stays as the dev-only
model-free probe behind pnpm smoke: it boots a sandboxed location through
the real CLI and asserts the v2 layering (discovery shows file skills, the
plugin boots clean). Skill content is proved by test/plugin-setup.test.ts
and the verify-pstack live drive. It has no tool home.
Differences from the Cursor plugin
- One skill frontmatter
namefield was normalized to its directory name (Poteto Mode→poteto-mode), because OpenCode requires the frontmatternameto equal the skill directory name. - The two agents are registered with
mode: subagent; Cursor used its ownis_backgroundflag which OpenCode does not understand. - The Cursor
automations/bennydirectory is not ported. Those are Slack issue automations that depend on Cursor's automation runtime; OpenCode has no equivalent. - Cursor's pstack relies on per-subagent model selection for some delegates,
reviewer panels, and judges. OpenCode has no per-subagent model selection.
This port therefore omits
Task.modeleverywhere and runs every subagent on the parent chat model. The skills retain parallelism and independent review, but cannot provide Cursor's model diversity. - Three skills are opencode-native additions with no Cursor counterpart in pstack:
deslop(diff cleanup before commit),control-ui, andcontrol-cli(drive the real UI or CLI and capture evidence). - Stacking uses plain
gitbranches plusgh(gh pr create,gh pr edit --base, bottom-upghmerges). There is nogtCLI and no Graphite UI, merge-when-ready, orgraphite-baserefs. Loops use background Tasks with poll instead of a built-in loop command, and goals live in a goal file the run re-reads. Session history comes from the opencode session API, not~/.cursor/projectstranscript paths.
Development
pnpm install
pnpm checkpnpm check runs typecheck, build, and the node --test suite against the
bundled skills and agents. It then runs pnpm smoke, which drives sandboxed
locations through the real CLI: none (empty config, built-ins boot clean),
manual (a native v2 skills config entry is accepted and the location boots)
and plugin (the checkout symlinked under .opencode/plugins, which boots and
registers both subagents). It skips rather than fails when opencode is not on
PATH outside CI. CI treats a missing or unusable OpenCode binary as a failed
smoke test. Skill content is proved by test/plugin-setup.test.ts, and
end-to-end skill proof (a live session loading poteto-mode) lives in the
verify-pstack skill, which needs model auth that CI smoke deliberately avoids.
Release
Update package.json to the release version, then push a matching version tag:
pnpm version patch --no-git-tag-version
git add package.json
git commit -m "release: v0.1.1"
git tag v0.1.1
git push origin main v0.1.1The publish workflow accepts tags in the v<version> format. It runs the full
check suite and publishes the package to npm with provenance.
Publishing uses npm trusted publishing, so the repository stores no publish
token. Set up the trusted publisher once on npmjs.com. Trust the GitHub
repository falentio/opencode-pstack, the workflow file publish.yml, and the
npm publish action. Publishing then authenticates with the GitHub Actions
OIDC identity from that workflow.
