@justjoshn/pi-pstack 0.15.36-pi.1 → 0.15.36-pi.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +15 -12
  3. package/agents/ci-watcher.md +27 -0
  4. package/agents/thermo-nuclear-code-quality-review.md +23 -0
  5. package/assets/logo.png +0 -0
  6. package/automations/benny/FOR_AGENTS.md +1 -1
  7. package/automations/benny/README.md +2 -2
  8. package/automations/benny/skills/setup-benny/SKILL.md +5 -5
  9. package/bin/pstack-routines-supervisor +9 -0
  10. package/docs/guide/07-overnight.md +1 -1
  11. package/docs/guide/09-make-it-yours.md +1 -1
  12. package/docs/guide/10-recipes-and-pitfalls.md +1 -1
  13. package/docs/native-gaps.md +11 -5
  14. package/docs/parity-reverse-engineering.md +94 -0
  15. package/package.json +41 -6
  16. package/packaging/install-supervisor-unit.sh +164 -0
  17. package/packaging/launchd/com.pstack.routines-supervisor.plist.example +24 -0
  18. package/packaging/systemd/pstack-routines-supervisor.service.example +15 -0
  19. package/skills/architect/SKILL.md +1 -1
  20. package/skills/architect/references/runner-prompt.md +1 -1
  21. package/skills/arena/SKILL.md +3 -3
  22. package/skills/check-compiler-errors/SKILL.md +23 -0
  23. package/skills/create-skill/SKILL.md +515 -29
  24. package/skills/fix-ci/SKILL.md +29 -0
  25. package/skills/fix-merge-conflicts/SKILL.md +32 -0
  26. package/skills/get-pr-comments/SKILL.md +23 -0
  27. package/skills/how/SKILL.md +1 -1
  28. package/skills/ketchup-video/SKILL.md +2 -2
  29. package/skills/loop-on-ci/SKILL.md +50 -0
  30. package/skills/make-bot-ui/SKILL.md +2 -2
  31. package/skills/make-pr-easy-to-review/SKILL.md +59 -0
  32. package/skills/new-branch-and-pr/SKILL.md +29 -0
  33. package/skills/no-inline-imports/SKILL.md +12 -0
  34. package/skills/poteto-help/SKILL.md +4 -4
  35. package/skills/poteto-mode/playbooks/multi-phase-plan.md +1 -1
  36. package/skills/poteto-mode/playbooks/orchestrate.md +1 -1
  37. package/skills/pr-review-canvas/SKILL.md +176 -0
  38. package/skills/pr-review-canvas/renderer.js +170 -0
  39. package/skills/pr-review-canvas/styles.css +96 -0
  40. package/skills/pr-review-canvas/template.html +18 -0
  41. package/skills/reflect/SKILL.md +1 -1
  42. package/skills/review-and-ship/SKILL.md +41 -0
  43. package/skills/run-smoke-tests/SKILL.md +42 -0
  44. package/skills/statechart/scripts/test/cli.test.ts +1 -1
  45. package/skills/swarm/SKILL.md +2 -2
  46. package/skills/thermo-nuclear-code-quality-review/SKILL.md +192 -0
  47. package/skills/typescript-exhaustive-switch/SKILL.md +10 -0
  48. package/skills/verify-this/SKILL.md +74 -0
  49. package/skills/weekly-review/SKILL.md +32 -0
  50. package/skills/what-did-i-get-done/SKILL.md +31 -0
  51. package/skills/why/SKILL.md +1 -1
  52. package/skills/workflow-from-chats/SKILL.md +50 -0
  53. package/src/mode.ts +3 -3
  54. package/src/paths.ts +13 -0
  55. package/src/pi-command.ts +12 -0
  56. package/src/rule.ts +4 -4
  57. package/src/sections.ts +2 -1
  58. package/src/subscriptions/durable-store.ts +482 -0
  59. package/src/subscriptions/durable-types.ts +41 -0
  60. package/src/subscriptions/ensure-supervisor.ts +67 -0
  61. package/src/subscriptions/index.ts +231 -271
  62. package/src/subscriptions/supervisor-main.ts +88 -0
  63. package/src/subscriptions/supervisor.ts +271 -0
  64. package/src/subscriptions/webhook.ts +22 -9
  65. package/src/task/card.ts +29 -0
  66. package/src/task/records.ts +3 -8
  67. package/src/task/runner.ts +9 -14
  68. package/src/task/tool.ts +18 -21
  69. package/src/todo.ts +1 -2
  70. package/scripts/live-e2e.mjs +0 -257
  71. package/test/aliases.test.ts +0 -57
  72. package/test/ask.test.ts +0 -85
  73. package/test/autocomplete.test.ts +0 -39
  74. package/test/e2e/aliases.e2e.test.ts +0 -81
  75. package/test/e2e/ask.e2e.test.ts +0 -135
  76. package/test/e2e/harness.ts +0 -179
  77. package/test/e2e/host.e2e.test.ts +0 -193
  78. package/test/e2e/lifecycle.e2e.test.ts +0 -99
  79. package/test/e2e/mode.e2e.test.ts +0 -160
  80. package/test/e2e/package.e2e.test.ts +0 -67
  81. package/test/e2e/task.e2e.test.ts +0 -734
  82. package/test/e2e/todo.e2e.test.ts +0 -59
  83. package/test/fixtures/cursor-askquestion-calls.json +0 -806
  84. package/test/fixtures/fake-pi.mjs +0 -96
  85. package/test/fixtures/image-model.ts +0 -16
  86. package/test/fixtures/list-models.ts +0 -15
  87. package/test/fixtures/readonly-shell-exit.ts +0 -17
  88. package/test/fixtures/scripted-model.ts +0 -113
  89. package/test/loop.test.ts +0 -209
  90. package/test/mode.test.ts +0 -143
  91. package/test/plan.test.ts +0 -126
  92. package/test/readonly-shell-security.test.ts +0 -84
  93. package/test/readonly-shell.test.ts +0 -44
  94. package/test/records.test.ts +0 -143
  95. package/test/registry.test.ts +0 -18
  96. package/test/resources.test.ts +0 -162
  97. package/test/rule.test.ts +0 -92
  98. package/test/scripts.test.ts +0 -182
  99. package/test/sections.test.ts +0 -56
  100. package/test/subscriptions-cron.test.ts +0 -60
  101. package/test/subscriptions.test.ts +0 -598
  102. package/test/task-agents.test.ts +0 -49
  103. package/test/task-card.test.ts +0 -34
  104. package/test/task-fork.test.ts +0 -233
  105. package/test/task-format.test.ts +0 -65
  106. package/test/task-model.test.ts +0 -141
  107. package/test/task-runner.test.ts +0 -259
  108. package/test/task-schema.test.ts +0 -50
  109. package/test/task-status.test.ts +0 -155
  110. package/test/task-worktree.test.ts +0 -106
  111. package/test/todo.test.ts +0 -74
  112. package/test/visualize.test.ts +0 -152
  113. package/tsconfig.json +0 -5
  114. package/vitest.config.ts +0 -16
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## [0.15.36-pi.7] - 2026-11-02
4
+
5
+ - Update the host compatibility documentation for Pi 1.5.0. Retain the four native gaps for RPC process control, skill-block formatting, named-ID fork truncation, and workspace folder naming.
6
+ - Keep earlier verification records unchanged. This documentation audit does not claim new runtime-test results or complete upstream parity.
7
+ - Preserve string-enum argument shapes and optional literal types with TypeBox schemas under Pi 1.5.0 validation.
8
+ - Preserve provider-reported cost provenance when aggregating subagent usage.
9
+ - Ship a versioned package-root changelog entry for Pi 1.5.0's extension update notices.
10
+
11
+ ## [0.15.36-pi.6]
12
+
13
+ - Implement version-2 durable subscription registry with transactional file locking, native owner continuation delivery via `pi.sendMessage`, bounded exponential retry on detached failures, per-subscription queue caps, non-blocking GitHub arming, legacy supervisor termination, and in-process fallback isolation.
14
+ - Decode child RPC stdout streams using `StringDecoder` to preserve split multibyte UTF-8 code points across buffer boundaries.
15
+ - Publish upstream pstack git commit provenance in `pstackSource` and exclude nested script dependencies from npm publication archives via `skills/.npmignore`.
16
+ - Canonicalize statechart symlink test fixture paths on macOS and add checksum-verified TLC statechart verification to CI.
17
+
18
+ ## [0.15.36-pi.5]
19
+
20
+ - Replace hand-rolled frontmatter, attachment MIME, and session header parsers with Pi 1.4.0 exports (`stripFrontmatter`, `detectSupportedImageMimeTypeFromFile`, and `parseSessionEntries`).
21
+ - Register TUI message renderers for `pstack/task` and `pstack/subscription`, drain parked `runtime/inbox/` wakes on session restore, surface durable delivery state in `list_subscriptions`, and report live supervisor status in `/routines`.
22
+ - Declare published `files` in `package.json`, record the REA architecture reconstruction report in `docs/parity-reverse-engineering.md`, and enforce zero dependencies on an external `pstack` checkout.
23
+
24
+ ## [0.15.36-pi.4]
25
+
26
+ - Add a durable routines supervisor (`pstack-routines-supervisor`) that dual-writes subscription desired state and auto-starts on `subscribe_*` so timers and webhook routines keep firing after the interactive chat exits. Optional launchd/systemd examples live under `packaging/`.
27
+ - Add `packaging/install-supervisor-unit.sh` for opt-in reboot survival (idempotent launchd or systemd user unit). Benny setup and the overnight guide point at it.
28
+ - Teach `/ketchup-video` and the host media section to open the rendered mp4 in the system player, read one frame per slide, and name the path (Pi chat does not inline-play video).
29
+ - Expand the vendored `create-skill` soft-dep to full interview and structure depth with Pi paths.
30
+
31
+ ## [0.15.36-pi.3]
32
+
33
+ - Vendor the full soft-dependency team-kit skill and agent set into the package (CI, PR, review, verification, weekly summary, and the two engineering rules as skills), so pi-pstack no longer needs a separate team-kit install for parity.
34
+ - Inject the two former always-apply engineering rules into the host system prompt, and teach the thermo-nuclear agent to gather diffs with Pi tools instead of inventing `shell` / `explore` Task types.
35
+ - Keep Claude Code harness notes out of the package (Pi users get `docs/native-gaps.md` instead).
36
+
37
+ ## [0.15.36-pi.2]
38
+
39
+ - Add repository, homepage, and bugs metadata and a changelog to the npm package.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # pstack for Pi (pi-pstack)
2
2
 
