Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"name": "t3-pstack",
"source": "./plugins/pstack",
"description": "pstack for T3 Code: rigorous agent workflows whose panels and fan-outs run across model families through T3. Original pstack by Lauren Tan (poteto).",
"version": "2.0.0-rc.6"
"version": "2.0.0-rc.7"
}
]
}
23 changes: 23 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

This file is the release changelog, with one `## <version> - <title>` entry per release, newest first. The Cursor-to-T3 rewrite rules live in [`tools/substitutions.json`](tools/substitutions.json), and the [sync boundary](CONTRIBUTING.md#the-sync-boundary) in `CONTRIBUTING.md` defines how a change to upstream's skill content is declared.

## 2.0.0-rc.7 - Worktree cleanup keeps ignored files, scratch, and reflog-only commits

Worktree cleanup could destroy work that existed nowhere else, as [cursor/plugins#449](https://github.com/cursor/plugins/issues/449) reports. The audit bucketed a worktree `safe` when it held only untracked scratch or an ignored file such as `.env` or `.claude/settings.local.json`. Step 5 then ran `git worktree remove --force`, and `rm -rf` on any directory that survived. A commit that only the worktree's HEAD reflog reached, such as one made on a detached HEAD, went with the worktree too. Removal deletes that reflog and leaves the commit for `git gc`. The audit also called itself read-only, yet it fetched the base ref ([cursor/plugins#470](https://github.com/cursor/plugins/issues/470)), and its `git status` rewrote the index of each worktree it read. That write can collide with an agent working in the worktree.

The audit now asks `git status` for ignored paths with `--ignored=matching`. It counts each one whose last component is not in a named list of build and cache directories, such as `node_modules`, `.venv`, `__pycache__`, `dist`, `build`, and `target`, as `ignored:N` and holds the worktree as `hold-ignored`. An ignored `build/.env` under a tracked `build/` directory still counts. The audit walks each worktree's HEAD and HEAD reflog and counts commits that no branch, tag, remote, or branch reflog reaches as `reflog:N`, held as `hold-reflog`. HEAD itself is in the walk, so a detached commit still counts after `git gc` expires its reflog. A branch reflog lives in the shared logs and outlives the worktree, so a rebased branch's old tip does not count. Both checks port Michael Denyer's [pstack-claude #277](https://github.com/michael-denyer/pstack-claude/pull/277) from his JavaScript audit to Lauren's bash script, with his test cases. Untracked scratch now holds as `hold-scratch`, and an explicit `--untracked-files` keeps a `status.showUntrackedFiles=no` config from hiding it. A worktree git cannot read holds as `unknown` instead of reading `clean`. The audit fetches only under `--fetch` and sets `GIT_OPTIONAL_LOCKS=0`, so without `--fetch` it writes nothing to the repository.

Step 5 now runs a plain `git worktree remove` and stops when it refuses, as sergchil's [jutsu `da94424`](https://github.com/sergchil/jutsu/commit/da9442422c72cc99442c1ce3500d2f2485234a31) does. A plain remove refuses tracked edits and a lock. It refuses untracked files unless a `status.showUntrackedFiles=no` config hides them, and it deletes ignored files without asking, so the audit holds both kinds itself. Step 4 deletes the scratch a user approves with `git --literal-pathspecs clean`, so `notes[1].md` matches only itself. `bun tools/generate.mjs --check` fails when any playbook force-removes a worktree, runs a recursive `rm`, runs `git clean -x`, or runs `git worktree prune`, which drops every prunable worktree's HEAD reflog at once. The audit and the playbook are declared forks that point at #449.

The plugin icon, in `plugins/pstack/.claude-plugin/icon.png` and `plugins/pstack/assets/pstack-icon.png`, carried a PNG `caBX` chunk with an image generator's signed C2PA manifest. A plugin directory screen that reads image text can take its certificate and signature for a credential. Both copies are now Michael's files from [pstack-claude #271](https://github.com/michael-denyer/pstack-claude/pull/271). Every other chunk is byte-identical, so the pixels do not change.

In a throwaway repository, rc.6's audit bucketed a worktree with an ignored `.env` and one with a detached commit `safe`. Its step 5 removed both, and the commit was gone after `git gc`. rc.7 holds both, and its step 5 removed only the clean, merged worktrees. At `99743e9` each component's dry run reports no undeclared fork, no denylist hit, and no substitution that matches nothing. Neither hooks file changes.

| Change | 2.0.0-rc.6 | 2.0.0-rc.7 | Source |
| --- | --- | --- | --- |
| Ignored files in a worktree | Not read. A worktree whose only change was an ignored `.env` read `clean` and could bucket `safe`. | `ignored:N` counts ignored paths whose last component is not one of the audit's build and cache directories, and buckets `hold-ignored`. A worktree with only `node_modules` and the like still reads `clean`. | pstack-claude #277 |
| Commits only a worktree's HEAD reflog reaches | Not checked, so a detached commit went with the worktree. | `reflog:N` counts commits only HEAD or its reflog reaches and buckets `hold-reflog`, also after `git gc` expires the reflog. A rebased branch's old tip stays in the branch reflog and does not count. | pstack-claude #277 |
| A worktree git cannot read | Read `clean` and could bucket `safe`. | `unknown` buckets `hold-wip`, and a failed reflog walk prints `reflog:?` and holds. Step 4 reads a prunable worktree's HEAD and reflog from the main checkout. | T3 fix |
| Untracked scratch | `scratch:N`, called throwaway, could bucket `safe`. | `scratch:N` buckets `hold-scratch`, and a `status.showUntrackedFiles=no` config no longer hides it. Step 4 names the paths and deletes only the ones the user approves, with a `git clean` that reads each name literally. | T3 fix |
| Cleanup step 5 | `git worktree remove --force`, then `rm -rf` on a directory that survived, then `git worktree prune`. | A plain `git worktree remove`. Its refusal is the stop, with no force flag and no hand delete. | jutsu `da94424` |
| Playbook check | None. | `bun tools/generate.mjs --check` fails on a playbook line that force-removes a worktree, runs a recursive `rm`, runs `git clean -x`, or runs `git worktree prune`. | jutsu `da94424` |
| Audit writes | Fetched the base from origin on every run, and `git status` rewrote each worktree's index, under a read-only claim. | Writes nothing to the repository unless `--fetch` is given. `GIT_OPTIONAL_LOCKS=0` keeps `git status` off the index. | T3 fix |
| Plugin icon | Carried a `caBX` chunk with a signed C2PA manifest. | No `caBX` chunk and the same pixels. `tests/image-metadata.test.mjs` fails on any tracked PNG that has one. | pstack-claude #271 |

## 2.0.0-rc.6 - Lauren's `99743e9`: marginal sections cut from four skills

t3-pstack moves to Lauren Tan's pstack at cursor/plugins `99743e9` for all three components. Only pstack changed upstream, and its version stays 0.15.25: four skills lose sections that padded or restated their core ([pstack #634](https://github.com/cursor/plugins/pull/634)). The change only deletes text. Two rules rewrote swarm lines that upstream deleted, "Fan out N parallel cloud workers." and "not the cloud concurrency limit.", so both matched nothing and are removed. Removing them moved the derived merge base and made the three-way merge conflict on swarm, so pstack synced through `bun tools/sync.mjs --bootstrap`, which derived 120 files, kept the 13 declared forks, and changed only the four upstream touched. The port's diff to those four files is upstream's line for line, apart from the T3 form of the two deleted lines. `poteto-mode`'s principles index never quoted the dropped description clause, and upstream left it alone. At `99743e9` each component's dry run reports no undeclared fork, no denylist hit, and no substitution that matches nothing. Upstream's README change falls under a path the port excludes, and neither hooks file changes.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Thanks for helping out. This repo is a **port**, not an original work: the skill
Upstream owns the skill text. This port owns the rewrite of upstream's Cursor mechanics into their T3 form, and nothing else. The rewrite has two parts:

- **Substitutions.** [`tools/substitutions.json`](tools/substitutions.json) rewrites each upstream sentence that names a Cursor mechanism: the `Task` tool, `subagent_type`, model slugs, the `pstack-models.mdc` rule, cloud agents, `/loop`, Cursor paths. Most T3 behavior the port adds, such as the dispatch ledger or the review loop, is an anchored insert: a rule whose pattern is an upstream sentence and whose replacement keeps that sentence and appends the T3 text. A substitution leaves upstream's later edits elsewhere in the file mechanical, so the port prefers it to a fork. Each rule's `rationale` names why it exists, and most cite the section of t3-pstack 1.0.14's `t3-tools.md` it replaces.
- **Forks.** [`tools/forks.json`](tools/forks.json) declares each file the port keeps in its own form, with a `kind`, a one-sentence `why`, the `since` release, and an `upstream` status. Today that is setup-pstack, which writes the T3 model sheet, the hook points of the watch-pr settle overlay, and the files that carry the rules and watch-pr fixes restored from Michael Denyer's pstack-claude. Every upstream change to a forked file needs a person to merge it, so a fork is the last resort.
- **Forks.** [`tools/forks.json`](tools/forks.json) declares each file the port keeps in its own form, with a `kind`, a one-sentence `why`, the `since` release, and an `upstream` status. Today that is setup-pstack, which writes the T3 model sheet, the hook points of the watch-pr settle overlay, the files that carry the rules and watch-pr fixes restored from Michael Denyer's pstack-claude, and the worktree audit and cleanup playbook, which fix [cursor/plugins#449](https://github.com/cursor/plugins/issues/449). Every upstream change to a forked file needs a person to merge it, so a fork is the last resort.

The port also owns files upstream does not have: the plugin manifests, the session-start hooks and their routing text, `models.json`, the sheet checker `t3-sheet.mjs`, the watch-pr settle overlay (`settle.ts`), and the transcript lookups reflect uses. The sync lists them as port-only.

Expand Down
5 changes: 3 additions & 2 deletions NOTICE-skills.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# NOTICE for the installed plugin

This plugin contains MIT-licensed work from five sources. The copyright notices and license terms travel beside this file.
This plugin contains MIT-licensed work from six sources. The copyright notices and license terms travel beside this file.

| Included work | Upstream | Copyright | License |
| --- | --- | --- | --- |
| The pstack skills, principles, scripts, and the `poteto-agent` and `comment-sicko` definitions | [cursor/plugins/pstack](https://github.com/cursor/plugins/tree/99743e9c151c8537cbbf1f98bb38f34ef3368453/pstack) | (c) 2026 Lauren Tan | [MIT](LICENSE) |
| `deslop`, `make-pr-easy-to-review`, `fix-ci`, `fix-merge-conflicts`, `get-pr-comments`, and `what-did-i-get-done` | [cursor/plugins/cursor-team-kit](https://github.com/cursor/plugins/tree/99743e9c151c8537cbbf1f98bb38f34ef3368453/cursor-team-kit) | (c) 2026 Cursor | [MIT](LICENSE-cursor-team-kit) |
| `thermos`, `thermo-nuclear-review`, `thermo-nuclear-code-quality-review`, and the `thermo-nuclear-review-subagent` and `thermo-nuclear-code-quality-review-subagent` definitions | [cursor/plugins/thermos](https://github.com/cursor/plugins/tree/99743e9c151c8537cbbf1f98bb38f34ef3368453/thermos) | (c) 2026 Cursor | [MIT](LICENSE-thermos) |
| The session-start hook scripts, `read-sheet.sh`, and `reflect/scripts/find-transcript.mjs`, which t3-pstack modified, and four `poteto-mode` rules, the worktree and head-guard rules in the Feature, Opening a PR, and Shipping playbooks, and three `watch-pr` fixes, which t3-pstack reworded or adapted for T3 | [michael-denyer/pstack-claude](https://github.com/michael-denyer/pstack-claude) | (c) 2026 Michael Denyer | [MIT](LICENSE) |
| The session-start hook scripts, `read-sheet.sh`, and `reflect/scripts/find-transcript.mjs`, which t3-pstack modified, and four `poteto-mode` rules, the worktree and head-guard rules in the Feature, Opening a PR, and Shipping playbooks, three `watch-pr` fixes, and the ignored-file and reflog-only-commit holds in `poteto-mode/scripts/worktree-audit.sh`, which t3-pstack reworded or adapted for T3, and the plugin icon | [michael-denyer/pstack-claude](https://github.com/michael-denyer/pstack-claude) | (c) 2026 Michael Denyer | [MIT](LICENSE) |
| The plain-remove prune step in the worktree-cleanup playbook, which t3-pstack adapted | [sergchil/jutsu](https://github.com/sergchil/jutsu/commit/da9442422c72cc99442c1ce3500d2f2485234a31) | (c) 2026 Sergey Chilingaryan | [MIT](LICENSE) |
| `poteto-mode/scripts/resolve-codex-transcript` and `resolve-codex-transcript.ts`, which t3-pstack modified | [ericlitman/open-pstack](https://github.com/ericlitman/open-pstack/tree/c5c8e237c324359a3d1929037da78fe66da3d1ed/plugins/pstack/skills/poteto-mode/scripts), [PR #151](https://github.com/ericlitman/open-pstack/pull/151) | (c) 2026 Eric A. Litman and Donncha O'Toole | [MIT](LICENSE) |

t3-pstack rewrites upstream's Cursor mechanics into their T3 form and adds the files its [repository notice](https://github.com/chhoumann/t3-pstack/blob/main/NOTICE.md) lists. Those modifications are (c) 2026 Christian Bager Bach Houmann under the same [MIT license](LICENSE). The [change log](https://github.com/chhoumann/t3-pstack/blob/main/CHANGES.md) records each release.
4 changes: 3 additions & 1 deletion NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ t3-pstack is a port of [pstack](https://github.com/cursor/plugins/tree/main/psta
| `plugins/pstack/skills/{thermos,thermo-nuclear-review,thermo-nuclear-code-quality-review}/`, `plugins/pstack/agents/thermo-nuclear-review-subagent.md`, `plugins/pstack/agents/thermo-nuclear-code-quality-review-subagent.md` | [cursor/plugins/thermos @ 99743e9](https://github.com/cursor/plugins/tree/99743e9c151c8537cbbf1f98bb38f34ef3368453/thermos) | (c) 2026 Cursor | MIT | [LICENSE-thermos](LICENSE-thermos) |
| `tools/sync.mjs`, `tools/generate.mjs`, `tools/validate-skills.mjs`, `tools/plugin.mjs`, `plugins/pstack/skills/reflect/scripts/find-transcript.mjs`, `plugins/pstack/hooks/session-start.sh`, `plugins/pstack/hooks/session-start.ps1`, `plugins/pstack/skills/setup-pstack/scripts/read-sheet.sh`, and the tests that cover them, each modified by t3-pstack | [michael-denyer/pstack-claude](https://github.com/michael-denyer/pstack-claude), as merged into t3-pstack through 1.0.14 | (c) 2026 Michael Denyer | MIT | [LICENSE](LICENSE) |
| Four rules in `plugins/pstack/skills/poteto-mode/SKILL.md` (load a platform's skill before deploying, stop an abandoned agent and confirm it stopped, keep a review gate closed with no independent reviewer, the `todo.md` fallback), the per-delegate worktree rule in `playbooks/feature.md`, the stop-live-agents rule in `playbooks/opening-a-pr.md`, the `--match-head-commit` guard in `playbooks/shipping.md`, and the review-gate, stale-check, and no-checks fixes in `plugins/pstack/skills/poteto-mode/scripts/watch-pr/` with their tests in `verdicts.test.ts`, each reworded or adapted for T3 by t3-pstack | [michael-denyer/pstack-claude](https://github.com/michael-denyer/pstack-claude), pull requests [#95](https://github.com/michael-denyer/pstack-claude/pull/95), [#97](https://github.com/michael-denyer/pstack-claude/pull/97), and [#153](https://github.com/michael-denyer/pstack-claude/pull/153) for watch-pr | (c) 2026 Michael Denyer | MIT | [LICENSE](LICENSE) |
| The ignored-file and reflog-only-commit holds in `plugins/pstack/skills/poteto-mode/scripts/worktree-audit.sh`, ported from JavaScript to bash, and their wording in `playbooks/worktree-cleanup.md`, with the test cases in `tests/worktree-audit.test.mjs`; the plugin icon with its C2PA manifest removed (`plugins/pstack/.claude-plugin/icon.png`, `plugins/pstack/assets/pstack-icon.png`) and `tests/image-metadata.test.mjs` | [michael-denyer/pstack-claude](https://github.com/michael-denyer/pstack-claude), pull requests [#277](https://github.com/michael-denyer/pstack-claude/pull/277) and [#271](https://github.com/michael-denyer/pstack-claude/pull/271) | (c) 2026 Michael Denyer | MIT | [LICENSE](LICENSE) |
| The plain-remove prune step in `plugins/pstack/skills/poteto-mode/playbooks/worktree-cleanup.md` and the playbook check in `tools/generate.mjs`, each adapted by t3-pstack | [sergchil/jutsu @ da94424](https://github.com/sergchil/jutsu/commit/da9442422c72cc99442c1ce3500d2f2485234a31) | (c) 2026 Sergey Chilingaryan | MIT | [LICENSE](LICENSE) |
| `plugins/pstack/skills/poteto-mode/scripts/resolve-codex-transcript` (verbatim) and `resolve-codex-transcript.ts` (modified, see below), `tests/resolve-codex-transcript.test.mjs` (ported from its `resolve-codex-transcript.test.ts`) | [ericlitman/open-pstack @ c5c8e23](https://github.com/ericlitman/open-pstack/tree/c5c8e237c324359a3d1929037da78fe66da3d1ed/plugins/pstack/skills/poteto-mode/scripts), [PR #151](https://github.com/ericlitman/open-pstack/pull/151) | (c) 2026 Eric A. Litman and Donncha O'Toole | MIT | [LICENSE](LICENSE) |

## What changed in the port
Expand All @@ -19,7 +21,7 @@ t3-pstack is a port of [pstack](https://github.com/cursor/plugins/tree/main/psta

- Plugin content lives at `plugins/pstack/`, with a Claude Code manifest (`.claude-plugin/plugin.json`) and a Codex manifest (`.codex-plugin/plugin.json`). The repository root holds both marketplaces (`.claude-plugin/marketplace.json`, `.agents/plugins/marketplace.json`) and the license, notice, readme, and changelog.
- Upstream's skill text is rewritten in place into its T3 form by the substitutions: Cursor's subagent tool, model slugs, model rule, cloud agents, and `/loop` become T3's `delegate_task`, sheet entries, `schedule_task`, and related tools. The `poteto-mode` skill drops upstream's `disable-model-invocation` flag so the session-start hook can invoke it.
- `plugins/pstack/skills/setup-pstack/SKILL.md` is a declared fork that writes the T3 model sheet. The watch-pr settle overlay (`plugins/pstack/skills/poteto-mode/scripts/watch-pr/settle.ts`) is t3-pstack's own, with declared forks at its hook points in upstream's watch-pr. The files that carry Michael Denyer's rules and watch-pr fixes, listed above, are declared forks too.
- `plugins/pstack/skills/setup-pstack/SKILL.md` is a declared fork that writes the T3 model sheet. The watch-pr settle overlay (`plugins/pstack/skills/poteto-mode/scripts/watch-pr/settle.ts`) is t3-pstack's own, with declared forks at its hook points in upstream's watch-pr. The files that carry Michael Denyer's rules and watch-pr fixes, listed above, are declared forks too, as are the worktree audit and the cleanup playbook, which fix [cursor/plugins#449](https://github.com/cursor/plugins/issues/449).
- `plugins/pstack/skills/poteto-mode/scripts/resolve-codex-transcript.ts` is Eric A. Litman's open-pstack resolver, which builds on Donncha O'Toole's candidate, and keeps their copyright. t3-pstack 1.0.13 modified it in seven ways. It finds the index directory as Codex 0.162.1 does, from `sqlite_home` in `config.toml`, else `CODEX_SQLITE_HOME`, else `CODEX_HOME`. It refuses a relative `CODEX_SQLITE_HOME` as `sqlite_home_relative`, since Codex reads one against a working directory the resolver cannot know. It uses the newest `state_<n>.sqlite` that opens with the `threads` schema instead of refusing more than one index or any unreadable one. It opens an index with no `-wal` file as immutable, so it reads a closed WAL index without writing beside it. It reports a live index whose schema it can see only through the `-wal` file, and cannot open that way, as `index_unreadable` instead of `index_missing`. It takes a rollout's first `session_meta` as its owner, so a forked rollout resolves. It stops at that `session_meta` and no longer prints the opening user message's metadata. Prettier formats the file.

## Port-authored files
Expand Down
Loading
Loading