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.15"
"version": "2.0.0-rc.16"
}
]
}
11 changes: 11 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

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.16 - setup opens the verification generators by path, and reflect follows Claude Code's transcript folder rule

Two lines from the port were wrong on Claude Code, and neither came from Lauren's text. After the user says yes, `/setup-pstack`'s steps 7 and 8 told the agent to invoke `/create-verification-skill` or `/create-formal-verification-skill`. Both generators carry Lauren's `disable-model-invocation`, so the Skill tool refuses them: "cannot be used with Skill tool due to disable-model-invocation. Ask the user to run /create-verification-skill themselves". The agent then stops and asks the user to type the command. Eric Litman's open-pstack hit the same conflict in its 0.15.29 sync (issue #234) and dropped the flag in [`614075f`](https://github.com/ericlitman/open-pstack/commit/614075f5abceef0b8d22497bddb13dc55c10872a). In a throwaway Claude Code 2.1.306 home, the yes turn of a real setup run was resampled. Sonnet 5.5 and Haiku 5.5 called the Skill tool, were refused, and stopped in 4 of 4 runs, and a T3 Claude thread on Sonnet 5.5 did the same. Opus 5.5 and Fable 5.1 found the files with `find` and read them. Steps 7 and 8 now link `../create-verification-skill/SKILL.md` or `../create-formal-verification-skill/SKILL.md` from setup-pstack's own file and say to read it and follow it without the Skill tool, the way poteto-mode reaches its leaves. As links, both fail the generator's link check if a generator is renamed. After the change, none of 15 resampled runs across the four models called the Skill tool, and they read the generators by path. A full Sonnet 5.5 run generated both skills and ran them. The generators keep `disable-model-invocation`, so they still never load on their own. setup-pstack is a declared fork, and its entry in `tools/forks.json` now names the change.

Reflect's step 1 said a Claude Code project's transcripts folder is the working directory with each `/` and `.` turned into `-`. Claude Code 2.1.306 takes its own `process.cwd()`, the physical path with symlinks resolved, normalizes it to NFC, and turns every character other than an ASCII letter or digit into `-` (`my_app` becomes `my-app`, and `ø` becomes `-`, as does a decomposed `å`). Past 200 characters it keeps the first 200 and appends `-` and a hash, so a 241-character path became a 207-character folder. With auto memory on, the system prompt names the folder, which hid the bug. With it off, an agent in a workspace named `my_app` followed the old rule, looked under `...-my_app`, and the finder exited 1, so reflect fell back to a digest. The rule in `tools/substitutions.json` and the port's copy now give `node -p 'process.cwd().normalize("NFC").replace(/[^a-zA-Z0-9]/g, "-")'`, run in the directory Claude Code started in, and send a longer result to the folder under `projects/` that starts with its first 200 characters and holds this session's transcript. `pwd` would print the logical `/tmp` path on macOS and a `/c/...` path in Git Bash on Windows, where Claude Code stores `C--...`. Michael Denyer's pstack-claude [#300](https://github.com/michael-denyer/pstack-claude/pull/300) made the same correction in its own port. No other skill, playbook, or script in the port describes or computes the encoding. recall, automate-me, show-me-your-work, and session pickup read T3 threads, and `find-transcript.mjs` takes the folder it is given. The pins stay at Lauren's `88d4751`, where 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.15 | 2.0.0-rc.16 | Source |
| --- | --- | --- | --- |
| `/setup-pstack` after a yes to a generator | Invokes `/create-verification-skill` or `/create-formal-verification-skill`, which the Skill tool refuses on Claude Code. | Reads the generator's `SKILL.md` by its path from setup-pstack's file and follows it. | open-pstack #234 |
| Reflect's `<encoded-cwd>` | The working directory with each `/` and `.` turned into `-`. | The physical path with every character other than an ASCII letter or digit turned into `-`, from a `node -p` command, and the folder that starts with its first 200 characters when it is longer. | pstack-claude #300 |

## 2.0.0-rc.15 - Lauren's `88d4751`: sharpen rewrites the prompt and no longer does the task

t3-pstack moves to Lauren Tan's pstack at cursor/plugins `88d4751` for all three components. Only pstack changed upstream, and its version moves to 0.15.29. `/sharpen` goes back to Lauren's original prompt, written in the user's voice ([pstack #729](https://github.com/cursor/plugins/pull/729)): "I want a deeper version of this task, not a bigger one." Before it rewrites the task, the agent does four things, now a numbered list. It says what a top professional in the field would do that the user isn't asking for, names the rawest material they would start from, names the specific methods and tools they would use, and says what, other than the agent or the user, would show the result is right. It then rewrites the user's prompt to ask for exactly that and does not do the task. Of the last version it keeps only the line that leaves the user's choices open, and its description now reads "Make a task deeper, not bigger, then rewrite the prompt." It keeps Lauren's `disable-model-invocation`, so on Claude Code it runs when the user types `/t3-pstack:sharpen`. On Codex it is `$t3-pstack:sharpen`, and Codex ignores the flag. poteto-help's row for `/sharpen` now says it returns a rewritten prompt and doesn't do the task, and its recipe reads `/sharpen <the prompt you're about to send>`. `bun tools/sync.mjs` updated sharpen, poteto-help, and the recipes cleanly through existing substitutions. The changed lines name no Cursor tool, path, model, or command, so no rule was added, and the 15 declared forks are untouched. #729's version bump, upstream's README row, its two guide pages under `docs/guide/`, and its copies under `harness/pstack/claude-code/` sit outside every synced component. At `88d4751` each component's dry run reports no undeclared fork, no denylist hit, and no substitution that matches nothing. Neither hooks file changes.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ npx -y github:chhoumann/t3-pstack update
npx -y github:chhoumann/t3-pstack doctor
```

`npx -y github:chhoumann/t3-pstack` runs the installer from the latest commit on `main`. That is the rolling channel, the same one each home's marketplace auto-updates from. To run one release's installer, name its tag, as in `npx -y github:chhoumann/t3-pstack#v2.0.0-rc.15 doctor`.
`npx -y github:chhoumann/t3-pstack` runs the installer from the latest commit on `main`. That is the rolling channel, the same one each home's marketplace auto-updates from. To run one release's installer, name its tag, as in `npx -y github:chhoumann/t3-pstack#v2.0.0-rc.16 doctor`.

`install` and `update` are the same command, and a second run changes nothing. With Node 20 or later, it installs or updates the `t3-pstack@t3-pstack` plugin in every Claude Code and Codex config home T3 can run: `~/.claude` and `~/.codex`, `$CLAUDE_CONFIG_DIR` and `$CODEX_HOME`, and the home of each `claudeAgent` and `codex` instance in T3's settings, disabled ones included. Name any other home with `--claude-home <dir>` or `--codex-home <dir>`. Each home's `t3-pstack` marketplace must come from `chhoumann/t3-pstack`, or from `--source <owner/repo|git URL|dir>` on the same run, and a home whose marketplace has another source is left as it is. A local directory needs a path such as `./t3-pstack`, since `owner/repo` always means GitHub. On Codex it also trusts t3-pstack's session-start hook, once its hooks file is the one this release pins. Codex runs a plugin's hook only once it is trusted, and T3's Codex sessions never ask, so without this step the hook never runs. Run `update` after each release.

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.0.0-rc.15
2.0.0-rc.16
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "t3-pstack",
"private": true,
"version": "2.0.0-rc.15",
"version": "2.0.0-rc.16",
"description": "The installer and development tooling for t3-pstack, Lauren Tan's pstack rewritten in place for T3 Code. The plugin itself lives in plugins/pstack.",
"author": {
"name": "Christian Bager Bach Houmann",
Expand Down
2 changes: 1 addition & 1 deletion plugins/pstack/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "t3-pstack",
"displayName": "t3-pstack (pstack for T3 Code)",
"version": "2.0.0-rc.15",
"version": "2.0.0-rc.16",
"description": "pstack for T3 Code: Lauren Tan's pstack with its Cursor mechanics rewritten in place for T3, so subagents, panels, schedules, and PR watches dispatch through T3's orchestration and panels mix Claude, GPT, and Grok.",
"author": {
"name": "Christian Bager Bach Houmann",
Expand Down
2 changes: 1 addition & 1 deletion plugins/pstack/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "t3-pstack",
"version": "2.0.0-rc.15",
"version": "2.0.0-rc.16",
"description": "pstack for T3 Code on a Codex host: Lauren Tan's pstack with its Cursor mechanics rewritten in place for T3, so subagents, panels, schedules, and PR watches dispatch through T3's orchestration.",
"author": {
"name": "Christian Bager Bach Houmann",
Expand Down
2 changes: 1 addition & 1 deletion plugins/pstack/skills/reflect/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
name: reflect
description: Spawn three parallel review subagents over the active transcript, surface learnings, and route each to a concrete edit on an existing skill. Use when the user says reflect.
Expand All @@ -20,7 +20,7 @@
node "<plugin root>/skills/reflect/scripts/find-transcript.mjs" --session "$CLAUDE_CODE_SESSION_ID" "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/projects/<encoded-cwd>" "<opening prompt fragment>"
```

`<plugin root>` is the directory that holds this plugin's `skills/`, and `<encoded-cwd>` is the working directory with each `/` and `.` turned into `-`. With the session ID set, the finder prints this session's own transcript, and exits 1 when it does not exist, because a scan could return a sibling session that shares the opening prompt. Without it, the finder scans the flat, nested, and subagent layouts newest first and prints the first transcript whose opening typed prompt carries the fragment. Do not reimplement the scan by hand.
`<plugin root>` is the directory that holds this plugin's `skills/`, and `<encoded-cwd>` is what `node -p 'process.cwd().normalize("NFC").replace(/[^a-zA-Z0-9]/g, "-")'` prints in the directory Claude Code started in, which is that directory's physical path with every character other than an ASCII letter or digit turned into `-`. If the result is longer than 200 characters, Claude Code keeps the first 200 and appends `-` and a hash, so use the folder under `projects/` whose name starts with those 200 characters and that holds this session's transcript. With the session ID set, the finder prints this session's own transcript, and exits 1 when it does not exist, because a scan could return a sibling session that shares the opening prompt. Without it, the finder scans the flat, nested, and subagent layouts newest first and prints the first transcript whose opening typed prompt carries the fragment. Do not reimplement the scan by hand.

On Codex, pass this thread's ID, which Codex exports as `CODEX_THREAD_ID`, to the resolver, and never search by chat title or time:

Expand Down
4 changes: 2 additions & 2 deletions plugins/pstack/skills/setup-pstack/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
name: setup-pstack
description: Configure which T3 provider and model pstack uses per role and at what reasoning budget. Detects the models T3 can run and writes the model sheet that overrides the skill defaults. Use for /setup-pstack, "configure pstack models", "pstack budget", or changing pstack's model choices.
Expand Down Expand Up @@ -70,8 +70,8 @@

### 7. Offer a verification skill (optional)

Check whether the project has a way to drive the real app for proof (a `verify-*` skill, or an existing harness). If not, offer once: "want a project-local verification skill, so agents can drive the app the way a user does and prove changes work? I can generate one with /create-verification-skill." On yes, invoke `/create-verification-skill` (resolves wherever pstack is installed: workspace, user, or plugin). On no, move on without pushing.
Check whether the project has a way to drive the real app for proof (a `verify-*` skill, or an existing harness). If not, offer once: "want a project-local verification skill, so agents can drive the app the way a user does and prove changes work? I can generate one with /create-verification-skill." On yes, read [`../create-verification-skill/SKILL.md`](../create-verification-skill/SKILL.md) from this file and follow it. Do not call the Skill tool for it, since that tool refuses a skill only the user may invoke. On no, move on without pushing.

### 8. Offer a formal verification skill (optional)

Check whether the project already has a formal verification skill (a project skill that runs a model checker, a proof, or another verifier against the code). If not, offer once: "want a formal verification skill, so agents can prove a key property of your code holds in every case in scope, not only the cases tests reach? I can generate one with /create-formal-verification-skill." On yes, invoke `/create-formal-verification-skill` (resolves wherever pstack is installed: workspace, user, or plugin). On no, move on without pushing.
Check whether the project already has a formal verification skill (a project skill that runs a model checker, a proof, or another verifier against the code). If not, offer once: "want a formal verification skill, so agents can prove a key property of your code holds in every case in scope, not only the cases tests reach? I can generate one with /create-formal-verification-skill." On yes, read [`../create-formal-verification-skill/SKILL.md`](../create-formal-verification-skill/SKILL.md) from this file and follow it. Do not call the Skill tool for it, since that tool refuses a skill only the user may invoke. On no, move on without pushing.
2 changes: 1 addition & 1 deletion tools/forks.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
},
"plugins/pstack/skills/setup-pstack/SKILL.md": {
"kind": "port-feature",
"why": "Writes the T3 model sheet from orchestrator_capabilities targets and checks it with t3-sheet.mjs, in place of Cursor's always-applied .mdc rule built from model slugs.",
"why": "Writes the T3 model sheet from orchestrator_capabilities targets and checks it with t3-sheet.mjs, in place of Cursor's always-applied .mdc rule built from model slugs. Steps 7 and 8 open the generator's SKILL.md by its path from this file instead of invoking it, since on Claude Code the Skill tool refuses a skill with disable-model-invocation, a conflict Eric Litman's open-pstack recorded in its 0.15.29 sync (#234).",
"since": "2.0.0-rc.1",
"upstream": "not-proposed"
}
Expand Down
2 changes: 1 addition & 1 deletion tools/substitutions.json
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@
},
{
"pattern": "```bash\nls -t <agent-transcripts>/*.jsonl <agent-transcripts>/*/*.jsonl <agent-transcripts>/*/subagents/*.jsonl 2>/dev/null | head -10\n```\n\nThat covers the legacy flat (`<id>.jsonl`), current nested (`<id>/<id>.jsonl`), and subagent (`<parent>/subagents/<child>.jsonl`) layouts. For each candidate, read the first JSONL line. Take the file whose `message.content[0].text` contains the conversation's opening user prompt. If none matches, pass a tight digest of the session instead.",
"replacement": "On Claude Code, run the finder with this session's ID, this project's transcripts directory, and a fragment of the conversation's opening user prompt:\n\n```bash\nnode \"<plugin root>/skills/reflect/scripts/find-transcript.mjs\" --session \"$CLAUDE_CODE_SESSION_ID\" \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/projects/<encoded-cwd>\" \"<opening prompt fragment>\"\n```\n\n`<plugin root>` is the directory that holds this plugin's `skills/`, and `<encoded-cwd>` is the working directory with each `/` and `.` turned into `-`. With the session ID set, the finder prints this session's own transcript, and exits 1 when it does not exist, because a scan could return a sibling session that shares the opening prompt. Without it, the finder scans the flat, nested, and subagent layouts newest first and prints the first transcript whose opening typed prompt carries the fragment. Do not reimplement the scan by hand.\n\nOn Codex, pass this thread's ID, which Codex exports as `CODEX_THREAD_ID`, to the resolver, and never search by chat title or time:\n\n```bash\n\"<plugin root>/skills/poteto-mode/scripts/resolve-codex-transcript\" \"$CODEX_THREAD_ID\"\n```\n\nOn success it exits 0 and prints JSON whose `path` is the transcript. If either command exits non-zero, pass a tight digest of the session instead.",
"replacement": "On Claude Code, run the finder with this session's ID, this project's transcripts directory, and a fragment of the conversation's opening user prompt:\n\n```bash\nnode \"<plugin root>/skills/reflect/scripts/find-transcript.mjs\" --session \"$CLAUDE_CODE_SESSION_ID\" \"${CLAUDE_CONFIG_DIR:-$HOME/.claude}/projects/<encoded-cwd>\" \"<opening prompt fragment>\"\n```\n\n`<plugin root>` is the directory that holds this plugin's `skills/`, and `<encoded-cwd>` is what `node -p 'process.cwd().normalize(\"NFC\").replace(/[^a-zA-Z0-9]/g, \"-\")'` prints in the directory Claude Code started in, which is that directory's physical path with every character other than an ASCII letter or digit turned into `-`. If the result is longer than 200 characters, Claude Code keeps the first 200 and appends `-` and a hash, so use the folder under `projects/` whose name starts with those 200 characters and that holds this session's transcript. With the session ID set, the finder prints this session's own transcript, and exits 1 when it does not exist, because a scan could return a sibling session that shares the opening prompt. Without it, the finder scans the flat, nested, and subagent layouts newest first and prints the first transcript whose opening typed prompt carries the fragment. Do not reimplement the scan by hand.\n\nOn Codex, pass this thread's ID, which Codex exports as `CODEX_THREAD_ID`, to the resolver, and never search by chat title or time:\n\n```bash\n\"<plugin root>/skills/poteto-mode/scripts/resolve-codex-transcript\" \"$CODEX_THREAD_ID\"\n```\n\nOn success it exits 0 and prints JSON whose `path` is the transcript. If either command exits non-zero, pass a tight digest of the session instead.",
"rationale": "Transcripts (t3-pstack 1.0.13: find-transcript.mjs on Claude Code, resolve-codex-transcript on Codex)"
},
{
Expand Down
Loading