pi-t3-bridge 0.6.0 → 0.7.1
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.
- package/CHANGELOG.md +41 -0
- package/README.md +144 -77
- package/package.json +5 -5
- package/src/amplike/btw.ts +5 -7
- package/src/amplike/handoff.ts +33 -23
- package/src/amplike/package.ts +37 -24
- package/src/amplike/selection.ts +26 -14
- package/src/bridge/accounts.ts +66 -49
- package/src/bridge/ask.ts +73 -93
- package/src/bridge/bash-timeout.ts +15 -8
- package/src/bridge/config.ts +29 -26
- package/src/bridge/plan.ts +19 -11
- package/src/bridge/resume.ts +17 -11
- package/src/bridge/state.ts +54 -34
- package/src/bridge/steer-judge.ts +130 -96
- package/src/bridge/steer-transcript.ts +4 -3
- package/src/bridge/steer.ts +16 -10
- package/src/bridge/t3-json.ts +14 -19
- package/src/bridge/tasks.ts +39 -31
- package/src/bridge/thread.ts +5 -6
- package/src/bridge/transcript.ts +11 -8
- package/src/pstack/brief.ts +4 -3
- package/src/pstack/child.ts +45 -32
- package/src/pstack/models.ts +138 -106
- package/src/pstack/overlay.ts +18 -20
- package/src/pstack/results.ts +4 -7
- package/src/pstack/sandbox.ts +12 -8
- package/pstack/skills/statechart/scripts/node_modules/.package-lock.json +0 -46
- package/pstack/skills/statechart/scripts/node_modules/fast-check/LICENSE +0 -21
- package/pstack/skills/statechart/scripts/node_modules/fast-check/README.md +0 -263
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/fast-check.js +0 -12147
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/package.json +0 -3
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/fast-check.js +0 -12011
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +0 -13
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/types57/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/package.json +0 -94
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/LICENSE +0 -21
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/README.md +0 -168
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +0 -14
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformBigInt.js +0 -38
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat32.js +0 -18
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat64.js +0 -22
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformInt.js +0 -134
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +0 -14
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +0 -37
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +0 -17
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +0 -21
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +0 -133
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/congruential32.js +0 -44
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/mersenne.js +0 -90
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +0 -80
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +0 -78
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/package.json +0 -3
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +0 -16
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +0 -2
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/generateN.js +0 -8
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/purify.d.ts +0 -12
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/purify.js +0 -9
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/skipN.js +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/congruential32.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/congruential32.js +0 -46
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/mersenne.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/mersenne.js +0 -92
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +0 -82
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xorshift128plus.js +0 -80
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +0 -16
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +0 -2
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/generateN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/generateN.js +0 -9
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/purify.d.ts +0 -12
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/purify.js +0 -10
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/skipN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/skipN.js +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/package.json +0 -133
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Change log
|
|
2
|
+
|
|
3
|
+
## 0.7.1, 4 November 2026
|
|
4
|
+
|
|
5
|
+
Version 0.7.1 changes only the documentation. The README now covers all four extensions and the pi-amplike adapter, and the package now ships this change log.
|
|
6
|
+
|
|
7
|
+
## 0.7.0, 4 November 2026
|
|
8
|
+
|
|
9
|
+
Version 0.7.0 builds and checks every schema with `@earendil-works/pi-schema` instead of `typebox`, because Pi 1.5.0 moved its own schemas and tool checks to pi-schema. The package now lists pi-schema as a dependency, and it no longer needs `typebox`.
|
|
10
|
+
|
|
11
|
+
The behavior stays the same for a person who uses the package. A schema that reads data from T3, a settings file, or a model still accepts fields it doesn't know, as it did with `typebox`. Tools now send a list of allowed words to the model as `enum` instead of `anyOf`, and the model can send the same values as before.
|
|
12
|
+
|
|
13
|
+
## 0.6.0, 4 November 2026
|
|
14
|
+
|
|
15
|
+
Version 0.6.0 adds `amplike.ts`, which loads pi-amplike's extensions and changes the parts that T3 can't show. In a T3 thread, amplike's `subagent` tool is off, so subagent work goes through T3's `delegate_task`. `/btw` starts a `delegate_task` child, and `/handoff` and the `handoff` tool start a new T3 thread with a summary and the parent session file. `/mode` sends each model change to T3, so T3's model picker shows the same model.
|
|
16
|
+
|
|
17
|
+
To use the adapter, change `"npm:pi-amplike"` in `~/.pi/agent/settings.json` to `{"source":"npm:pi-amplike","extensions":[]}`. Outside T3, amplike works as before.
|
|
18
|
+
|
|
19
|
+
## 0.5.0, 4 November 2026
|
|
20
|
+
|
|
21
|
+
Version 0.5.0 lets the stop checks use any chat model when Jev isn't available. You can name the model with `classifierModel` in `~/.config/pi-t3/config.json`, and without the setting the bridge uses Jev when you have access and the session model when you don't. The release also updates pstack to t3-pstack 2.2.1, and it pins T3 to 0.1.7.
|
|
22
|
+
|
|
23
|
+
## 0.4.0, 2 November 2026
|
|
24
|
+
|
|
25
|
+
Version 0.4.0 adds a second set of skills to the package, and the package now serves the pstack skills in a new way. The sections below describe each change and the benefit of the change.
|
|
26
|
+
|
|
27
|
+
### Skills from tstack
|
|
28
|
+
|
|
29
|
+
The package now includes the skills from tstack, a public set of skills by Theo Browne. The nine skills are babysit-pr, council, file-pr, full-send, full-stop, leaving-pr-comments, modernize, sol-loop, and takeover, and a new file named tstack.ts serves the skills to Pi. The tstack.ts file works on its own, so the skills stay available when a person turns the pstack part of the package off.
|
|
30
|
+
|
|
31
|
+
The benefit is that a person gets the skills with the package and does not copy skill folders into a personal skills folder by hand. Updates to the skills arrive with package updates, so a person does not keep a separate copy up to date.
|
|
32
|
+
|
|
33
|
+
### How the package serves pstack
|
|
34
|
+
|
|
35
|
+
The pstack folder now holds the exact text from the pstack project, and a new folder named overlay holds every change that Pi needs. At start, the package copies pstack into a folder in the state directory and applies the changes from overlay to the copy, and Pi reads the copy.
|
|
36
|
+
|
|
37
|
+
The benefit is that an update from the pstack project needs no work to combine the update with the changes for Pi. A maintainer takes the new text as it comes, and the test run fails with the name of the file when a change in overlay no longer matches the new text.
|
|
38
|
+
|
|
39
|
+
### What a person needs to do
|
|
40
|
+
|
|
41
|
+
A person who copied the tstack skills into a personal skills folder can delete the copies, because the package now serves the same skills and two copies of one skill can conflict. A person who did not copy the skills needs to do nothing, and the pstack skills work as before.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-t3-bridge
|
|
2
2
|
|
|
3
|
-
pi-t3-bridge is a [Pi](https://pi.dev) package that lets Pi
|
|
3
|
+
pi-t3-bridge is a [Pi](https://pi.dev) package that lets Pi run as an agent inside [T3 Code](https://github.com/pingdotgg/t3code). It also ships the pstack and tstack skill sets, and it adapts [pi-amplike](https://github.com/pasky/pi-amplike) so that amplike's commands work in a T3 thread.
|
|
4
4
|
|
|
5
5
|
```mermaid
|
|
6
6
|
flowchart LR
|
|
@@ -8,12 +8,17 @@ flowchart LR
|
|
|
8
8
|
T3 -->|runs a thread| Pi[Pi agent]
|
|
9
9
|
subgraph pkg [pi-t3-bridge]
|
|
10
10
|
Bridge[bridge.ts<br/>T3 tools, cards, limits]
|
|
11
|
-
Pstack[pstack.ts<br/>skills
|
|
11
|
+
Pstack[pstack.ts<br/>pstack skills, model routing]
|
|
12
|
+
Tstack[tstack.ts<br/>tstack skills]
|
|
13
|
+
Amplike[amplike.ts<br/>pi-amplike in T3]
|
|
12
14
|
end
|
|
13
15
|
Pi --> Bridge
|
|
14
16
|
Pi --> Pstack
|
|
17
|
+
Pi --> Tstack
|
|
18
|
+
Pi --> Amplike
|
|
15
19
|
Bridge -->|MCP| T3
|
|
16
20
|
Pstack -->|delegate_task| T3
|
|
21
|
+
Amplike -->|t3_thread_launch, delegate_task| T3
|
|
17
22
|
T3 -->|child threads| Children[Claude, GPT, and other models]
|
|
18
23
|
```
|
|
19
24
|
|
|
@@ -25,9 +30,9 @@ You need the following programs:
|
|
|
25
30
|
- Pi 1.4.0 or later
|
|
26
31
|
- T3 Code, if you want to run Pi threads inside T3 or call T3 tools from Pi
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
A delegated child runs its shell commands in a sandbox, which is `sandbox-exec` on macOS and `bwrap` (bubblewrap) on Linux and WSL2. On Linux you need the `bubblewrap` package and unprivileged user namespaces. The Ubuntu `bubblewrap` package ships an AppArmor profile that lets `bwrap` run (checked on 26.04). If AppArmor still blocks `bwrap`, run `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0`.
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
Native Windows and WSL1 have no sandbox. Where no sandbox can run, the bridge blocks a child's shell commands, unless you set `childSandbox` to `"off"` in the settings file.
|
|
31
36
|
|
|
32
37
|
## Install
|
|
33
38
|
|
|
@@ -37,45 +42,42 @@ Install the package with Pi:
|
|
|
37
42
|
pi install npm:pi-t3-bridge
|
|
38
43
|
```
|
|
39
44
|
|
|
40
|
-
Pi loads
|
|
45
|
+
Pi loads every extension in the package on the next start. To try the package for one session without saving it to your settings, run `pi -e npm:pi-t3-bridge`.
|
|
41
46
|
|
|
42
47
|
## What is in the package
|
|
43
48
|
|
|
44
|
-
The package has
|
|
49
|
+
The package has four Pi extensions, and you can turn off any of them. None of the extensions needs another one to be loaded, although `pstack.ts` and `amplike.ts` reuse code from `src/bridge`.
|
|
45
50
|
|
|
46
51
|
```text
|
|
47
52
|
pi-t3-bridge/
|
|
48
|
-
├── bridge.ts
|
|
49
|
-
├── pstack.ts
|
|
53
|
+
├── bridge.ts # connects Pi to T3 Code
|
|
54
|
+
├── pstack.ts # serves pstack skills and picks models for subagents
|
|
55
|
+
├── tstack.ts # serves tstack skills
|
|
56
|
+
├── amplike.ts # loads pi-amplike and adapts it for T3 threads
|
|
50
57
|
├── src/
|
|
51
|
-
│ ├── bridge/
|
|
52
|
-
│
|
|
53
|
-
└──
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
│ ├── bridge/ # code for bridge.ts
|
|
59
|
+
│ ├── pstack/ # code for pstack.ts
|
|
60
|
+
│ └── amplike/ # code for amplike.ts
|
|
61
|
+
├── pstack/ # upstream pstack skills, agents, and model defaults
|
|
62
|
+
├── overlay/ # the changes Pi needs on top of pstack/
|
|
63
|
+
└── tstack/ # Theo Browne's tstack skills
|
|
57
64
|
```
|
|
58
65
|
|
|
59
|
-
To load only
|
|
66
|
+
To load only some extensions, list the package in `~/.pi/agent/settings.json` in its object form:
|
|
60
67
|
|
|
61
68
|
```json
|
|
62
69
|
{
|
|
63
|
-
"packages": [
|
|
64
|
-
{
|
|
65
|
-
"source": "npm:pi-t3-bridge",
|
|
66
|
-
"extensions": ["bridge.ts"]
|
|
67
|
-
}
|
|
68
|
-
]
|
|
70
|
+
"packages": [{ "source": "npm:pi-t3-bridge", "extensions": ["bridge.ts"] }]
|
|
69
71
|
}
|
|
70
72
|
```
|
|
71
73
|
|
|
72
74
|
## The bridge extension
|
|
73
75
|
|
|
74
|
-
The bridge gives Pi the tools and commands that T3 Code expects, and it shows them as cards in the T3 chat. When another installed package already registers a tool with the same name,
|
|
76
|
+
The bridge gives Pi the tools and commands that T3 Code expects, and it shows them as cards in the T3 chat. When another installed package already registers a tool with the same name, e.g. `ask` from pi-ask, the bridge keeps the other package's tool and tells you once that its own copy is off.
|
|
75
77
|
|
|
76
78
|
| Name | Kind | What it does |
|
|
77
79
|
| --- | --- | --- |
|
|
78
|
-
| `tasks` | tool |
|
|
80
|
+
| `tasks` | tool | Shows the task list for the run as a card in the chat. |
|
|
79
81
|
| `plan` | tool | Shows a plan card with Approve, Revise, and Cancel buttons. |
|
|
80
82
|
| `ask` | tool | Asks you one or more questions as cards and waits for your answers. |
|
|
81
83
|
| `transcript` | tool | Returns the session file and session ID, for workflows that read the transcript. |
|
|
@@ -86,7 +88,7 @@ The bridge gives Pi the tools and commands that T3 Code expects, and it shows th
|
|
|
86
88
|
|
|
87
89
|
### Plan mode
|
|
88
90
|
|
|
89
|
-
When T3 is in Plan mode, or when a plan
|
|
91
|
+
When T3 is in Plan mode, or when a plan card waits for your answer, the bridge blocks every tool that can change files. Read-only tools still run, so the agent can read files while you decide.
|
|
90
92
|
|
|
91
93
|
```mermaid
|
|
92
94
|
stateDiagram-v2
|
|
@@ -101,9 +103,9 @@ stateDiagram-v2
|
|
|
101
103
|
approved --> [*]: write tools run again
|
|
102
104
|
```
|
|
103
105
|
|
|
104
|
-
### Calls to T3 from
|
|
106
|
+
### Calls to T3 from a terminal
|
|
105
107
|
|
|
106
|
-
When you run Pi in a terminal instead of
|
|
108
|
+
When you run Pi in a terminal instead of a T3 thread, the bridge connects Pi to T3's MCP server, which is the endpoint where T3 Code serves its tools. You can then start threads, send messages to them, and wait on them from the terminal, and the status bar shows whether the connection works.
|
|
107
109
|
|
|
108
110
|
```text
|
|
109
111
|
on(session start)
|
|
@@ -120,7 +122,7 @@ on(session start)
|
|
|
120
122
|
|
|
121
123
|
### Usage limits and resume
|
|
122
124
|
|
|
123
|
-
The bridge
|
|
125
|
+
The bridge records which model families are out of usage, and every Pi session on the machine reads the same record. When a child fails with a usage limit, the bridge marks the family as out until its reset time, so pstack sends new work to another family.
|
|
124
126
|
|
|
125
127
|
```mermaid
|
|
126
128
|
sequenceDiagram
|
|
@@ -136,76 +138,102 @@ sequenceDiagram
|
|
|
136
138
|
Parent->>T3: delegate_task (next family)
|
|
137
139
|
```
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
The main thread's own account can also run out, and then the agent can't call any tool. When the main thread's account runs out, the bridge asks T3 to post a resume message into the thread just after the reset time.
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
### Shell time limit
|
|
142
144
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
When a run is about to stop, the bridge asks a classifier how the run ended. It picks the classifier in this order:
|
|
145
|
+
The bridge stops any shell command after 300 seconds, in the main thread and in children, so a test suite that hangs stops the chat for 5 minutes at most. A command can ask for a shorter timeout but not a longer one, and you can change the limit with `bashTimeoutSeconds` in the settings file.
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
2. `typesafe/jev-latest`, when it is in your Pi model catalog and you have access to it.
|
|
149
|
-
3. The model of the current session.
|
|
147
|
+
### Stop checks
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- Stuck in a loop
|
|
154
|
-
- Doesn't know when to stop
|
|
155
|
-
- Wandered off
|
|
156
|
-
- Broke the brief, and says one thing but does another
|
|
149
|
+
When a run is about to stop, the bridge asks a classifier model how the run ended, and it gives the agent one more turn when the agent gave up partway. The checks come from [pi-mast-steer](https://github.com/dbreunig/pi-mast-steer).
|
|
157
150
|
|
|
158
151
|
```text
|
|
159
152
|
on(run about to stop)
|
|
160
153
|
ask the classifier how the run ended
|
|
161
154
|
if the classifier is down or takes more than 5 seconds
|
|
162
155
|
let the run stop
|
|
163
|
-
if the agent gave up partway and fewer than 2 notes were sent for
|
|
156
|
+
if the agent gave up partway and fewer than 2 notes were sent for the current prompt
|
|
164
157
|
add a note
|
|
165
158
|
continue for one more turn
|
|
159
|
+
|
|
160
|
+
every 3 turns
|
|
161
|
+
ask the classifier whether the agent shows a known failure
|
|
162
|
+
if one is likely
|
|
163
|
+
add a note that names it
|
|
166
164
|
```
|
|
167
165
|
|
|
168
|
-
The
|
|
166
|
+
The known failures come from the MAST list of agent failures:
|
|
167
|
+
|
|
168
|
+
- Stuck in a loop
|
|
169
|
+
- Doesn't know when to stop
|
|
170
|
+
- Wandered off
|
|
171
|
+
- Broke the brief, or says one thing and does another
|
|
169
172
|
|
|
170
|
-
|
|
173
|
+
The bridge picks the classifier in the order below, and it doesn't fall back to the next one when the chosen one fails.
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
pick classifier
|
|
177
|
+
if classifierModel is set in the settings file
|
|
178
|
+
use that chat model, or report an error if it's not in the catalog or has no auth
|
|
179
|
+
else if typesafe/jev-latest is in your Pi model catalog and you have access
|
|
180
|
+
use Jev
|
|
181
|
+
else
|
|
182
|
+
use the session model
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
A chat model answers the same questions through one tool call. Its probabilities are its own guesses and not calibrated like Jev's, and the thresholds were fitted on Jev, so a chat model may add notes more or less often. A chat model also costs tokens on your account, with one call per stop check and one every 3 turns. Set `steer` to `"shadow"` to log the verdicts without changing the session, or to `"off"` to turn the checks off.
|
|
171
186
|
|
|
172
187
|
## The pstack extension
|
|
173
188
|
|
|
174
|
-
The pstack extension adds the pstack skills to Pi's skill
|
|
189
|
+
The pstack extension adds the pstack skills to Pi's skill list, and it adds a note to each prompt that tells the agent when to enter `poteto-mode`. The `poteto-mode` skill picks the workflow that fits your goal, e.g. a bug fix, a feature, a design review, or a PR watch.
|
|
190
|
+
|
|
191
|
+
The skills come from [pstack](https://github.com/cursor/plugins/tree/main/pstack) by way of [t3-pstack](https://github.com/chhoumann/t3-pstack). The `pstack/` folder holds the upstream text unchanged, and `overlay/` holds the changes Pi needs.
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
on(Pi start)
|
|
195
|
+
copy pstack/ to ~/.local/state/pi-t3/pstack-overlay/<hash>/
|
|
196
|
+
apply each change in overlay/ to the copy
|
|
197
|
+
serve the skills from the copy
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
When a change in `overlay/` no longer matches a new upstream text, the test run fails and names the file.
|
|
175
201
|
|
|
176
202
|
### Model routing
|
|
177
203
|
|
|
178
|
-
The `pstack_model` tool picks the model for each subagent. The agent passes a role, a job type, and a size, and the tool returns a target
|
|
204
|
+
The `pstack_model` tool picks the model for each subagent. The agent passes a role, a job type, and a size, and the tool returns a target that the agent passes to T3's `delegate_task`.
|
|
179
205
|
|
|
180
206
|
```text
|
|
181
207
|
pstack_model(role, job, size)
|
|
208
|
+
if size is L
|
|
209
|
+
refuse, so the agent splits the job
|
|
182
210
|
if the model sheet names a model for the role
|
|
183
|
-
use
|
|
211
|
+
use the model from the sheet
|
|
184
212
|
else
|
|
185
213
|
look up the job and size in the routing table
|
|
186
|
-
if
|
|
214
|
+
if the model's family is out of usage
|
|
187
215
|
use the same tier in the next family
|
|
188
216
|
(GPT takes only size S work)
|
|
189
217
|
return the target for delegate_task
|
|
190
218
|
```
|
|
191
219
|
|
|
192
|
-
The routing table in `pstack/models.json
|
|
220
|
+
The routing table lives in `pstack/models.json`. Size S is a job of 30 minutes or less that touches 5 files or fewer, and size M is a job of 90 minutes or less that touches 15 files or fewer.
|
|
193
221
|
|
|
194
222
|
| Job | Size S | Size M |
|
|
195
223
|
| --- | --- | --- |
|
|
196
|
-
| `mechanical`,
|
|
224
|
+
| `mechanical`, e.g. a lint fix or rename | Haiku 5.5, low | Sonnet 5.5, medium |
|
|
197
225
|
| `check`, which runs given commands | GPT 6 Luna, low | Haiku 5.5, medium |
|
|
198
226
|
| `research`, which writes one notes file | Muse Spark 1.3, medium | Muse Wonder 1.0, medium |
|
|
199
227
|
| `implement`, one unit with named tests | GPT 6.1 Sol, medium | Sonnet 5.5, high |
|
|
200
|
-
| `hard`,
|
|
228
|
+
| `hard`, e.g. concurrency or a bug with an unknown cause | Opus 5.5, high | Opus 5.5, high |
|
|
201
229
|
| `review` panel | Opus 5.5, Muse Wonder Full 1.0, and GPT 6.1 Sol, all high | same |
|
|
202
230
|
| `design` panel | Opus 5.5, Muse Wonder Full 1.0, and GPT 6 Astra, all high | same |
|
|
203
231
|
|
|
204
|
-
|
|
232
|
+
To choose your own models, run the `setup-pstack` skill, which writes a model sheet at `~/.config/pi-t3-bridge/models.md`. A line of `session hook: off` in the sheet stops the note about `poteto-mode` on each prompt.
|
|
205
233
|
|
|
206
234
|
### Limits for delegated children
|
|
207
235
|
|
|
208
|
-
When the first message of a session is a complete pstack brief, the extension treats the session as a delegated child and holds it to the brief. The child can't lift the limits through anything it writes.
|
|
236
|
+
When the first message of a session is a complete pstack brief, the extension treats the session as a delegated child and holds it to the limits in the brief. The child can't lift the limits through anything it writes.
|
|
209
237
|
|
|
210
238
|
```mermaid
|
|
211
239
|
sequenceDiagram
|
|
@@ -223,29 +251,67 @@ sequenceDiagram
|
|
|
223
251
|
Note over Parent: the extension adds the report from the ledger
|
|
224
252
|
```
|
|
225
253
|
|
|
226
|
-
##
|
|
254
|
+
## The tstack extension
|
|
227
255
|
|
|
228
|
-
|
|
256
|
+
The tstack extension serves Theo Browne's tstack skills from `tstack/skills`, which are babysit-pr, council, file-pr, full-send, full-stop, leaving-pr-comments, modernize, sol-loop, and takeover. It imports no other code from the package, so the skills stay available when you turn the other extensions off.
|
|
229
257
|
|
|
230
|
-
|
|
231
|
-
|
|
258
|
+
## pi-amplike in T3 threads
|
|
259
|
+
|
|
260
|
+
pi-amplike adds handoff, `/btw`, subagents, and prompt modes to Pi, but T3 can't show most of them. T3 shows Pi's `notify`, `select`, `confirm`, `input`, and `editor` calls, and it drops widgets, status lines, custom UI, and key presses. T3 also resumes a thread from the session file it first recorded, so a handoff that moves Pi to a new session file breaks the thread.
|
|
261
|
+
|
|
262
|
+
To use the adapter, keep pi-amplike installed and turn off its own extensions in `~/.pi/agent/settings.json`. The adapter then loads amplike's extension files itself.
|
|
263
|
+
|
|
264
|
+
```diff
|
|
265
|
+
"packages": [
|
|
266
|
+
"npm:pi-t3-bridge",
|
|
267
|
+
- "npm:pi-amplike"
|
|
268
|
+
+ { "source": "npm:pi-amplike", "extensions": [] }
|
|
269
|
+
]
|
|
232
270
|
```
|
|
233
271
|
|
|
234
|
-
|
|
272
|
+
```text
|
|
273
|
+
on(Pi start)
|
|
274
|
+
find pi-amplike with Pi's package manager
|
|
275
|
+
if amplike still loads its own extensions
|
|
276
|
+
do nothing, and in a T3 thread show a notice with the settings change
|
|
277
|
+
else if Pi runs inside a T3 thread
|
|
278
|
+
load amplike's extensions with the T3 changes below
|
|
279
|
+
else
|
|
280
|
+
load amplike's extensions unchanged
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
In a T3 thread, the adapter changes the following parts of amplike:
|
|
235
284
|
|
|
236
285
|
| amplike | In a T3 thread |
|
|
237
286
|
| --- | --- |
|
|
238
|
-
| `subagent` tool |
|
|
239
|
-
| `/btw <prompt>` | Starts a `delegate_task` child that reads
|
|
240
|
-
| `handoff` tool and `/handoff <goal>` | Writes a summary with the session model, then starts a new T3 thread
|
|
241
|
-
| `/mode` | Works as in the terminal
|
|
242
|
-
| Shortcuts |
|
|
287
|
+
| `subagent` tool | The adapter turns it off, so subagents run through T3's `delegate_task` and show up in T3. |
|
|
288
|
+
| `/btw <prompt>` | Starts a `delegate_task` child that reads the parent thread's session with `session_query`. The child's answer wakes the parent thread. |
|
|
289
|
+
| `handoff` tool and `/handoff <goal>` | Writes a summary with the session model, then starts a new T3 thread. The current thread keeps its own session file. |
|
|
290
|
+
| `/mode` | Works as in the terminal, and sends each model and thinking change to T3, so T3's model picker shows the same model. |
|
|
291
|
+
| Shortcuts | The adapter turns them off, because T3 sends Pi no key presses. |
|
|
292
|
+
|
|
293
|
+
`session_query`, `/permissions`, and amplike's skills work unchanged. The diagram below shows the three commands that talk to T3.
|
|
243
294
|
|
|
244
|
-
|
|
295
|
+
```mermaid
|
|
296
|
+
sequenceDiagram
|
|
297
|
+
participant You
|
|
298
|
+
participant Pi as Pi (amplike.ts)
|
|
299
|
+
participant T3
|
|
300
|
+
You->>Pi: /handoff fix the failing tests
|
|
301
|
+
Pi->>Pi: summarize the chat with the session model
|
|
302
|
+
Pi->>T3: t3_thread_launch(goal, summary, parent session file)
|
|
303
|
+
T3-->>You: link to the new thread
|
|
304
|
+
You->>Pi: /btw which file holds the parser?
|
|
305
|
+
Pi->>T3: delegate_task(question, parent session file)
|
|
306
|
+
T3-->>Pi: child's answer wakes the thread
|
|
307
|
+
You->>Pi: /mode rush
|
|
308
|
+
Pi->>Pi: set model and thinking level
|
|
309
|
+
Pi->>T3: t3_thread_configure(modelSelection)
|
|
310
|
+
```
|
|
245
311
|
|
|
246
|
-
##
|
|
312
|
+
## Settings
|
|
247
313
|
|
|
248
|
-
The bridge reads one JSON file per machine, at `~/.config/pi-t3/config.json`. Every key is optional. The bridge reads the file again on each prompt, so an edit applies on the next prompt. When
|
|
314
|
+
The bridge reads one JSON file per machine, at `~/.config/pi-t3/config.json`. Every key is optional. The bridge reads the file again on each prompt, so an edit applies on the next prompt. When a value is invalid, only the invalid key falls back to its default, and the bridge tells you once.
|
|
249
315
|
|
|
250
316
|
```json
|
|
251
317
|
{
|
|
@@ -260,12 +326,12 @@ The bridge reads one JSON file per machine, at `~/.config/pi-t3/config.json`. Ev
|
|
|
260
326
|
| Key | Default | Meaning |
|
|
261
327
|
| --- | --- | --- |
|
|
262
328
|
| `bashTimeoutSeconds` | `300` | The longest a shell command can run, in seconds. |
|
|
263
|
-
| `childSandbox` | `"on"` |
|
|
264
|
-
| `classifierModel` | unset |
|
|
265
|
-
| `mcpUrl` | `http://127.0.0.1:3773/mcp` | The T3 MCP endpoint to use
|
|
329
|
+
| `childSandbox` | `"on"` | With `"on"`, a child's `bash` is blocked when no sandbox can run. With `"off"`, commands run with no sandbox on every platform, and the child's report says `SANDBOX: off`. |
|
|
330
|
+
| `classifierModel` | unset | The chat model that runs the stop checks, as `"provider/modelId"`. The model ID may contain more slashes. |
|
|
331
|
+
| `mcpUrl` | `http://127.0.0.1:3773/mcp` | The T3 MCP endpoint to use from a terminal. |
|
|
266
332
|
| `steer` | `"on"` | The stop checks, as `"on"`, `"shadow"`, or `"off"`. |
|
|
267
333
|
|
|
268
|
-
The package writes its files in the
|
|
334
|
+
The package writes its files in the places below. When `XDG_CONFIG_HOME` or `XDG_STATE_HOME` is set, the folder it names replaces `~/.config` or `~/.local/state`.
|
|
269
335
|
|
|
270
336
|
```text
|
|
271
337
|
~/.config/
|
|
@@ -273,19 +339,20 @@ The package writes its files in the following places. When `XDG_CONFIG_HOME` or
|
|
|
273
339
|
└── pi-t3-bridge/models.md # model sheet, written by setup-pstack
|
|
274
340
|
~/.local/state/pi-t3/
|
|
275
341
|
├── accounts.json # model families that are out of usage
|
|
276
|
-
├── ledger.jsonl # one line per delegated brief
|
|
277
|
-
|
|
342
|
+
├── ledger.jsonl # one line per delegated brief, with cost and report
|
|
343
|
+
├── steer.jsonl # one line per stop check verdict, with no transcript text
|
|
344
|
+
└── pstack-overlay/ # pstack skills with the Pi changes applied
|
|
278
345
|
```
|
|
279
346
|
|
|
280
|
-
Earlier releases kept the state and the model sheet under `t3-pstack
|
|
347
|
+
Earlier releases kept the state and the model sheet under `t3-pstack`, and the first start after an upgrade moves them to the new folders.
|
|
281
348
|
|
|
282
349
|
## Data handling
|
|
283
350
|
|
|
284
|
-
The package has no server and sends no telemetry. The stop checks send parts of the session transcript to the classifier provider,
|
|
351
|
+
The package has no server and sends no telemetry. The stop checks send parts of the session transcript to the classifier's provider, and any file a skill asks the agent to read goes to your model provider. Scripts run on your machine, and the PR tools use your GitHub CLI login.
|
|
285
352
|
|
|
286
353
|
## Development
|
|
287
354
|
|
|
288
|
-
The repository uses npm,
|
|
355
|
+
The repository uses npm. The tests need Docker, because they also run the child tests in Linux containers.
|
|
289
356
|
|
|
290
357
|
```bash
|
|
291
358
|
npm install
|
|
@@ -294,11 +361,11 @@ npm run typecheck
|
|
|
294
361
|
npm run check # Ultracite lint and format check
|
|
295
362
|
```
|
|
296
363
|
|
|
297
|
-
The `pstack/` folder is a git subtree of t3-pstack.
|
|
364
|
+
The `pstack/` folder is a git subtree of t3-pstack. To take upstream changes, run `git merge -X subtree=pstack pstack-upstream`, and put Pi changes in `overlay/` instead of editing `pstack/`.
|
|
298
365
|
|
|
299
366
|
## License
|
|
300
367
|
|
|
301
|
-
The package
|
|
368
|
+
The package uses the MIT license. The copyright holders include the following people and companies:
|
|
302
369
|
|
|
303
370
|
- Lauren Tan, for the original pstack
|
|
304
371
|
- Cursor, for the imported cursor-team-kit and thermos skills
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-t3-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Pi extension adapter for t3-pstack inside T3 Code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-extension",
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"LICENSE",
|
|
40
40
|
"tstack.ts",
|
|
41
41
|
"tstack",
|
|
42
|
-
"amplike.ts"
|
|
42
|
+
"amplike.ts",
|
|
43
|
+
"CHANGELOG.md"
|
|
43
44
|
],
|
|
44
45
|
"type": "module",
|
|
45
46
|
"scripts": {
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"typecheck": "tsc --project tsconfig.json && tsc --project pstack/skills/poteto-mode/scripts/watch-pr/tsconfig.json && tsc --project pstack/skills/statechart/scripts/tsconfig.json"
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
54
|
+
"@earendil-works/pi-schema": "1.5.0",
|
|
53
55
|
"commander": "^15.0.0",
|
|
54
56
|
"marked": "18.0.11",
|
|
55
57
|
"pele": "1.13.0"
|
|
@@ -61,14 +63,12 @@
|
|
|
61
63
|
"oxfmt": "^0.74.0",
|
|
62
64
|
"oxlint": "^1.89.0",
|
|
63
65
|
"testcontainers": "^12.2.1",
|
|
64
|
-
"typebox": "1.3.27",
|
|
65
66
|
"typescript": "^7.0.2",
|
|
66
67
|
"ultracite": "^8.0.1"
|
|
67
68
|
},
|
|
68
69
|
"peerDependencies": {
|
|
69
70
|
"@earendil-works/pi-ai": "*",
|
|
70
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
71
|
-
"typebox": "*"
|
|
71
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
72
72
|
},
|
|
73
73
|
"peerDependenciesMeta": {
|
|
74
74
|
"@earendil-works/pi-coding-agent": {
|
package/src/amplike/btw.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import { Value } from "typebox/value";
|
|
2
|
+
import { compile, nullable, obj, opt, str } from "@earendil-works/pi-schema";
|
|
4
3
|
|
|
5
4
|
import { callT3Tool } from "../bridge/t3-http.ts";
|
|
6
5
|
import type { LoadModeSpec } from "./package.ts";
|
|
@@ -14,10 +13,9 @@ import type { SelectionChange } from "./selection.ts";
|
|
|
14
13
|
|
|
15
14
|
type Command = Parameters<ExtensionAPI["registerCommand"]>[1];
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
link:
|
|
19
|
-
|
|
20
|
-
});
|
|
16
|
+
const isDelegated = compile(
|
|
17
|
+
obj({ link: opt(nullable(str())), taskId: str() }, { open: true })
|
|
18
|
+
).check;
|
|
21
19
|
|
|
22
20
|
const TITLE_LENGTH = 80;
|
|
23
21
|
|
|
@@ -76,7 +74,7 @@ export const btwCommand = (loadModeSpec: LoadModeSpec): Command => ({
|
|
|
76
74
|
target: await targetFor(change),
|
|
77
75
|
});
|
|
78
76
|
|
|
79
|
-
if (!
|
|
77
|
+
if (!isDelegated(delegated)) {
|
|
80
78
|
throw new Error("delegate_task returned no task.");
|
|
81
79
|
}
|
|
82
80
|
|
package/src/amplike/handoff.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
ExtensionAPI,
|
|
9
9
|
ExtensionContext,
|
|
10
10
|
} from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { compile, nullable, obj, opt, str } from "@earendil-works/pi-schema";
|
|
12
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
13
13
|
|
|
14
14
|
import { callT3Tool } from "../bridge/t3-http.ts";
|
|
15
15
|
import type { LoadModeSpec } from "./package.ts";
|
|
@@ -39,10 +39,28 @@ Output only the prompt, with no preamble.`;
|
|
|
39
39
|
|
|
40
40
|
const TITLE_LENGTH = 80;
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
link:
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const isLaunched = compile(
|
|
43
|
+
obj({ link: opt(nullable(str())), threadId: str() }, { open: true })
|
|
44
|
+
).check;
|
|
45
|
+
|
|
46
|
+
const HandoffSchema = obj(
|
|
47
|
+
{
|
|
48
|
+
goal: str({ description: "The goal/task for the new thread" }),
|
|
49
|
+
mode: opt(
|
|
50
|
+
str({
|
|
51
|
+
description:
|
|
52
|
+
"Amplike mode name to start the new thread with (e.g. 'rush', 'smart', 'deep')",
|
|
53
|
+
})
|
|
54
|
+
),
|
|
55
|
+
model: opt(
|
|
56
|
+
str({
|
|
57
|
+
description:
|
|
58
|
+
"Model to start the new thread with, as provider/modelId (e.g. 'anthropic/claude-haiku-4-5')",
|
|
59
|
+
})
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
{ open: true }
|
|
63
|
+
);
|
|
46
64
|
|
|
47
65
|
const summarize = async (
|
|
48
66
|
ctx: ExtensionContext,
|
|
@@ -123,7 +141,7 @@ const handoff = async (
|
|
|
123
141
|
modelSelection: { ...applyChange(await currentSelection(), change) },
|
|
124
142
|
});
|
|
125
143
|
|
|
126
|
-
if (!
|
|
144
|
+
if (!isLaunched(launched)) {
|
|
127
145
|
throw new Error("t3_thread_launch returned no thread.");
|
|
128
146
|
}
|
|
129
147
|
|
|
@@ -134,7 +152,13 @@ export const handoffTool = (loadModeSpec: LoadModeSpec) =>
|
|
|
134
152
|
defineTool({
|
|
135
153
|
description:
|
|
136
154
|
"Transfer context to a new focused T3 thread. ONLY use this when the user explicitly asks for a handoff. Provide a goal describing what the new thread should focus on. The result is the new thread's link, which you show the user verbatim.",
|
|
137
|
-
execute: async (
|
|
155
|
+
execute: async (
|
|
156
|
+
_toolCallId,
|
|
157
|
+
params: Static<typeof HandoffSchema>,
|
|
158
|
+
signal,
|
|
159
|
+
_onUpdate,
|
|
160
|
+
ctx
|
|
161
|
+
) => {
|
|
138
162
|
const link = await handoff(
|
|
139
163
|
ctx,
|
|
140
164
|
params.goal,
|
|
@@ -150,21 +174,7 @@ export const handoffTool = (loadModeSpec: LoadModeSpec) =>
|
|
|
150
174
|
},
|
|
151
175
|
label: "Handoff",
|
|
152
176
|
name: "handoff",
|
|
153
|
-
parameters:
|
|
154
|
-
goal: Type.String({ description: "The goal/task for the new thread" }),
|
|
155
|
-
mode: Type.Optional(
|
|
156
|
-
Type.String({
|
|
157
|
-
description:
|
|
158
|
-
"Amplike mode name to start the new thread with (e.g. 'rush', 'smart', 'deep')",
|
|
159
|
-
})
|
|
160
|
-
),
|
|
161
|
-
model: Type.Optional(
|
|
162
|
-
Type.String({
|
|
163
|
-
description:
|
|
164
|
-
"Model to start the new thread with, as provider/modelId (e.g. 'anthropic/claude-haiku-4-5')",
|
|
165
|
-
})
|
|
166
|
-
),
|
|
167
|
-
}),
|
|
177
|
+
parameters: HandoffSchema,
|
|
168
178
|
});
|
|
169
179
|
|
|
170
180
|
export const handoffCommand = (loadModeSpec: LoadModeSpec): Command => ({
|