3
- pi-pstack is pstack 0.15.36 for Pi 1.4.0: rigorous agent workflows (`/poteto-mode` and its playbooks), the principle skills, and the review, research, and verification skills, plus `deslop`, `control-cli`, and `control-ui`. A small extension provides the host features the skills call by name: `/name` skill commands, `/mode`, `/plan`, the `Task` subagent tool with isolated workers, forks, and `agent_status`, `TodoWrite`, `AskQuestion`, the model rule, `/loop`, subscriptions and webhook routines, and `visualize`.
3
+ pi-pstack is pstack 0.15.36 for Pi 1.5.0: rigorous agent workflows (`/poteto-mode` and its playbooks), the principle skills, and the review, research, and verification skills, plus the full soft-dependency team-kit set (`deslop`, `control-cli`, `control-ui`, CI/PR helpers, thermo-nuclear review, and the rest) vendored in so you do not install a separate team-kit package. A small extension provides the host features the skills call by name: `/name` skill commands, `/mode`, `/plan`, the `Task` subagent tool with local worktree workers, forks, and `agent_status`, `TodoWrite`, `AskQuestion`, the model rule, `/loop`, subscriptions and webhook routines, and `visualize`.
4
4
 
5
5
  ## Get set up
6
6
 
@@ -14,7 +14,7 @@ pi-pstack is pstack 0.15.36 for Pi 1.4.0: rigorous agent workflows (`/poteto-mod
14
14
  ```
15
15
 
16
16
  Pi does not install dependencies for a local package, so `bun install` (or `npm install` in `extensions/pi-pstack`) fetches the one runtime dependency, `@anthropic-ai/sandbox-runtime`, which the read-only shell loads (readonly subagents and `/plan`). Without it everything else works, and a read-only shell command fails instead of running unsandboxed. To try it for one session without installing, run `pi -e ./extensions/pi-pstack`. To install the published package instead, run `pi install npm:@justjoshn/pi-pstack`.
17
- Installing loads pi-pstack's tools and system-prompt sections at once, but no skill runs until you invoke it. 57 pstack skills stay out of the model's automatic skill list; only `/setup-pstack`, `create-skill`, `deslop`, `control-cli`, and `control-ui` can load from your words alone.
17
+ Installing loads pi-pstack's tools and system-prompt sections at once, but no skill runs until you invoke it. 61 workflow skills stay out of the model's automatic skill list. Setup, create-skill, and the team-kit shipping and review skills (`deslop`, `control-cli`, `control-ui`, CI and PR helpers, and the rest of that set) can load from your words alone.
18
18
  2. Run `/setup-pstack`. It lists the models the `Task` tool can use, asks for a reasoning budget, maps a model to each role, and writes the model rule. A new rule applies from the next request.
19
19
  3. Start real work with `/poteto-mode`, a goal, and a check that can pass or fail.
20
20
 
@@ -47,13 +47,14 @@ Remove the package with `pi remove ./extensions/pi-pstack`. Its state lives in `
47
47
  | `agent_status` | Reads a subagent's state (`running` while its run lock names a live pid, `idle`, or `missing`), type, model, directory, branch, times, and last reply, without waking it. It also shows whether the agent is readonly, the agent it was forked from, its pid while running, and its transcript. Without `agent_id` it lists the workspace's 20 newest agents. In the root chat that includes every descendant, isolated workers too. |
48
48
  | Subagent types | `generalPurpose` (default), `poteto-agent` (a background delegate that reads poteto-mode first), and `comment-sicko`, read from `agents/*.md`. Unknown types fail with the list. |
49
49
  | Models | A Pi model spec such as `claude-opus-5-5:xhigh` or `xai/grok-4.7:high`, model parameters such as `claude-opus-5-5[effort=high]` or `grok-4.7[fast=true]` (picks a listed `-fast` id of that model), or `inherit`, `inherit-parent`, `auto`, or nothing for the parent model. A model Pi does not list, or a thinking level the model does not support, fails with the allowed list. A bare model id that several providers offer resolves to the parent chat's provider when it offers that id, and otherwise fails with the choices. Older rules that wrote `claude-opus-5-5-xhigh` still resolve. The system prompt's `pstack_subagents` section lists the types, the parent model, and the models with their levels. |
50
- | Isolated workers (`environment: "cloud"`) | The subagent runs in a new git worktree at `<pstack dir>/workspaces/<workspace folder>/worktrees/<agent id>` on branch `pstack/<agent id>`, from `cloud_base_branch` (a local ref, else `origin/<branch>`) or your HEAD commit, so uncommitted changes do not reach it. The result and the card name the branch to merge, and `resume` and `fork` run in the same worktree. It fails clearly outside a git repository, in a repository with no commits, or when the base does not resolve. The worker shares the root chat's workspace state, so it sees the same projects, stores, and subagent transcripts. `swarm` and `orchestrate` spawn isolated workers by default. |
50
+ | Isolated workers (`environment: "cloud"`) | The subagent runs in a new git worktree at `<pstack dir>/workspaces/<workspace folder>/worktrees/<agent id>` on branch `pstack/<agent id>`, from `cloud_base_branch` (a local ref, else `origin/<branch>`) or your HEAD commit, so uncommitted changes do not reach it. The result and the card name the branch to merge, and `resume` and `fork` run in the same worktree. It fails clearly outside a git repository, in a repository with no commits, or when the base does not resolve. The worker shares the root chat's workspace state, so it sees the same projects, stores, and subagent transcripts. It also shares this machine's ports, processes, writable caches, simulators, and credentials. Assign separate ports, output directories, and writable caches to concurrent runtime lanes. `swarm` and `orchestrate` spawn worktree workers by default. |
51
51
  | `readonly: true` | The child gets `read`, `grep`, `find`, `ls`, `TodoWrite`, and a read-only `bash`, and no MCP. That shell runs each command in an OS sandbox ([`@anthropic-ai/sandbox-runtime`](https://github.com/anthropics/sandbox-runtime): `sandbox-exec` on macOS, bubblewrap on Linux) that blocks every file write and all network access, so `git log` works and `touch` or `curl` fail. Where no sandbox can start, the command fails rather than running unsandboxed. |
52
52
  | `TodoWrite` | `todos` with `id`, `content`, `status`, and `merge`. The list follows the session branch and shows above the editor. |
53
53
  | `AskQuestion` | `title`, and per question `id`, `prompt`, `options` (`id`, `label`, optional `description`), and `allow_multiple`, through Pi's select dialog. Every question ends with `Other: (type to answer)`; a typed answer comes back as `other` with its text. In print and JSON runs, including subagents, each question comes back skipped. |
54
54
  | The model rule | `<pstack dir>/pstack-models.md`, plain Markdown with one line per role, added to every request's system prompt. A `pstack-models.mdc` from an earlier version is moved there once, without its frontmatter, and kept as `pstack-models.mdc.migrated`. |
55
- | Subscriptions | `subscribe_github_pr` (`scope` `pr` with `prUrl`, `repo` with `repo`, or `author` with `author` and `repo`) polls with `gh` every 60 seconds and wakes the chat when a PR's state, head, mergeability, review decision, reviews, or comments change, or when a check concludes or its conclusion changes; the first poll is a baseline. `subscribe_timer` takes a `name`, a `prompt`, and a 5-field `cron` or `delaySeconds`, either with `once`; `sessionStrategy` `wake_self` wakes this chat, and `new_session` runs each fire in a fresh background subagent. Re-subscribing an existing timer name returns `created: false`. `list_subscriptions` and `unsubscribe` manage them. Subscriptions persist in the session, restore on reload and resume, expire after 7 days unless `expiresInHours` says otherwise (at most 30 days), and stop with the Pi process. |
56
- | Webhook routines | `subscribe_webhook` (`name`, `prompt`) serves `http://127.0.0.1:<port>/routines/<slug>` (port `PSTACK_ROUTINES_PORT`, default 47913, where `0` picks a free port) and keeps a random sender key in `<pstack dir>/routines/<slug>/credentials.json` (mode 0600). The result names the URL and the file, never the key. A JSON POST with `X-Automation-Key` or `Authorization: Bearer` returns 200 and wakes the chat with a `[routine]` turn holding the prompt and a `<webhook_event>` block (`headers`, `body_digest`, `body`, `timestamp_ms`). A wrong key gets 401, an unknown routine 404, a method other than POST 405, a body over 64 KiB 413, and a body that is not a JSON object 400. `make-bot-ui` builds a page on top of this. |
55
+ | Subscriptions | `subscribe_github_pr` (`scope` `pr` with `prUrl`, `repo` with `repo`, or `author` with `author` and `repo`) polls with `gh` every 60 seconds and wakes the chat when a PR's state, head, mergeability, review decision, reviews, or comments change, or when a check concludes or its conclusion changes; the first poll is a baseline. `subscribe_timer` takes a `name`, a `prompt`, and a 5-field `cron` or `delaySeconds`, either with `once`; `sessionStrategy` `wake_self` queues a wake for this owning session. With `new_session`, a live owner starts a background Task and receives its notification. An offline owner permits a detached run with a recorded outcome. Re-subscribing an existing timer name returns `created: false`. `list_subscriptions` and `unsubscribe` manage them. The authoritative registry is `<pstack dir>/durable/<workspace>/subscriptions.json`. Any session in that workspace can list or cancel subscriptions. Session history does not recreate cancelled or completed subscriptions. Owner-directed events wait for the creating session rather than waking another workspace session. They expire after 7 days unless `expiresInHours` says otherwise (at most 30 days). |
56
+ | Webhook routines | `subscribe_webhook` (`name`, `prompt`) serves `http://127.0.0.1:<port>/routines/<slug>` (port `PSTACK_ROUTINES_PORT`, default 47913, where `0` picks a free port) and keeps a random sender key in `<pstack dir>/routines/<slug>/credentials.json` (mode 0600). The result names the URL and the file, never the key. A JSON POST with `X-Automation-Key` or `Authorization: Bearer` returns 200 after durable acceptance. The owner receives a `[routine]` turn holding the prompt and a `<webhook_event>` block (`headers`, `body_digest`, `body`, `timestamp_ms`). HTTP 200 does not mean the owner has handled the event. Each authenticated POST is a separate event, including identical bodies. Storage failure returns 503 rather than acknowledging a lost event. A wrong key gets 401, an unknown routine 404, a method other than POST 405, a body over 64 KiB 413, and a body that is not a JSON object 400. `make-bot-ui` builds a page on top of this. |
57
+ | Durable supervisor | Creating a subscription auto-starts `pstack-routines-supervisor --workspace <cwd>` when it is not already running. Creation waits for that subscription to arm, and webhook creation returns the bound listener's URL. The supervisor reads the durable registry, arms timers and GitHub polls, and owns the routines port. An online owner receives native Pi continuation messages. Owner-directed events accepted while the owner is offline wait for that same session to resume. Only a timer explicitly configured with `sessionStrategy: "new_session"` can start detached work while its owner is offline. You can still start the bin yourself. For reboot survival, run `packaging/install-supervisor-unit.sh --workspace <cwd>` (idempotent; installs the launchd or systemd unit from the examples under `packaging/`). Print and JSON runs still cannot *create* subscriptions. |
57
58
  | Stores and projects | The system prompt names "the current agent's store" (per session), "the root agent's store" (the main chat's, named to every subagent however deep), and the workspace's `projects/` folder, where a program's Project is `<slug>/notes.md` (its tracker) and `<slug>/store/`. |
58
59
  | `visualize` | `title`, `kind` (`bar` or `line`), `labels`, `series` (`name`, `values`), and `unit` render a Unicode chart in the result and write a standalone SVG to the session's artifacts folder. |
59
60
  | Transcripts | The system prompt names this workspace's Pi session directory, the current session file, and this workspace's subagent transcripts. |
@@ -63,11 +64,12 @@ Subagent transcripts are Pi sessions in `<pstack dir>/workspaces/<workspace fold
63
64
 
64
65
  ## Limits
65
66
 
66
- - Isolated workers run on this machine. They start from committed code only and share your installed extensions, MCP servers, and network, except that a readonly worker gets no MCP servers and no network. pi-pstack never pushes their branches, though a worker can push its own. Worktrees and branches stay until you or the worktree-cleanup playbook remove them.
67
- - Subscriptions and routines live in the Pi process that created them. Keep that session running (for example in tmux) while they matter. A GitHub subscription restored after a restart takes a new baseline, so changes made while Pi was down do not wake it. Only one Pi process can hold the routine port; set `PSTACK_ROUTINES_PORT` for a second one. The routine listener binds `127.0.0.1`, so a page served to other machines forwards through a local server, as `make-bot-ui` describes.
68
- - The Benny automation pack under `automations/benny/` runs on pi-pstack subscriptions in a long-lived Pi session and needs a Slack MCP server for its Slack steps.
67
+ - Worktree workers run on this machine, not remote VMs. They start from committed code only and share your installed extensions, MCP servers, and network, except that a readonly worker gets no MCP servers and no network. A worktree is not a credential boundary. Concurrent runtime lanes need separate ports, output directories, and writable caches. pi-pstack never pushes their branches, though a worker can push its own. Worktrees and branches stay until you or the worktree-cleanup playbook remove them.
68
+ - The supervisor can accept events after chat exit, but owner-directed events wait until the owning session resumes. Explicit `new_session` timers can spend tokens with no human watching. Detached runs do not supply the live owner's Task notification flow. For reboot survival, run `packaging/install-supervisor-unit.sh --workspace <cwd>`. If the supervisor cannot start, an explicitly reported in-process fallback stops when that Pi process exits. A GitHub subscription restarted after downtime takes a new baseline, so changes made while nothing was polling do not wake it. Only one listener can hold a fixed routine port. Set `PSTACK_ROUTINES_PORT` for another workspace, or use `0` for a free port. The listener binds `127.0.0.1`, so a page served to other machines forwards through a local server, as `make-bot-ui` describes.
69
+ - Event delivery is at-least-once. A process crash after Pi queues a message but before its durable acknowledgement can repeat a wake or a fresh run. Automation prompts must make external actions idempotent. Accepted events remain queued until delivery or cancellation. Expiry stops new occurrences rather than discarding accepted work. Failed detached executions retain their event for retry and expose the error in `list_subscriptions`. Cancelling a subscription drops pending undelivered events, but cannot undo work already handed to Pi.
70
+ - The Benny automation pack under `automations/benny/` runs on pi-pstack subscriptions. Keep its owning Pi session running for immediate handling, or resume that session to handle parked events. It needs a Slack MCP server for its Slack steps.
69
71
  - `/plan` uses `bash_readonly` for its shell rather than replacing `bash`, so your shell settings stay as they are outside plan mode.
70
- - Background subagent token usage is recorded in the child's transcript and in the `usage` field of the notification's details, but does not enter the parent session's totals: Pi 1.4.0 gives extensions no way to add usage outside a tool result.
72
+ - Background subagent token usage is recorded in the child's transcript and in the `usage` field of the notification's details, but does not enter the parent session's totals: Pi 1.5.0 has no public API for adding a background completion's usage to the parent totals. Native tool-result usage covers synchronous nested work, not later notifications.
71
73
  - `/reload`, `/new`, and Pi's `/resume` and `/fork` commands stop running background subagents, with a warning that names how many. Continue one later with `Task` `resume` and its agent ID.
72
74
  - A print or JSON run waits for its background subagents before it exits, with no timeout of its own, unless it is aborted.
73
75
  - Subagents start the same Pi script that runs the parent (`process.argv[1]`), or `pi` from `PATH`. Embedding the package through the SDK in another host is not supported.
@@ -76,21 +78,22 @@ Subagent transcripts are Pi sessions in `<pstack dir>/workspaces/<workspace fold
76
78
  - Subagents run headless in RPC mode, so an extension that asks for permission through a dialog cannot ask there.
77
79
  - The read-only shell sandboxes shell subprocesses only, and is verified on macOS and on the Ubuntu CI runner. On Linux it needs `bubblewrap`, `socat`, and `ripgrep`. Ubuntu 24.04 and later restrict unprivileged user namespaces: either add an AppArmor profile that grants `userns` to `bwrap`, or run `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0`, which lifts the restriction for every program on the machine. The policy sets `allowAllUnixSockets: true` so Linux skips `apply-seccomp`, whose nested userns fails on GitHub-hosted runners; filesystem write denial and network denial still come from bubblewrap.
78
80
  - Whether a model follows a playbook is the model's call.
79
- - Workspace folders follow Pi's session-folder naming, so two paths that differ only by `/` versus `-` share a folder; resume and fork refuse an agent whose record names the other directory.
81
+ - Workspace folders follow Pi's session-folder naming, so two paths that differ only by `/` versus `-` share a folder. Resume and fork refuse an agent whose record names the other directory. Subscription reads and mutations also reject a registry owned by the other workspace.
80
82
  - The run lock that keeps one writer per agent ID names the process writing the transcript. A lock file without a readable pid counts as held; the error names the file to delete. `agent_status` shows such an agent as `idle`. A lock whose pid is dead is taken over, and two processes that take over the same stale lock at the same moment can both succeed.
81
83
  - `skills/poteto-mode/scripts/watch-pr` needs Bun and installs its one dependency on first run. `check-plan.mjs` needs only Node. `worktree-audit.sh` needs `rg` and `jq`, and works with BSD (macOS) or GNU `stat` and `date`.
82
84
  - `statechart` runs `skills/statechart/scripts/statechart` on Node 22.18 to 22.x, Node 23.6 or later, Bun 1.1.5 or later, or Deno 2.0 or later. The first run installs TLC and Java through [mise](https://mise.jdx.dev/) and needs the network. Without a SPEC it prints `Give one SPEC.tla.` and its usage, then exits 2.
83
85
 
84
86
  ## Maintain it
85
87
 
86
- The skills, agents, guide, and automation pack are this package's own files; edit them in place. They track pstack 0.15.36 in behavior. The record of the move to Pi-native text and the host features added for it is at the repository root, in `parity/pi-pstack-0.15.36/` (design and decisions); earlier records are in the root's `parity/pi-pstack-*`. Four mechanisms Pi 1.4.0 does not export keep a hand-written implementation here: [`docs/native-gaps.md`](docs/native-gaps.md) names each one, the evidence, and the public API that would replace it.
88
+ The skills, agents, guide, and automation pack are this package's own files; edit them in place. They track pstack 0.15.36 in behavior. The record of the move to Pi-native text and the host features added for it is at the repository root, in `parity/pi-pstack-0.15.36/` (design and decisions); earlier records are in the root's `parity/pi-pstack-*`. Four mechanisms Pi 1.5.0 does not export keep a hand-written implementation here: [`docs/native-gaps.md`](docs/native-gaps.md) names each one, the evidence, and the public API that would replace it.
87
89
 
88
90
  ```sh
89
91
  bun run typecheck
90
92
  bun run test
93
+ bun run test:statechart # full compiler suite; set TLA2TOOLS and JAVA for an existing verified toolchain
91
94
  bun run live:e2e -- --model deepseek/deepseek-flash # real-model scenarios; needs credentials and gives the model under test your real auth.json (see the script header)
92
95
  ```
93
96
 
94
97
  ## Licenses
95
98
 
96
- The port's own code is MIT (`LICENSE`). pstack's files keep their MIT notice in `licenses/pstack.LICENSE` (© 2026 Lauren Tan), and the `deslop`, `control-cli`, and `control-ui` skills keep theirs in `licenses/cursor-team-kit.LICENSE`.
99
+ The port's own code is MIT (`LICENSE`). pstack's files keep their MIT notice in `licenses/pstack.LICENSE` (© 2026 Lauren Tan), and the vendored team-kit skills and agents keep theirs in `licenses/cursor-team-kit.LICENSE`.
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: ci-watcher
3
+ description: Watch PR CI for the current branch and report pass/fail with relevant failure links. Use when waiting for CI results or CI has failed. Use proactively to monitor branch CI.
4
+ is_background: true
5
+ ---
6
+
7
+ # CI watcher
8
+
9
+ CI monitoring specialist for PR-attached checks.
10
+
11
+ ## Trigger
12
+
13
+ Use when waiting for CI results, CI has failed, or when proactively monitoring branch CI.
14
+
15
+ ## Workflow
16
+
17
+ 1. Determine current branch: `git branch --show-current`
18
+ 2. Resolve the PR: `gh pr view --json number,url,headRefName`
19
+ 3. Inspect attached checks: `gh pr checks --json name,bucket,state,workflow,link`
20
+ 4. If checks are pending, watch: `gh pr checks --watch --fail-fast`
21
+ 5. If a GitHub Actions check failed, fetch logs with `gh run view <run-id> --log-failed`; otherwise, return the check link and concise next step.
22
+
23
+ ## Output
24
+
25
+ - CI status (passed/failed)
26
+ - PR and check metadata
27
+ - If failed: concise failure excerpt or external check link and likely next step
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: thermo-nuclear-code-quality-review
3
+ description: Thermo-nuclear code quality audit (maintainability, structure, 1k-line rule, spaghetti, code-judo). Invoked via Task after a parent gathers diff and file contents. Loads the rubric from the `thermo-nuclear-code-quality-review` skill shipped with pi-pstack.
4
+ ---
5
+
6
+ # Thermo-Nuclear Code Quality Review
7
+
8
+ You are a **Task subagent**. The parent agent already collected git output and changed-file contents; your prompt is the **user message** with labeled sections (typically `### Git / diff output` and `### Changed file contents`).
9
+
10
+ ## Rubric
11
+
12
+ 1. Load the `thermo-nuclear-code-quality-review` skill (shipped with pi-pstack) and treat its `SKILL.md` as the **complete** rubric — tone, approval bar, output ordering, code-judo / 1k-line / spaghetti rules.
13
+ 2. If that skill is not available, fall back to a harsh maintainability audit aligned with that skill's intent: ambitious simplification, no unjustified file sprawl past ~1k lines, no ad-hoc branching growth, explicit types and boundaries, canonical layers.
14
+
15
+ ## Work
16
+
17
+ - Apply the rubric **only** to what the diff and contents show. Trace cross-file impact when the change touches module boundaries.
18
+ - Output in the **priority order** the rubric specifies. Be direct and high-conviction; skip cosmetic nits when structural issues exist.
19
+ - Do **not** spawn nested subagents unless the user or parent explicitly asks.
20
+
21
+ ## Parent orchestration
22
+
23
+ Typical flow: collect `git diff <base>...HEAD` (default base `main`) and the full contents of changed files with this chat's own tools (`bash`, `read`, `grep`), or with one `Task` `generalPurpose` / `poteto-agent` helper when the tree is large. Then invoke this agent with `subagent_type: "thermo-nuclear-code-quality-review"` and a user prompt containing `### Git / diff output` and `### Changed file contents`. Do not invent Task types such as `shell` or `explore`; only the types in `<pstack_subagents>` exist.
Binary file
@@ -73,7 +73,7 @@ i want this setup session to run in the target repository, so a fresh subagent i
73
73
 
74
74
  if pi-pstack or any shared dependency does not resolve, stop and explain what failed. do not move `.pi/automations/benny/skills/` into `.pi/skills/` or expect its files to appear in the slash-skill list.
75
75
 
76
- tell me that subscriptions live in the pi process: the session that creates them must keep running, for example in tmux, and they expire after seven days unless renewed. do not create or update a subscription until i explicitly ask.
76
+ tell me that creating a subscription auto-starts `pstack-routines-supervisor`, that Benny's owner-session wakes park while this chat is offline until the same session is restored, and that subscriptions expire after seven days unless renewed. only `new_session` timers can start detached work while the owner is offline. for reboot survival, ask whether to run `packaging/install-supervisor-unit.sh --workspace <target-repository>` and run it when i say yes. do not create or update a subscription until i explicitly ask.
77
77
 
78
78
  for first-time creation, create the triage subscription first, check it with `list_subscriptions`, and confirm one harmless fire before creating the repro subscription.
79
79
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  benny gives you two pi automations for slack issue reports. one triages each report. the other reproduces confirmed bugs and may prepare a small draft fix.
4
4
 
5
- a pi automation is a pi-pstack subscription in a long-running pi session rooted in the target repository. a scheduled sweep is `subscribe_timer` with a cron schedule. each fire wakes that session, which hands one report to a background subagent on the automation's model. a push trigger is `subscribe_webhook`: a slack app or relay you run posts each new report to the local routine url. slack reads and writes go through a slack mcp server configured in pi (`pi mcp list`). durable memory is plain files in a directory setup names, such as `~/.pi/agent/pstack/automations/benny/memories/`.
5
+ a pi automation is a pi-pstack subscription rooted in the target repository. creating one auto-starts `pstack-routines-supervisor`. owner-session wakes received while the setup chat is offline park until that same session is restored. a scheduled sweep is `subscribe_timer` with a cron schedule. each fire hands one report to a background subagent on the automation's model. a push trigger is `subscribe_webhook`: a slack app or relay you run posts each new report to the local routine url. slack reads and writes go through a slack mcp server configured in pi (`pi mcp list`). durable memory is plain files in a directory setup names, such as `~/.pi/agent/pstack/automations/benny/memories/`.
6
6
 
7
7
  the files in this directory are dormant setup and automation sources. they do not appear as slash skills.
8
8
 
@@ -17,4 +17,4 @@ the files in this directory are dormant setup and automation sources. they do no
17
17
 
18
18
  ## what differs from hosted automations
19
19
 
20
- subscriptions live in the pi process. they run only while the session that created them runs, so keep it open, for example in tmux, and keep the machine awake. they come back when you resume that session after a restart. they expire after seven days by default: `list_subscriptions` shows `expiresAt`, and renewing one means `unsubscribe`, then subscribing again with the same name. a webhook routine listens on `127.0.0.1` only, so slack cannot reach it directly. a push trigger needs a relay you run.
20
+ creating a subscription auto-starts `pstack-routines-supervisor`. keep the owning pi session running for immediate handling, or restore it later to drain parked wakes. only a timer explicitly configured with `sessionStrategy: "new_session"` starts detached work while its owner is offline. for reboot survival, run `packaging/install-supervisor-unit.sh --workspace <target-repository>` (idempotent launchd or systemd user unit). if the supervisor cannot start, subscriptions still arm in the creating pi process and stop when that process exits, so tmux still works as a fallback. they expire after seven days by default: `list_subscriptions` shows `expiresAt`, and renewing one means `unsubscribe`, then subscribing again with the same name. a webhook routine listens on `127.0.0.1` only, so slack cannot reach it directly. a push trigger needs a relay you run.
@@ -15,7 +15,7 @@ Benny needs external configuration and two live automations. Each automation is
15
15
  - Timer mode (default): `subscribe_timer` with a 5-field `cron`. Each fire wakes the owning session, which sweeps the source channel, claims one report, and hands it to one background `Task` on the automation's configured model. The run's result arrives as a Task notification.
16
16
  - Webhook mode: `subscribe_webhook`. Each POST to the local routine URL wakes the owning session with a `[routine]` turn, and the prompt hands the event to one background `Task` on the automation's configured model.
17
17
 
18
- Subscriptions live in the Pi process. They stop when that session exits, return when it is resumed, and expire (default seven days). Tell the user this before creating anything.
18
+ Creating a subscription auto-starts `pstack-routines-supervisor`. Benny's `wake_self` timers and webhook routines target the owning session. While it is offline, wakes park until that session is restored. Only `new_session` timers can start detached work while the owner is offline. Subscriptions expire after seven days unless renewed. Tell the user this before creating anything. For fires that survive a reboot, ask whether to run `packaging/install-supervisor-unit.sh --workspace <target-repository>` (resolve the script from the pi-pstack package root) and run it when they say yes.
19
19
 
20
20
  Do not create or update a subscription until the user explicitly asks. Never put a secret value in pack files, prompts, memory, or committed configuration.
21
21
 
@@ -38,7 +38,7 @@ If this file is already being read from the target destination, treat the copy a
38
38
 
39
39
  Confirm that pi-pstack is installed in Pi. A personal install (`pi install <path-to-pi-pstack>`) serves every repository on this machine. A project install (`pi install -l <path-to-pi-pstack>`) writes the target repository's `.pi/settings.json`; preserve every unrelated setting and package entry when that file exists, and validate it after editing.
40
40
 
41
- This setup session must run in the target repository, because a `Task` subagent starts in its parent's working directory. If it does not, stop and tell the user to start Pi in the target repository and point it at `FOR_AGENTS.md` again. Start a fresh `Task` subagent with `readonly: true`. Ask it which of these skills its system prompt lists as installed:
41
+ This setup session must run in the target repository, because a `Task` subagent starts in its parent's working directory. If it does not, stop and tell the user to start Pi in the target repository and point it at `FOR_AGENTS.md` again. Start a fresh `Task` subagent with `readonly: true`. Ask it to resolve `<SKILLS>` from its own system prompt and read each required `<SKILLS>/<name>/SKILL.md` file below. It must report each absolute path and confirm the file's frontmatter names the required skill. Hidden skills need not appear in Pi's automatic skill catalog.
42
42
 
43
43
  - `how`
44
44
  - `why`
@@ -51,7 +51,7 @@ This setup session must run in the target repository, because a `Task` subagent
51
51
  - `principle-fix-root-causes`
52
52
  - `principle-prove-it-works`
53
53
 
54
- Do not count a skill this session read by hand. The check must show that a fresh subagent in the target repository receives pi-pstack.
54
+ Do not count a skill this session read by hand or a catalog listing alone. The check must show that a fresh subagent in the target repository receives pi-pstack's host instructions and can read every required installed file.
55
55
 
56
56
  If pi-pstack or any shared dependency does not resolve, stop and explain the failure.
57
57
 
@@ -169,7 +169,7 @@ Ask whether this is first-time creation or configuration of existing subscriptio
169
169
 
170
170
  Read `../../FOR_AGENTS.md` from the copied pack as the primary user-intent source for either path. Use it to understand the two triggers, tools, instructions, outcomes, and shared rules.
171
171
 
172
- The owning session must be interactive or RPC, rooted in the target repository, and expected to keep running. A print or JSON run cannot own a subscription. Suggest a dedicated tmux window, such as `tmux new -s benny 'cd <target-repository> && pi'`. In both trigger modes, each fire hands its report to one background `Task` with the automation's configured `model`, so one owning session serves both automations, whatever model that session runs on.
172
+ The owning session must be interactive or RPC and rooted in the target repository. A print or JSON run cannot create a subscription. Creating the subscription auto-starts `pstack-routines-supervisor`. Keep the owning session available for prompt handling, or restore it later to drain parked wakes. In both trigger modes, each delivered fire hands its report to one background `Task` with the automation's configured `model`. After both subscriptions exist, ask whether to install the reboot unit with `packaging/install-supervisor-unit.sh --workspace <target-repository>`, and run it only when the user says yes.
173
173
 
174
174
  ### First-time creation
175
175
 
@@ -229,7 +229,7 @@ To renew an expiring subscription, do the same with the unchanged prompt. Do not
229
229
 
230
230
  ### Creation boundary
231
231
 
232
- Create Benny's automations only with pi-pstack's `subscribe_timer` and `subscribe_webhook` tools in the owning session. Never start a scheduler outside Pi, such as `cron` or `launchd`, and never expose the routine listener beyond `127.0.0.1` from this setup.
232
+ Create Benny's automations only with pi-pstack's `subscribe_timer` and `subscribe_webhook` tools in the owning session. Do not invent a separate `cron` or `launchd` schedule for Benny. The opt-in `packaging/install-supervisor-unit.sh` install is the reboot path for the durable supervisor, not a Benny schedule. Never expose the routine listener beyond `127.0.0.1` from this setup.
233
233
 
234
234
  Do not let either automation handle normal traffic until the thread-safety test passes.
235
235
 
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ # Starts the durable routines supervisor for one workspace.
3
+ set -euo pipefail
4
+ here="$(cd "$(dirname "$0")" && pwd)"
5
+ entry="$here/../src/subscriptions/supervisor-main.ts"
6
+ if command -v bun >/dev/null 2>&1; then
7
+ exec bun "$entry" "$@"
8
+ fi
9
+ exec node --experimental-strip-types "$entry" "$@"
@@ -115,7 +115,7 @@ Every loop above still waits for you to start it. A scheduled or event-driven au
115
115
  - Every stage can stop the line. Triage can decide the report is expected behavior, repro can fail to reproduce it, and the fixer can judge the change too risky. Each of those outcomes is useful, because it keeps bad work from reaching the next stage, where it costs more to undo.
116
116
  - Every stage hands over evidence. Repro attaches screenshots and video of the broken state, and the fix attaches before-and-after proof. A human can then check that the agent fixed the right thing before reading a line of code.
117
117
 
118
- pstack ships this as a dormant [automation pack](../../automations/benny/README.md) for Slack issue reports. It runs as subscriptions in a Pi session you keep running. One automation triages each report. The other reproduces confirmed bugs and may prepare a small draft fix. Point an agent at its [`FOR_AGENTS.md`](../../automations/benny/FOR_AGENTS.md) and name the target repository to set it up.
118
+ pstack ships this as a dormant [automation pack](../../automations/benny/README.md) for Slack issue reports. It runs as pi-pstack subscriptions. Creating a subscription auto-starts `pstack-routines-supervisor` for the workspace. Benny's timers and webhook routines target their owning Pi session. Keep it running for immediate handling, or resume it later to drain parked events. Only timers explicitly configured with `sessionStrategy: "new_session"` start detached work while their owner is offline. For reboot survival, run [`packaging/install-supervisor-unit.sh`](../../packaging/install-supervisor-unit.sh) `--workspace <repo>` (it writes the launchd or systemd unit from the examples under `packaging/`). One automation triages each report. The other reproduces confirmed bugs and may prepare a small draft fix. Point an agent at its [`FOR_AGENTS.md`](../../automations/benny/FOR_AGENTS.md) and name the target repository to set it up.
119
119
 
120
120
  **Pitfall:** a duration is not a finish condition. "work on this for 4 hours" gives the agent nothing to check, and you'll wake up to four hours of motion instead of a result. Give `/loop` a predicate that can pass or fail.
121
121
 
@@ -93,7 +93,7 @@ Read every output yourself before accepting the verdict. If you disagree with th
93
93
 
94
94
  ## Build a bot UI with `/make-bot-ui`
95
95
 
96
- One situational skill is for driving a Pi session from a page. [`/make-bot-ui`](../../skills/make-bot-ui/SKILL.md) builds a small page whose buttons wake this Pi session through a pi-pstack webhook routine (`subscribe_webhook`). For example, you could swipe through a review queue and have each swipe ask the session to act on that item. The session that owns the routine is the bot, so keep it running. A server on your machine holds the webhook's sender key, so the key never reaches the browser or the chat. The skill also covers exposing the page on Tailscale.
96
+ One situational skill is for driving agent work from a page. [`/make-bot-ui`](../../skills/make-bot-ui/SKILL.md) builds a small page whose buttons POST to a pi-pstack webhook routine (`subscribe_webhook`). For example, you could swipe through a review queue and have each swipe ask an agent to act on that item. Creating the subscription auto-starts `pstack-routines-supervisor`. Keep the owning Pi session running for immediate handling. Events accepted while it is offline wait until that same session resumes. For reboot survival, run `packaging/install-supervisor-unit.sh --workspace <repo>`. A server on your machine holds the webhook's sender key, so the key never reaches the browser or the chat. The skill also covers exposing the page on Tailscale.
97
97
 
98
98
  **Pitfall:** don't edit a skill mid-task because it's misbehaving. Fix it in its own PR and keep the task moving. A skill edit that ships tangled into feature work is invisible to review and impossible to evaluate.
99
99
 
@@ -158,7 +158,7 @@ That's the whole prompt. [`/bro`](../../skills/bro/SKILL.md) restates the last m
158
158
 
159
159
  [`/ketchup`](../../skills/ketchup/SKILL.md) tells you in plain words what changed since your last message, then lists each call waiting on you with its pick, evidence, and risk. It changes nothing while it reports.
160
160
 
161
- To watch the catch-up instead, run [`/ketchup-video`](../../skills/ketchup-video/SKILL.md). It shows what happened in a short subtitled video of slides, and lists the calls waiting on you as text under it.
161
+ To watch the catch-up instead, run [`/ketchup-video`](../../skills/ketchup-video/SKILL.md). It opens a short subtitled video of slides in the system player, shows one frame per slide in chat, and lists the calls waiting on you as text under it.
162
162
 
163
163
  ## The pitfalls
164
164
 
@@ -1,8 +1,13 @@
1
1
  # Pi native gaps
2
2
 
3
- pi-pstack uses Pi's public extension API. Four mechanisms have no public equivalent in Pi 1.4.0, so the package
4
- implements them itself against documented lower-level surfaces. Each entry names what Pi lacks, what the package does
5
- instead, and what would let the copy go. Pi line numbers refer to `@earendil-works/pi-coding-agent@1.4.0`.
3
+ pi-pstack uses Pi's public extension API. Four mechanisms have no public equivalent in Pi 1.5.0, so the package
4
+ implements them itself against documented lower-level APIs. Each entry names what Pi lacks, what the package does
5
+ instead, and what would let the copy go.
6
+
7
+ The Pi 1.5.0 audit checked `docs/extensions.md`, `docs/rpc.md`, `docs/rpc-extension-ui.md`,
8
+ `dist/index.d.ts`, `dist/modes/rpc/rpc-client.d.ts`, and the corresponding installed implementations.
9
+ Pi paths below refer to `@earendil-works/pi-coding-agent@1.5.0`. Legacy line coordinates are retained
10
+ as search hints from the 1.4.0 audit, not as 1.5.0 line references. This is a contract audit, not a new runtime-test receipt.
6
11
 
7
12
  ## 1. The subagent process
8
13
 
@@ -24,7 +29,7 @@ instead, and what would let the copy go. Pi line numbers refer to `@earendil-wor
24
29
  listeners and offers no way to send the response; its `send` is private.
25
30
  - **stderr and exit.** The runner keeps the last 8 KiB of stderr and reports the child's exit code in the outcome
26
31
  (`outcomeOf`, `:226-234`). `RpcClient` appends stderr without a bound and mirrors it into the parent's stderr
27
- (`rpc-client.js:49-52`), and exposes neither an exit promise nor a code.
32
+ (`rpc-client.js:49-52`), and exposes neither an exit promise nor a code. Pi 1.5.0 does reject pending requests on process exit and startup errors, but that does not expose a successful exit outcome.
28
33
 
29
34
  `RpcClient` does cover the rest of what the runner sends: `prompt(message, images, "steer")`, `abort`, `clearQueue`,
30
35
  `followUp`, and the event stream. The runner speaks the JSONL protocol from `docs/rpc.md` directly and keeps its own
@@ -36,7 +41,8 @@ thin adapter over `RpcClient`.
36
41
 
37
42
  ## 2. The skill block `/mode` sends
38
43
 
39
- `modeSection` (`src/mode.ts:52-58`) builds the block Pi's own `/skill:name` expansion builds
44
+ `modeSection` (`src/mode.ts:52-58`) strips frontmatter with Pi's exported `stripFrontmatter` (`dist/index.d.ts:50`) and
45
+ wraps the body in the `<skill name="..." location="...">` block Pi's own `/skill:name` expansion builds
40
46
  (`AgentSession._expandSkillCommand`, `dist/core/agent-session.js:1739`). Pi exports `parseSkillBlock` and
41
47
  `formatSkillsForPrompt` (`dist/index.d.ts:3,23`), which parse a block and format the skills catalog; neither formats
42
48
  one skill block. **When this goes away.** Pi exports the block formatter and `mode.ts` calls it.
@@ -0,0 +1,94 @@
1
+ # Software architecture reconstruction: pstack 0.15.36 and dependencies
2
+
3
+ This is a historical static-analysis record, not proof of current full parity. The repository's `parity/pi-pstack-sar/requirements.md` maps the later SAR report to implementations and checks. Source provenance is published in `package.json.pstackSource`. A passing resource inventory does not prove workflow execution or remote-service behavior.
4
+
5
+ ## Goal
6
+
7
+ Reconstruct the software architecture of `pstack` `0.15.36` and all of its dependencies with the REA MCP server, then map every upstream capability and dependency to Pi's native extension mechanisms in `pi-pstack` with zero dependencies on the upstream `pstack` plugin.
8
+
9
+ ## Sources and REA evidence ledger
10
+
11
+ Every executable package in `pstack` `0.15.36`, its sibling `team-kit` `1.2.0` plugin, and `pi-pstack` `src/` was analyzed in this session with `rea-javascript-application` v1, `rea-analysis-view` v1, and `rea-javascript-application-workflows` v1.
12
+
13
+ | Target | Format | Root SHA-256 | Parent Evidence ID | Summary / View Evidence ID | Files / JS parsed |
14
+ | --- | --- | --- | --- | --- | --- |
15
+ | `pstack/skills/poteto-mode/scripts` (clean cache) | directory | `ab08fdd851002bfdd61fcc3c902bf0e6bb2bbd4b0229b5443e30626e3a788e07` | `ev_bf12ac9c3d463df579c1009ce80a874431c3cc14c168a783114077161d704139` | `ev_5cb366a2d252413ad6fc6350f1644aab7f751bfcfdd86e8af41a18851c99ac29`, `ev_f9e9795252c5470742dd90329b7bc1198882f4f5138e369cadb6a0397a0f5ee0`, `ev_5935daf21a6e6160681b399f1cc7482596cfedd3a7494c859a0e369fa6b0a946` | 15 relevant, 13 JS/TS parsed, 0 failures |
16
+ | `pstack/skills/poteto-mode/scripts` (with `node_modules`) | directory | `5b92deccc760dacf7f0f5278c2c4ecff34b98d87fc70f04fecc2210fcc52980c` | `ev_d6ff54533e36b7719f1b6e18031ee2521ff4368bdabe87f34372f46a1760c3e8` | retained in session bundle | Includes `commander@14.0.0` and `typescript@7.0.2` |
17
+ | `pstack/skills/statechart/scripts` | directory | `2193bf21071d9a8d176d142c5aa0d3257c98de4689e948e21b20957f83616e33` | `ev_5068b39b821b4f8848661475ed4d4e141343d183785cd0d1f48cc4c560700b24` | `ev_ce9ee247f111b881d6c100242cfa0560623e65b11248377553e053fb8b6f62f3`, `ev_bd7036ccd42e670602201871d0feba62dfffde58a1e942edcf879019555c25d2` | 50 relevant, 48 JS/TS parsed, 0 failures |
18
+ | `team-kit/skills/pr-review-canvas` | directory | `2666f69c5a27cb4256a403747f8606c55d68b7ab28556d7f0d3fe6fe359f9b3a` | `ev_2c98abedf7c1c05212d64174a87f0039f79218f72f4b0f1def35f6f3c2327ac9` | `ev_d63a021f7e544b9403b2a48e25bebe7ad59220b82aa1378ffed159e559c2da19`, `ev_2c3f2ede73725fa0fa715e3992b851b3e526d2df85d8e1ef1de50752d04bf93d` | 2 relevant, 1 JS parsed (`renderer.js`), 0 failures |
19
+ | `pi-pstack/src` | directory | `ebb60ef861603834b12d5f9a45f4108759d8c29d0605b38e07560456c0605ce8` | `ev_6fe43d2bbfab36c6763a2d1e940ee728fdbbe2ad2abb9162f70c102ccab8860f` | `ev_f5ea22bb2d470f8108ea52961fdbd0f8411142176ac7db78b0bdeca4c0f0e37e`, `ev_16b3d7080fa763f288e7e5a8291873a3bb1130fd1ad6be06070d51e7d753b71b` | 36 relevant, 36 TS parsed, 0 failures |
20
+ | `pi-pstack/skills/statechart/scripts` | directory | `9b47d92dbdc42204b53f020bdc7f802b6f5fff6220ecbe164dcf263906f2f914` | `ev_a8c8d7db63d2519d306e47d6d724a5119b28a1049a9eddbd73ea6f29dbc94caf` | `ev_1091007aca08202f865c78a8dd7452fa09d54fa0dcb807428f4d5c38732cb39f` | 50 relevant, 48 JS/TS parsed, 0 failures |
21
+ | `pi-pstack/skills/pr-review-canvas` | directory | `2666f69c5a27cb4256a403747f8606c55d68b7ab28556d7f0d3fe6fe359f9b3a` | `ev_e2dd5f48359956b83e32cdf0ac784c770cb97673cf712a4aaf490a27ecc1e8db` | `ev_12653e2b69c57038367443acf5635729793344211a0a13ef80a5c3dfdb1c376f` | 2 relevant, 1 JS parsed, 0 failures |
22
+
23
+ ### Focused module item and trace Evidence IDs
24
+
25
+ - `bootstrap.ts` module item view: `ev_76dece32cf003cb0c2ba0994d5c886d5ff51b2c4dbeabc63e1b01fd5f4df0f42`
26
+ - `check-plan.mjs` module item view: `ev_d8b696f0eebbd0ee8619cb4a70bcfcec7d85d8f7c397a717799db1217e7ec99b`
27
+ - `statechart/scripts/run.ts` module item view: `ev_e43256ff8736be8e4ab9dc0a065c5acc134048f557bf3a9bd0b78ce537a1bc1b`
28
+ - `pr-review-canvas/renderer.js` module item view: `ev_161a445223f452c7cc7f3104399476f625137fc93a3fc5fe4b9bd485742185c4`
29
+ - Outgoing feature trace on `watch-pr/github.ts`: `ev_47b1b4f41568acc919b7b99f7b18014ab564745436bfc493d9bf88ad56f15f29` (18 matched seeds, 27 traced nodes, 28 traced edges)
30
+ - Outgoing feature trace on `statechart/scripts/run.ts`: `ev_b2c06c4cca93538bcb8b18f0570627f9149c127b69b3055b7a4d174dca19e6fd` (7 matched seeds, 115 traced nodes, 194 traced edges)
31
+ - Outgoing feature trace on `pi-pstack/src/index.ts`: `ev_22556088c77e2fa9073d079a7ed0796b2545e2f36a6223d130b2df64a8b04d12` (3 matched seeds, 372 traced nodes, 558 traced edges)
32
+ - Version comparison for `statechart/scripts`: `ev_a220a808b81c474aaaa62752f324f54976d47a43ccc4e7100da1cff2b4c470a4` (`changed: 1`, `added: 0`, `removed: 0`, only `package.json` package name differs)
33
+ - Version comparison for `pr-review-canvas`: `ev_1066025d4b0edd77d4d50a798a4cd11b3581a601509962224fa04546d55d549d` (`changed: 0`, `added: 0`, `removed: 0`, byte-identical SHA-256)
34
+
35
+ ## Architecture of pstack 0.15.36 and its dependency graph
36
+
37
+ ```
38
+ pstack 0.15.36
39
+ ├── skills/ (58 workflow, principle, research, and verification skill directories)
40
+ ├── agents/ (poteto-agent, comment-sicko)
41
+ ├── automations/benny/ (setup-benny, triage-issue-reports, reproduce-and-fix-issues)
42
+ ├── docs/guide/ (10 guide chapters + README)
43
+ └── soft dependencies (vendored into pi-pstack)
44
+ ├── team-kit 1.2.0
45
+ │ ├── skills/ (18 skills, including deslop, control-cli, control-ui, pr-review-canvas)
46
+ │ ├── agents/ (ci-watcher, thermo-nuclear-code-quality-review)
47
+ │ └── rules/ (no-inline-imports, typescript-exhaustive-switch)
48
+ └── create-skill (host built-in skill for authoring and tuning SKILL.md files)
49
+ ```
50
+
51
+ ### Executable script packages inside the skill tree
52
+
53
+ 1. **`skills/poteto-mode/scripts/` (`ev_bf12ac9c3d463df579c1009ce80a874431c3cc14c168a783114077161d704139`)**:
54
+ - `bootstrap.ts` (`ev_76dece32cf003cb0c2ba0994d5c886d5ff51b2c4dbeabc63e1b01fd5f4df0f42`): verifies `node_modules/commander` and runs `bun install --frozen-lockfile` via `Bun.spawnSync` on first run before re-executing the target script.
55
+ - `watch-pr/` (`cli.ts`, `github.ts`, `policy.ts`, `render.ts`, `types.ts`): CLI built on `commander@14.0.0` that polls GitHub PR status, review threads (`REVIEW_THREADS_QUERY`), check runs, and mergeability by spawning `gh` (`ev_47b1b4f41568acc919b7b99f7b18014ab564745436bfc493d9bf88ad56f15f29`).
56
+ - `check-plan.mjs` (`ev_d8b696f0eebbd0ee8619cb4a70bcfcec7d85d8f7c397a717799db1217e7ec99b`): standalone Node script (`node:fs`, `node:process`) that validates multi-phase plan Markdown structure.
57
+ - `worktree-audit.sh`: bash script using `git`, `rg`, `jq`, and BSD or GNU `stat` and `date` to classify git worktrees against Pi session and subagent transcript activity.
58
+ 2. **`skills/statechart/scripts/` (`ev_5068b39b821b4f8848661475ed4d4e141343d183785cd0d1f48cc4c560700b24`)**:
59
+ - `statechart` wrapper, `statechart.ts`, `worker.ts`, `pipeline.ts`, `ir.ts`, `run.ts` (`ev_e43256ff8736be8e4ab9dc0a065c5acc134048f557bf3a9bd0b78ce537a1bc1b`), `frontends/`, `passes/`, and `backends/`.
60
+ - `run.ts` (`ev_b2c06c4cca93538bcb8b18f0570627f9149c127b69b3055b7a4d174dca19e6fd`) resolves Java (`java@temurin-25` through `mise` or `JAVA`) and `tla2tools.jar` (`TLA2TOOLS`), invokes `tlc2.TLC`, parses state graphs and counterexample traces into `ir.ts`, and produces Mermaid charts, reports, and plain-text TLC output. The separate rendering guide and tests use Pele and Mermaid.
61
+ 3. **`skills/pr-review-canvas/` (`ev_2c98abedf7c1c05212d64174a87f0039f79218f72f4b0f1def35f6f3c2327ac9`)**:
62
+ - `renderer.js` (`ev_161a445223f452c7cc7f3104399476f625137fc93a3fc5fe4b9bd485742185c4`), `template.html`, and `styles.css` render an interactive diff review canvas in the browser with zero npm dependencies.
63
+ 4. **`skills/show-me-your-work/scripts/log.sh`**:
64
+ - Appends ISO-8601 timestamped rows to a TSV decision trail while sanitizing tabs, newlines, and spreadsheet-formula prefix characters.
65
+
66
+ ## Pi-native mechanism architecture in pi-pstack
67
+
68
+ REA analysis of `pi-pstack/src` (`ev_6fe43d2bbfab36c6763a2d1e940ee728fdbbe2ad2abb9162f70c102ccab8860f`, trace `ev_22556088c77e2fa9073d079a7ed0796b2545e2f36a6223d130b2df64a8b04d12`) maps each host feature to Pi 1.4.0 native extension mechanisms (`native-gaps.md` documents the remaining lower-level surfaces):
69
+
70
+ | Host capability | `pi-pstack` module | Pi 1.4.0 native mechanism |
71
+ | --- | --- | --- |
72
+ | `/name` skill aliases and completions | `src/aliases.ts`, `src/autocomplete.ts` | `pi.on('input')` rewriting `/name` to `/skill:name`, `ctx.ui.addAutocompleteProvider`, `pi.getCommands()` |
73
+ | Sticky mode (`/mode <skill>`) | `src/mode.ts` | `pi.registerCommand('mode')`, `pi.appendEntry('pstack/mode')`, `ctx.sessionManager.getBranch()`, `stripFrontmatter`, `ctx.ui.setStatus`, `before_agent_start` `systemPromptOptions.sections.pstack_mode` |
74
+ | Plan mode (`/plan`) | `src/plan.ts`, `src/readonly-shell.ts` | `pi.registerCommand('plan')`, `pi.setActiveTools`, `pi.on('tool_call')`, `createBashTool` with `spawnHook` and `@anthropic-ai/sandbox-runtime` |
75
+ | Model rule (`pstack-models.md`) | `src/rule.ts`, `src/sections.ts` | `stripFrontmatter`, `before_agent_start` `systemPromptOptions.sections.pstack_models` and `pstack_host` |
76
+ | `Task` subagents (`fresh`, `resume`, `steer`, `fork`, `fork_turns`, `cloud` worktree, `readonly`, `file_attachments`) | `src/task/tool.ts`, `src/task/runner.ts`, `src/task/records.ts`, `src/task/registry.ts`, `src/task/worktree.ts` | `pi.registerTool`, `parseSessionEntries`, `SessionManager.open`, `SessionManager.forkFrom`, `detectSupportedImageMimeTypeFromFile`, `truncateHead`, `pi --mode rpc`, `pi.on('agent_before_settle')`, `pi.sendMessage` with `pi.registerMessageRenderer('pstack/task')` |
77
+ | `stop_agent` and `agent_status` | `src/task/stop.ts`, `src/task/status.ts` | `pi.registerTool` with MCP `annotations`, process-group signaling (`-pid`), run-lock inspection |
78
+ | `TodoWrite` checklist and widget | `src/todo.ts` | `pi.registerTool` (`executionMode: 'sequential'`), tool-result `details.todos` reconstructed from `ctx.sessionManager.getBranch()`, `ctx.ui.setWidget('pstack-todos')` |
79
+ | `AskQuestion` structured questions | `src/ask.ts` | `pi.registerTool` (`exposure: 'model-only'`, `executionMode: 'sequential'`), `ctx.ui.select`, `ctx.ui.input` |
80
+ | `/loop` and `Loop` tool | `src/loop.ts` | `pi.registerCommand('loop')`, `pi.registerTool`, `pi.on('agent_settled')`, `pi.sendUserMessage(..., { expandPromptTemplates: true })` |
81
+ | Subscriptions and webhook routines (`subscribe_github_pr`, `subscribe_timer`, `subscribe_webhook`, `list_subscriptions`, `unsubscribe`, `/routines`) | `src/subscriptions/*` | `pi.registerTool`, `pi.registerCommand('routines')`, `pi.appendEntry('pstack/subscriptions')`, `pi.sendMessage` with `pi.registerMessageRenderer('pstack/subscription')`, durable supervisor (`pstack-routines-supervisor`) with live-session wake delivery |
82
+ | `visualize` charts | `src/visualize.ts` | `pi.registerTool` rendering Unicode bar and line charts and writing standalone SVG files to the session artifacts directory |
83
+
84
+ ## Parity predicate
85
+
86
+ 1. Every `pstack` `0.15.36` skill (58) and agent (2) exists under `pi-pstack`.
87
+ 2. Every `team-kit` `1.2.0` skill (18), agent (2), and rule (2, as skills plus always-applied host prompt rules) plus `create-skill` (1) exists under `pi-pstack` (79 total skills, 4 agent files).
88
+ 3. `pi-pstack` has no runtime dependency or synchronization against an upstream plugin checkout or cache. Normal package checks need no upstream installation. Passive provenance and optional source-comparison audits do not load upstream code.
89
+ 4. Every host mechanism named in playbooks runs on Pi's native extension APIs (`ExtensionAPI`, `parseSessionEntries`, `SessionManager`, `stripFrontmatter`, `detectSupportedImageMimeTypeFromFile`, `truncateHead`, `createBashTool`, `registerMessageRenderer`, `registerTool`, `registerCommand`).
90
+ 5. Package checks run with `bun run typecheck` and `bun run test` from the package directory. `bun run test:statechart` additionally runs the bundled statechart suite. Set `TLA2TOOLS` and `JAVA` to run real TLC cases. Repository-only checks such as `node scripts/check-pi-mechanisms.mjs` run from the repository root and are not shipped package commands.
91
+
92
+ ## REA coverage notes
93
+
94
+ Static JavaScript and TypeScript semantic graphs report bounded unknowns for dynamic property lookups and cross-function value flows (3,303 in `poteto-mode/scripts`, 12,803 in `statechart/scripts`, 356 in `pr-review-canvas`, and 7,204 in `pi-pstack/src`), and 1 unanalyzed inline script in `pr-review-canvas/template.html`. The Vitest tests cover their asserted extension contracts. They do not prove all runtime behavior, external services, or the separately executed statechart suite. See [`native-gaps.md`](native-gaps.md) for the remaining lower-level Pi 1.4.0 surfaces.
package/package.json CHANGED
@@ -1,13 +1,32 @@
1
1
  {
2
2
  "name": "@justjoshn/pi-pstack",
3
- "version": "0.15.36-pi.1",
4
- "description": "pstack 0.15.36 for Pi: rigorous agent workflows and principles as Pi skills, with the host features they use: subagents, todos, modes, plan mode, the model rule, /loop, subscriptions and routines, AskQuestion, and visualize",
3
+ "version": "0.15.36-pi.7",
4
+ "description": "pstack 0.15.36 for Pi with its soft-dependency team-kit skills vendored in: rigorous agent workflows and principles as Pi skills, with the host features they use: subagents, todos, modes, plan mode, the model rule, /loop, subscriptions and routines, AskQuestion, and visualize",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
+ "pstackSource": {
8
+ "repository": "https://github.com/cursor/plugins",
9
+ "revision": "ae5650febf4320793844c12c4adaa937f417f8da",
10
+ "path": "pstack",
11
+ "version": "0.15.36",
12
+ "lastChange": "c742dd61706fbacc1b95f1a20b7b988cf096ce6c"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/just-joshn/pi-customizations.git",
17
+ "directory": "extensions/pi-pstack"
18
+ },
19
+ "homepage": "https://github.com/just-joshn/pi-customizations/tree/main/extensions/pi-pstack#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/just-joshn/pi-customizations/issues"
22
+ },
7
23
  "keywords": [
8
24
  "pi-package",
9
25
  "pstack"
10
26
  ],
27
+ "bin": {
28
+ "pstack-routines-supervisor": "./bin/pstack-routines-supervisor"
29
+ },
11
30
  "engines": {
12
31
  "node": ">=22.19.0"
13
32
  },
@@ -23,10 +42,25 @@
23
42
  "./skills"
24
43
  ]
25
44
  },
45
+ "files": [
46
+ "src",
47
+ "skills",
48
+ "agents",
49
+ "automations",
50
+ "bin",
51
+ "docs",
52
+ "assets",
53
+ "licenses",
54
+ "packaging",
55
+ "README.md",
56
+ "CHANGELOG.md",
57
+ "LICENSE"
58
+ ],
26
59
  "scripts": {
27
60
  "typecheck": "tsc --noEmit -p tsconfig.json",
28
61
  "test": "vitest run",
29
62
  "test:coverage": "vitest run --coverage",
63
+ "test:statechart": "node --disable-warning=ExperimentalWarning --test skills/statechart/scripts/test/*.test.ts",
30
64
  "live:e2e": "node scripts/live-e2e.mjs"
31
65
  },
32
66
  "dependencies": {
@@ -40,12 +74,13 @@
40
74
  "typebox": "*"
41
75
  },
42
76
  "devDependencies": {
43
- "@earendil-works/pi-ai": "1.4.0",
44
- "@earendil-works/pi-agent-core": "1.4.0",
45
- "@earendil-works/pi-coding-agent": "1.4.0",
46
- "@earendil-works/pi-tui": "1.4.0",
77
+ "@earendil-works/pi-ai": "1.5.0",
78
+ "@earendil-works/pi-agent-core": "1.5.0",
79
+ "@earendil-works/pi-coding-agent": "1.5.0",
80
+ "@earendil-works/pi-tui": "1.5.0",
47
81
  "@types/node": "^22.19.0",
48
82
  "@vitest/coverage-v8": "^5.0.2",
83
+ "fast-check": "4.5.3",
49
84
  "typebox": "1.3.27",
50
85
  "typescript": "^7.0.2",
51
86
  "vitest": "^5.0.2"