pi-session-mcp 0.7.1 → 0.8.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/.pi-session-mcp-cli/config.js +47 -7
- package/.pi-session-mcp-cli/doctor.js +75 -2
- package/.pi-session-mcp-cli/execution-profile.js +1 -0
- package/.pi-session-mcp-cli/override-lock.js +125 -0
- package/.pi-session-mcp-cli/setup-platform.js +195 -0
- package/.pi-session-mcp-cli/setup-result.js +8 -0
- package/.pi-session-mcp-cli/skill-catalog.js +35 -0
- package/.pi-session-mcp-cli/skill-customize.js +268 -0
- package/.pi-session-mcp-cli/skill-library.js +188 -0
- package/CHANGELOG.md +176 -0
- package/README.md +15 -3
- package/dist/capabilities.d.ts +1 -0
- package/dist/capabilities.js +2 -1
- package/dist/client-adapters/mcp-verifier.js +6 -2
- package/dist/config.d.ts +4 -0
- package/dist/config.js +47 -7
- package/dist/doctor.d.ts +7 -1
- package/dist/doctor.js +75 -2
- package/dist/execution-profile.d.ts +4 -0
- package/dist/execution-profile.js +1 -0
- package/dist/override-lock.d.ts +34 -0
- package/dist/override-lock.js +125 -0
- package/dist/pi-adapter.d.ts +7 -5
- package/dist/pi-adapter.js +1 -0
- package/dist/pi-skills.d.ts +17 -0
- package/dist/pi-skills.js +64 -0
- package/dist/sdk-pi-adapter.d.ts +7 -3
- package/dist/sdk-pi-adapter.js +82 -16
- package/dist/server.js +1 -0
- package/dist/session-registry.d.ts +8 -6
- package/dist/session-registry.js +3 -2
- package/dist/setup-cli.d.ts +2 -0
- package/dist/setup-cli.js +16 -0
- package/dist/setup-main.d.ts +1 -1
- package/dist/setup-main.js +18 -3
- package/dist/setup-ownership.d.ts +9 -0
- package/dist/setup-ownership.js +32 -5
- package/dist/setup-skills.d.ts +76 -0
- package/dist/setup-skills.js +586 -0
- package/dist/setup.d.ts +7 -0
- package/dist/setup.js +49 -6
- package/dist/skill-catalog.d.ts +26 -0
- package/dist/skill-catalog.js +35 -0
- package/dist/skill-customize.d.ts +41 -0
- package/dist/skill-customize.js +268 -0
- package/dist/skill-library.d.ts +106 -0
- package/dist/skill-library.js +188 -0
- package/docs/acceptance.md +593 -1
- package/docs/adr/0006-pi-extension-allowlist.md +3 -0
- package/docs/adr/0007-profile-skill-selection.md +228 -0
- package/docs/architecture.md +10 -6
- package/docs/client-setup-design.md +219 -1
- package/docs/client-setup.md +86 -3
- package/docs/doctor-design.md +9 -1
- package/docs/installation.md +128 -5
- package/docs/pi-extensions-design.md +28 -4
- package/docs/releasing.md +18 -9
- package/docs/session-mcp.md +7 -2
- package/docs/skills.md +616 -0
- package/docs/threat-model.md +19 -2
- package/docs/tool-contracts.md +9 -5
- package/package.json +2 -1
- package/pi-session-mcp.example.json +9 -3
- package/skills/pi-session-implementation/SKILL.md +42 -0
- package/skills/pi-session-orchestration/SKILL.md +94 -0
- package/skills/pi-session-review/SKILL.md +58 -0
package/docs/skills.md
ADDED
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
# Pi skills in execution profiles
|
|
2
|
+
|
|
3
|
+
Status: decided in [ADR 0007](adr/0007-profile-skill-selection.md), issue
|
|
4
|
+
[#46](https://github.com/plagor44-ux/pi-session-mcp/issues/46).
|
|
5
|
+
|
|
6
|
+
A Pi skill is a `SKILL.md` file with instructions that Pi lists to the model in
|
|
7
|
+
its system prompt. The model may read the file when a task matches the skill's
|
|
8
|
+
description. Pi Session MCP lets the operator register skill files in a catalog
|
|
9
|
+
and select them per execution profile. MCP callers never choose skills.
|
|
10
|
+
|
|
11
|
+
The package ships three skills and keeps them in a skill library together with
|
|
12
|
+
the operator's own overrides. `pi-session-mcp-setup --apply` also installs the
|
|
13
|
+
controller skill into Claude Code and Codex. Nothing needs to be linked by hand.
|
|
14
|
+
Sections: [Configuration](#configuration), [The skill library](#the-skill-library),
|
|
15
|
+
[Customize and add skills](#customize-and-add-skills), [Install the
|
|
16
|
+
orchestration skill into Codex and Claude Code](#install-the-orchestration-skill-into-codex-and-claude-code)
|
|
17
|
+
and [Upgrade from 0.8.0](#upgrade-from-080).
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
Two optional parts of `pi-session-mcp.json`:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"workspaces": {
|
|
26
|
+
"my-project": "/absolute/path/to/my-project"
|
|
27
|
+
},
|
|
28
|
+
"skillCatalog": {
|
|
29
|
+
"pi-session-implementation": "builtin:pi-session-implementation",
|
|
30
|
+
"pi-session-review": "builtin:pi-session-review",
|
|
31
|
+
"release-notes": "skills-local/release-notes/SKILL.md"
|
|
32
|
+
},
|
|
33
|
+
"executionProfiles": {
|
|
34
|
+
"safe-readonly": {
|
|
35
|
+
"default": true,
|
|
36
|
+
"permissionProfile": "read-only",
|
|
37
|
+
"provider": "your-configured-provider",
|
|
38
|
+
"model": "your-configured-model",
|
|
39
|
+
"thinkingLevel": "medium",
|
|
40
|
+
"skills": ["pi-session-review"]
|
|
41
|
+
},
|
|
42
|
+
"coding-worker": {
|
|
43
|
+
"default": false,
|
|
44
|
+
"permissionProfile": "coding",
|
|
45
|
+
"provider": "your-configured-provider",
|
|
46
|
+
"model": "your-configured-model",
|
|
47
|
+
"thinkingLevel": "high",
|
|
48
|
+
"skills": ["pi-session-implementation", "release-notes"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Catalog: `skillCatalog`
|
|
55
|
+
|
|
56
|
+
- An optional top-level object that maps a skill alias to the path of a
|
|
57
|
+
`SKILL.md` file. A missing catalog is an empty catalog.
|
|
58
|
+
- At most 64 entries. An alias matches `^[a-z][a-z0-9_-]{0,63}$`, like every
|
|
59
|
+
other alias.
|
|
60
|
+
- Each value is either `builtin:<name>` or names exactly one regular, readable
|
|
61
|
+
file whose last path segment is `SKILL.md`. `builtin:<name>` refers to a
|
|
62
|
+
skill of the [skill library](#the-skill-library); `<name>` must follow the
|
|
63
|
+
skill name rule below, and `builtin:` followed by anything else is rejected.
|
|
64
|
+
Directories, globs, URLs and every other scheme-prefixed source (`npm:`,
|
|
65
|
+
`git+…`, `https:`) are rejected. So are `~` and backslashes. A value has at
|
|
66
|
+
most 4096 characters.
|
|
67
|
+
- A relative path resolves against the directory of the configuration file,
|
|
68
|
+
like a workspace. It never resolves against a workspace or the shell's
|
|
69
|
+
working directory. `~` is not expanded: write an absolute path, or use
|
|
70
|
+
`builtin:<name>` for a library skill.
|
|
71
|
+
- A skill folder needs no `package.json` and no extension. The file can live
|
|
72
|
+
anywhere the server's OS user can read. Keep catalog files outside every
|
|
73
|
+
configured workspace: a `coding` session can change any file in its
|
|
74
|
+
workspace, and a changed skill reaches other sessions too (see
|
|
75
|
+
[snapshot semantics](#snapshot-semantics)).
|
|
76
|
+
- The catalog alias is only the public handle. It may differ from the `name` in
|
|
77
|
+
the skill's own frontmatter. Nothing is renamed.
|
|
78
|
+
|
|
79
|
+
### Selection: `executionProfiles.<alias>.skills`
|
|
80
|
+
|
|
81
|
+
- An optional list of catalog aliases, at most 16, no duplicates.
|
|
82
|
+
- Missing or empty means no skills for that profile. There is no inheritance
|
|
83
|
+
between profiles and no default skill.
|
|
84
|
+
- All other profile fields and the rule that unknown fields are rejected are
|
|
85
|
+
unchanged.
|
|
86
|
+
|
|
87
|
+
### Invalid configuration
|
|
88
|
+
|
|
89
|
+
These make the whole configuration invalid. The server does not start, and
|
|
90
|
+
Doctor reports `config_invalid`. Stderr shows the stable startup code
|
|
91
|
+
`invalid_execution_profile_config`:
|
|
92
|
+
|
|
93
|
+
- a selected alias that is not in the catalog;
|
|
94
|
+
- a duplicate alias in one profile's list;
|
|
95
|
+
- two selected aliases of one profile whose paths resolve to the same path,
|
|
96
|
+
for example two aliases for `builtin:pi-session-review`;
|
|
97
|
+
- a catalog value that violates the rules above (including a malformed
|
|
98
|
+
`builtin:` name), or more than 64 entries;
|
|
99
|
+
- more than 16 selected aliases.
|
|
100
|
+
|
|
101
|
+
## The skill library
|
|
102
|
+
|
|
103
|
+
The skill library has two sources and nothing else:
|
|
104
|
+
|
|
105
|
+
1. **Shipped skills.** The package's `skills/` directory.
|
|
106
|
+
2. **Operator overrides.** A `skills/` directory next to the configuration
|
|
107
|
+
file, that is, in the directory of the path in `PI_SESSION_MCP_CONFIG`. For
|
|
108
|
+
the default location `~/.config/pi-session-mcp/pi-session-mcp.json` it is
|
|
109
|
+
`~/.config/pi-session-mcp/skills/<name>/SKILL.md`.
|
|
110
|
+
|
|
111
|
+
An override with the same name replaces the shipped skill. A name that is not
|
|
112
|
+
shipped adds a skill. A name follows the Agent Skills rule: lowercase letters
|
|
113
|
+
and digits in hyphen-separated groups, 1 to 64 characters. No other directory
|
|
114
|
+
is searched: not the current directory, not a workspace and not a client's
|
|
115
|
+
skill directory.
|
|
116
|
+
|
|
117
|
+
### `builtin:<name>` in the catalog
|
|
118
|
+
|
|
119
|
+
A catalog value `builtin:<name>` resolves to `<override dir>/<name>/SKILL.md`
|
|
120
|
+
if that file exists, else to the shipped skill of that name. If neither
|
|
121
|
+
exists, the value keeps the shipped location. Nothing fails when the
|
|
122
|
+
configuration loads, but Doctor then reports `skill_missing` for the profile
|
|
123
|
+
that selects it, and a session start fails with `skill_load_failed`.
|
|
124
|
+
|
|
125
|
+
Resolution happens when the server loads the configuration. Adding or removing
|
|
126
|
+
an override therefore needs a server restart, like any configuration change.
|
|
127
|
+
Edits to a skill file that already resolves reach new sessions, as described
|
|
128
|
+
under [snapshot semantics](#snapshot-semantics). Deleting a resolved override
|
|
129
|
+
leaves the catalog pointing at a missing file until the restart.
|
|
130
|
+
|
|
131
|
+
The shipped example configuration registers the two worker skills with
|
|
132
|
+
`builtin:`. After you copy the example, its skill entries need no path edits.
|
|
133
|
+
|
|
134
|
+
### Shipped skills
|
|
135
|
+
|
|
136
|
+
The package ships three skills under `skills/`. Each has one canonical copy and
|
|
137
|
+
frontmatter with only `name` and `description`.
|
|
138
|
+
|
|
139
|
+
| Skill | For | Use |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| `pi-session-implementation` | A Pi worker | One bounded implementation task and a fixed final report. Register it as `builtin:pi-session-implementation` and select it on coding profiles. |
|
|
142
|
+
| `pi-session-review` | A Pi worker | A review of a fixed target with findings and evidence. Register it as `builtin:pi-session-review` and select it on read-only profiles. |
|
|
143
|
+
| `pi-session-orchestration` | The controlling Claude Code or Codex agent | How to run Pi worker sessions through this server. `setup --apply` installs it into the clients. It is not a Pi worker skill: do not select it in a profile. |
|
|
144
|
+
|
|
145
|
+
A package update can change the shipped skills. Close affected sessions before
|
|
146
|
+
you update, as for any skill change.
|
|
147
|
+
|
|
148
|
+
## Customize and add skills
|
|
149
|
+
|
|
150
|
+
Do not edit the files inside the installed package: an update replaces them.
|
|
151
|
+
Put your version in the override directory.
|
|
152
|
+
|
|
153
|
+
### Customize a shipped skill
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
export PI_SESSION_MCP_CONFIG="$HOME/.config/pi-session-mcp/pi-session-mcp.json"
|
|
157
|
+
pi-session-mcp-setup --customize-skill pi-session-review # dry-run
|
|
158
|
+
pi-session-mcp-setup --apply --customize-skill pi-session-review
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The dry-run reports what would happen, for example:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
dry-run: planned
|
|
165
|
+
skills/override/pi-session-review: planned (skill_customize_planned)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`--apply` copies the shipped skill directory into the override directory as a
|
|
169
|
+
starting point and records the fingerprint of the shipped skill in
|
|
170
|
+
`<override dir>/.pi-session-mcp-bases.json`. Then edit
|
|
171
|
+
`<override dir>/pi-session-review/SKILL.md`, restart the server so that the new
|
|
172
|
+
override is picked up, and start new sessions.
|
|
173
|
+
|
|
174
|
+
- The command works without `--target`; it touches no client. It cannot be
|
|
175
|
+
combined with `--target`, `--verify`, `--rollback` or `--remove`, which are
|
|
176
|
+
usage errors (exit 64).
|
|
177
|
+
- It requires `PI_SESSION_MCP_CONFIG` (otherwise `config_required`) and the
|
|
178
|
+
same platform as the rest of `setup`: Linux or macOS, otherwise
|
|
179
|
+
`platform_unsupported`. It takes no ownership lock. `--apply` takes the
|
|
180
|
+
[override lock](#concurrent-runs-and-the-override-lock); the dry-run takes no
|
|
181
|
+
lock.
|
|
182
|
+
- It never overwrites an existing override and never edits your files.
|
|
183
|
+
- Only regular files are copied: at most 32 files, 1 MiB and 8 directory
|
|
184
|
+
levels, no links, and entries whose name starts with `.` are skipped.
|
|
185
|
+
|
|
186
|
+
The finding target is `{ client: "skills", scope: "override", alias: <name> }`:
|
|
187
|
+
|
|
188
|
+
| Code | Status | Meaning |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `skill_customize_planned` | planned | Dry-run: no override exists, or an existing override equals the shipped skill but has no recorded base; `--apply` would copy the shipped skill if it is absent and record the base. |
|
|
191
|
+
| `skill_customized` | ok | The override was created and its base recorded, or an existing override that equals the shipped skill got its missing base. The second case completes a customization whose bases commit failed. |
|
|
192
|
+
| `skill_override_current` | unchanged | The override exists and its recorded base equals the current shipped skill. Of two concurrent applies for the same skill, the later one reports this. |
|
|
193
|
+
| `skill_override_outdated` | planned | The shipped skill changed since the copy, or no base is recorded for an existing override that differs from the shipped skill, or a 0.8.0 base names a released shipped skill that is not the current one. |
|
|
194
|
+
| `skill_base_migration_planned` | planned | Dry-run: a 0.8.0 base names the current shipped skill; `--apply` would record it as a version 2 base. |
|
|
195
|
+
| `skill_base_migrated` | ok | `--apply` after `skill_base_migration_planned`: the base is recorded as version 2. |
|
|
196
|
+
| `skill_base_unverified` | planned | Dry-run: a 0.8.0 base names no released shipped skill, so it cannot be confirmed. `--apply` records the current shipped skill as the base after you reviewed it. |
|
|
197
|
+
| `skill_base_updated` | ok | `--apply` after `skill_override_outdated` or `skill_base_unverified`: only the recorded base moved. |
|
|
198
|
+
| `skill_not_shipped` | failed | The name is not valid or the package ships no such skill. |
|
|
199
|
+
| `skill_bases_corrupt` | failed | The bases file is not valid. Repair or remove it. |
|
|
200
|
+
| `skill_override_invalid` | failed | The override entry is not a directory, or its tree is unusable (no `SKILL.md`, a link, too large). |
|
|
201
|
+
| `skill_customize_lock_busy` | failed | Another run held the override lock for the whole wait of 30 seconds. Run the command again. |
|
|
202
|
+
| `skill_customize_lock_unavailable` | failed | The lock cannot be taken: the platform, the filesystem or the `flock` binary is not supported. |
|
|
203
|
+
| `skill_customize_failed` | failed | Any other failure while copying or recording. |
|
|
204
|
+
|
|
205
|
+
### Concurrent runs and the override lock
|
|
206
|
+
|
|
207
|
+
`--apply --customize-skill` is one transaction per override directory. It takes
|
|
208
|
+
an exclusive kernel lock on `<override dir>/.pi-session-mcp-bases.lock` (mode
|
|
209
|
+
`0600`, never deleted), reads and validates the bases file under the lock,
|
|
210
|
+
copies the shipped skill if no override exists, merges the base, and replaces
|
|
211
|
+
the bases file atomically: an fsynced temporary file, a rename and a directory
|
|
212
|
+
fsync. The lock is released on every path. Two runs for different skills
|
|
213
|
+
therefore cannot lose each other's base. If the commit of the bases file
|
|
214
|
+
fails, the previous file stays; a retry then completes the customization
|
|
215
|
+
without overwriting your files (`skill_customized` for an override that equals
|
|
216
|
+
the shipped skill and has no base).
|
|
217
|
+
|
|
218
|
+
- The lock wait is bounded at 30 seconds, then the result is
|
|
219
|
+
`skill_customize_lock_busy`. A lock that cannot be taken at all is
|
|
220
|
+
`skill_customize_lock_unavailable`.
|
|
221
|
+
- On Linux the lock needs the trusted util-linux `flock` at `/usr/bin/flock` or
|
|
222
|
+
`/bin/flock`; on macOS it uses `O_EXLOCK`. Both need a supported local
|
|
223
|
+
filesystem.
|
|
224
|
+
- A holder that is killed releases the lock through the kernel. It may leave a
|
|
225
|
+
stale hidden temporary bases file `.pi-session-mcp-bases.json.<hex>.tmp` or
|
|
226
|
+
hidden temporary copy directory `.<skill>.<hex>.tmp` in the override
|
|
227
|
+
directory. Both are harmless: they are hidden and never resolved as skills.
|
|
228
|
+
Nothing removes them automatically; you may delete them while no
|
|
229
|
+
customization runs.
|
|
230
|
+
- The dry-run takes no lock and writes nothing: no directory, lock file or
|
|
231
|
+
temporary file.
|
|
232
|
+
- Doctor stays offline, read-only and lock-free.
|
|
233
|
+
|
|
234
|
+
The bases file is `{"schemaVersion":2,"bases":{"<name>":"<fingerprint>"}}`. A
|
|
235
|
+
value is a `v2:` fingerprint, or a legacy 64-hex value that could not be
|
|
236
|
+
migrated. A version 1 file (0.8.0) is still read. Every write produces version
|
|
237
|
+
2 and migrates each legacy value that names a released 0.8.0 shipped skill; any
|
|
238
|
+
other legacy value is kept as it is. See [Upgrade from
|
|
239
|
+
0.8.0](#upgrade-from-080).
|
|
240
|
+
|
|
241
|
+
### Follow a changed shipped skill
|
|
242
|
+
|
|
243
|
+
After a package update, `skill_override_outdated` (from the command above, or
|
|
244
|
+
as a [Doctor](#doctor-boundary) warning) means that the shipped skill differs
|
|
245
|
+
from the one your override was copied from. Review the shipped text, merge what
|
|
246
|
+
you want into your override by hand, and then acknowledge it:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
pi-session-mcp-setup --apply --customize-skill pi-session-review
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
That moves only the recorded base (`skill_base_updated`). It never touches your
|
|
253
|
+
files. The override keeps winning until you delete it; the base only decides
|
|
254
|
+
whether Doctor warns.
|
|
255
|
+
|
|
256
|
+
### Add a new skill
|
|
257
|
+
|
|
258
|
+
No command is needed. Create `<override dir>/<new-name>/SKILL.md` (a valid
|
|
259
|
+
Agent Skills file with `name` and `description` frontmatter), reference it as
|
|
260
|
+
`builtin:<new-name>` in `skillCatalog`, select its alias in a profile, and
|
|
261
|
+
restart the server. Companion files belong in the same directory. A name that
|
|
262
|
+
equals a shipped skill replaces that skill instead of adding one.
|
|
263
|
+
|
|
264
|
+
Where `setup` is unsupported, create an override by copying a shipped skill
|
|
265
|
+
directory by hand. Doctor does not track a copy that has no recorded base.
|
|
266
|
+
|
|
267
|
+
## Install the orchestration skill into Codex and Claude Code
|
|
268
|
+
|
|
269
|
+
The orchestration skill is for the controlling agent, not for a Pi worker.
|
|
270
|
+
`pi-session-mcp-setup --apply --target <target>` installs it after the
|
|
271
|
+
registration, as a real copy of the effective skill: your override if you have
|
|
272
|
+
one, else the shipped skill. Clients discover it without further steps.
|
|
273
|
+
|
|
274
|
+
| Target | Skill directory |
|
|
275
|
+
| --- | --- |
|
|
276
|
+
| `codex:user:pi-session-mcp` | `~/.agents/skills/pi-session-orchestration` |
|
|
277
|
+
| `claude-code:user:pi-session-mcp` and `claude-code:local:pi-session-mcp` | `~/.claude/skills/pi-session-orchestration` (one shared directory) |
|
|
278
|
+
| `claude-code:project:pi-session-mcp` | `<project>/.claude/skills/pi-session-orchestration`, where `<project>` is the directory in which `setup` runs |
|
|
279
|
+
|
|
280
|
+
Claude Code reads personal skills in `~/.claude/skills/<name>/SKILL.md` and
|
|
281
|
+
project skills in `.claude/skills/<name>/SKILL.md`
|
|
282
|
+
([Claude Code skills](https://code.claude.com/docs/en/skills)). Codex reads user
|
|
283
|
+
skills in `~/.agents/skills`
|
|
284
|
+
([Codex skills](https://learn.chatgpt.com/docs/build-skills)).
|
|
285
|
+
|
|
286
|
+
Every `setup` result has a second finding per target, with the same client and
|
|
287
|
+
scope and the alias `pi-session-orchestration`. A skill problem never blocks
|
|
288
|
+
the registration, but a `divergent` or `failed` skill finding makes the overall
|
|
289
|
+
status `failed` (exit 1), so it is not overlooked.
|
|
290
|
+
|
|
291
|
+
| Operation | Code (status) |
|
|
292
|
+
| --- | --- |
|
|
293
|
+
| `--dry-run` | `skill_absent` (absent), `skill_equivalent` (unchanged), `skill_linked` (unchanged), `skill_update_planned` (planned), `skill_recovery_planned` (planned), `skill_divergent` (divergent), `skill_legacy_unverified` (divergent), `skill_source_invalid` (failed) |
|
|
294
|
+
| `--apply` | `skill_installed` (ok), `skill_already_equivalent` (unchanged), `skill_recovered` (ok), `skill_linked` (unchanged), `skill_updated` (ok), `skill_divergent` (divergent), `skill_legacy_unverified` (divergent), `skill_recovery_retained` (divergent), `skill_source_invalid` (failed), `skill_install_failed` (failed) |
|
|
295
|
+
| `--verify` | `skill_verified` (ok), `skill_missing` (failed), `skill_not_equivalent` (failed) |
|
|
296
|
+
| `--rollback`, `--remove` | `skill_removed` (ok), `skill_kept_shared` (unchanged), `skill_not_owned` (unchanged), `skill_absent` (ok), `skill_divergent` (divergent), `skill_legacy_unverified` (divergent), `skill_recovery_retained` (divergent) |
|
|
297
|
+
|
|
298
|
+
- `--apply` installs the skill only when the registration finding is `ok` or
|
|
299
|
+
`unchanged`; `--rollback` and `--remove` handle it only after the
|
|
300
|
+
registration was removed.
|
|
301
|
+
- `skill_updated` means that setup replaced its own unmodified copy after a
|
|
302
|
+
package update or a changed override.
|
|
303
|
+
- `skill_recovered` means that `--apply` settled an interrupted update of
|
|
304
|
+
setup's own copy (it renamed an intermediate into place or deleted one, or
|
|
305
|
+
finished the pending ownership record) and needed no further update.
|
|
306
|
+
If the settled copy still needs the new version, `--apply` continues and
|
|
307
|
+
reports `skill_installed` or `skill_updated`.
|
|
308
|
+
- `skill_recovery_planned` means that the ownership record is pending for an
|
|
309
|
+
update that `--apply` would settle. The dry-run does not write or delete
|
|
310
|
+
anything and does not look at the intermediate directories, so `--apply` can
|
|
311
|
+
still find a modified or foreign intermediate, keep it and report
|
|
312
|
+
`skill_recovery_retained`. A divergent or
|
|
313
|
+
foreign copy keeps `skill_divergent`, and a 0.8.0 record keeps its own code.
|
|
314
|
+
- `skill_kept_shared` means that the other Claude Code registration (`user` or
|
|
315
|
+
`local`) still uses the shared directory. The last one removes the skill.
|
|
316
|
+
- A copy that already equals the effective skill but was not created by `setup`
|
|
317
|
+
is reported as equivalent and stays unowned; a later `--remove` reports
|
|
318
|
+
`skill_not_owned`.
|
|
319
|
+
- `--verify` compares the installed copy with the effective skill and does not
|
|
320
|
+
look at ownership.
|
|
321
|
+
|
|
322
|
+
### What setup never replaces or deletes
|
|
323
|
+
|
|
324
|
+
Setup reports `skill_divergent` and leaves the entry alone when it finds:
|
|
325
|
+
|
|
326
|
+
- an installed copy that was modified after setup wrote it;
|
|
327
|
+
- a skill of the same name that setup did not install and that differs from the
|
|
328
|
+
effective skill;
|
|
329
|
+
- any entry whose name starts with `.` inside an installed copy, such as your
|
|
330
|
+
own notes or a `.DS_Store` that macOS Finder adds: setup never writes such
|
|
331
|
+
entries, so it treats them as yours; delete them to let setup manage the copy
|
|
332
|
+
again;
|
|
333
|
+
- a link at the skill entry that points anywhere but the effective skill, or a
|
|
334
|
+
non-directory there.
|
|
335
|
+
|
|
336
|
+
A link at the skill entry that points exactly at the effective skill (your
|
|
337
|
+
override, else the shipped skill) is your own equivalent setup: setup reports
|
|
338
|
+
`skill_linked` (unchanged), `--verify` reports `skill_verified`, and removal
|
|
339
|
+
leaves the link alone (`skill_not_owned`). If you replace setup's own copy with
|
|
340
|
+
such a link, setup forgets its copy on the next `--apply` or `--remove`. A link
|
|
341
|
+
counts only while the effective skill itself is valid.
|
|
342
|
+
|
|
343
|
+
A project copy belongs to its project: setup records an opaque project
|
|
344
|
+
identity, so a `--remove` in another project never deletes it.
|
|
345
|
+
|
|
346
|
+
Links in the path to the entry are handled by place. In your home directory,
|
|
347
|
+
the client's skill directory may be your own link, for example into a dotfiles
|
|
348
|
+
checkout, and is followed. Inside a project, which may be untrusted, any link
|
|
349
|
+
below the project root makes the entry divergent, so setup never writes outside
|
|
350
|
+
the project.
|
|
351
|
+
|
|
352
|
+
### Interrupted updates
|
|
353
|
+
|
|
354
|
+
An update first writes a pending ownership record, then works in intermediate
|
|
355
|
+
directories in the parent of the skill directory. They are named after the
|
|
356
|
+
record's transaction id: `.pi-session-mcp-<skill>-<transactionId>.staging`,
|
|
357
|
+
`.backup` and `.trash`. The order is: pending record, staging directory, rename
|
|
358
|
+
of the old copy to the backup, install, verification, rename of the backup to
|
|
359
|
+
the trash, deletion of the trash entry by entry, owned record.
|
|
360
|
+
|
|
361
|
+
If an update is interrupted, for example by a full disk or a signal, setup
|
|
362
|
+
still recognizes the old copy as its own. `--apply`, `--remove` and
|
|
363
|
+
`--rollback` settle a pending transaction first:
|
|
364
|
+
|
|
365
|
+
- `--apply` finishes forward when a complete staging directory is left, or
|
|
366
|
+
moves the verified backup back, and then continues.
|
|
367
|
+
- `--remove` and `--rollback` delete the verified intermediates and then remove
|
|
368
|
+
the copy as usual.
|
|
369
|
+
- A partial trash directory is deleted after a structural recheck (real
|
|
370
|
+
directories and regular files only, no hidden entries, within the tree
|
|
371
|
+
limits).
|
|
372
|
+
- A partially written staging directory is deleted only when every file in it
|
|
373
|
+
is a prefix-consistent part of the current library tree, and that tree is the
|
|
374
|
+
record's target.
|
|
375
|
+
- Anything modified or foreign stays and is reported as
|
|
376
|
+
`skill_recovery_retained` (divergent). Inspect the directory and delete it
|
|
377
|
+
yourself if it is not yours.
|
|
378
|
+
|
|
379
|
+
A failed update leaves its staging directory until the next run settles it.
|
|
380
|
+
The directories of updates by 0.8.0 had random names. Setup never searches for
|
|
381
|
+
or deletes them; you may delete them by hand. `--dry-run` and `--verify` do not
|
|
382
|
+
report leftover intermediates.
|
|
383
|
+
|
|
384
|
+
### Customize the controller skill
|
|
385
|
+
|
|
386
|
+
Never edit the installed copy: it becomes divergent. Instead:
|
|
387
|
+
|
|
388
|
+
1. `pi-session-mcp-setup --apply --customize-skill pi-session-orchestration`
|
|
389
|
+
2. Edit `<override dir>/pi-session-orchestration/SKILL.md`.
|
|
390
|
+
3. `pi-session-mcp-setup --apply --target <target>` again. The unmodified
|
|
391
|
+
installed copy is replaced (`skill_updated`).
|
|
392
|
+
|
|
393
|
+
To recover after editing the installed copy, move your edits into the override,
|
|
394
|
+
delete the installed copy, and run `--apply` again.
|
|
395
|
+
|
|
396
|
+
### Scope of what setup installs
|
|
397
|
+
|
|
398
|
+
Setup installs only `pi-session-orchestration` into clients. The worker skills
|
|
399
|
+
are for Pi profiles and are used through `builtin:`. Controller skills of your
|
|
400
|
+
own belong in the clients' native skill directories; setup does not manage
|
|
401
|
+
them.
|
|
402
|
+
|
|
403
|
+
### Install by hand where setup is unsupported
|
|
404
|
+
|
|
405
|
+
Where `setup` does not run, copy the directory; do not link it. Copy
|
|
406
|
+
`skills/pi-session-orchestration` from the installed package (in an npm
|
|
407
|
+
installation `"$(npm root -g)/pi-session-mcp/skills/pi-session-orchestration"`)
|
|
408
|
+
to `~/.claude/skills/` or `.claude/skills/` of a project for Claude Code, or to
|
|
409
|
+
`~/.agents/skills/` for Codex. Repeat the copy after a package update; nothing
|
|
410
|
+
keeps a manual copy current. Do not replace an existing skill of the same name
|
|
411
|
+
without checking it first.
|
|
412
|
+
|
|
413
|
+
Neither client needs a skill to call the Pi Session MCP tools; the skill only
|
|
414
|
+
describes the working method. Headless `codex exec` runs still need the
|
|
415
|
+
per-tool approvals for `pi_session_prompt`, `pi_session_abort` and
|
|
416
|
+
`pi_session_close` that [client
|
|
417
|
+
setup](client-setup.md#run-codex-without-prompts) describes.
|
|
418
|
+
|
|
419
|
+
### Pi workers
|
|
420
|
+
|
|
421
|
+
Pi workers never discover skills on their own in Pi Session MCP. Register the
|
|
422
|
+
worker skills with `builtin:` and select them on profiles, as described above.
|
|
423
|
+
Do not select the orchestration skill for a Pi worker: a worker has only the
|
|
424
|
+
tools of its profile and is not a controller of other Pi sessions.
|
|
425
|
+
|
|
426
|
+
## What happens at session start
|
|
427
|
+
|
|
428
|
+
The server loads exactly the selected files through the Pi SDK's public
|
|
429
|
+
`loadSkills`, without any default directories, and validates them completely.
|
|
430
|
+
The SDK's skill override returns exactly that set, also after an extension adds
|
|
431
|
+
resources later (`resources_discover`). A profile without skills gets no
|
|
432
|
+
skills, whatever is installed on the machine or shipped by an extension.
|
|
433
|
+
|
|
434
|
+
The start fails with `skill_load_failed` (message `Configured Pi skill could
|
|
435
|
+
not be loaded`) if:
|
|
436
|
+
|
|
437
|
+
- a selected file is missing, unreadable, or larger than 256 KiB (also a
|
|
438
|
+
`builtin:` value that resolved to no skill);
|
|
439
|
+
- the SDK reports the skill as invalid, for example a missing description or an
|
|
440
|
+
invalid name;
|
|
441
|
+
- two selected files declare the same Pi skill name;
|
|
442
|
+
- two aliases point at the same canonical file, for example through a symlink;
|
|
443
|
+
- the skill sets `disable-model-invocation: true`.
|
|
444
|
+
|
|
445
|
+
The message is fixed. It never contains a path, a skill name or SDK text.
|
|
446
|
+
Stderr gets a structured diagnostic. A selected file that fails validation
|
|
447
|
+
reports the stage `skill_load` and, when one alias is to blame, that catalog
|
|
448
|
+
alias in a `skill` field. If the session's actual skill catalog differs from
|
|
449
|
+
the selection after construction, the stage is `postcheck`, or
|
|
450
|
+
`extension_load` and `extension_bind` for a profile with extensions. Neither
|
|
451
|
+
carries a path.
|
|
452
|
+
|
|
453
|
+
If the session's prompt-template or theme catalog is not empty after
|
|
454
|
+
construction, which the overrides should prevent, the start fails with
|
|
455
|
+
`pi_session_creation_failed`.
|
|
456
|
+
|
|
457
|
+
Explicit-only skills (`disable-model-invocation: true`) are incompatible in
|
|
458
|
+
this version. Pi hides such skills from the model, and MCP prompts never run
|
|
459
|
+
`/skill:` commands, so the skill could never be used. The server does not
|
|
460
|
+
rewrite the flag. The same Pi skill name in different sessions is fine.
|
|
461
|
+
|
|
462
|
+
## Doctor boundary
|
|
463
|
+
|
|
464
|
+
Doctor stays offline and never parses or executes a skill. For each profile and
|
|
465
|
+
selected alias it adds three checks after the extension checks, with the
|
|
466
|
+
subject `<profile>:<skill-alias>`. A `builtin:` alias is checked at the
|
|
467
|
+
location it resolved to:
|
|
468
|
+
|
|
469
|
+
| ID | Condition |
|
|
470
|
+
| --- | --- |
|
|
471
|
+
| `skill_missing` | The selected file does not exist. |
|
|
472
|
+
| `skill_unreadable` | The path is not a regular file, is over 256 KiB, or cannot be read. |
|
|
473
|
+
| `skill_duplicate` | Two selected aliases of one profile resolve to the same canonical file. |
|
|
474
|
+
|
|
475
|
+
Frontmatter, name rules, name collisions and the explicit-only flag are checked
|
|
476
|
+
only at session start by the SDK contract. A clean Doctor run therefore does
|
|
477
|
+
not promise that the skill loads.
|
|
478
|
+
|
|
479
|
+
A fourth check concerns overrides, not profiles:
|
|
480
|
+
|
|
481
|
+
| ID | Severity | Subject | Condition |
|
|
482
|
+
| --- | --- | --- | --- |
|
|
483
|
+
| `skill_override_outdated` | warning | `skill:<name>` | The shipped skill's current fingerprint differs from the base recorded in `<override dir>/.pi-session-mcp-bases.json`. A 0.8.0 base counts as the released shipped skill that it names. |
|
|
484
|
+
| `skill_override_outdated` | warning | `skill:<name>` | The recorded base is a 0.8.0 value that names no released shipped skill. The remediation says that the base predates version 2 fingerprints and cannot be confirmed: review the shipped skill, then run `pi-session-mcp-setup --apply --customize-skill <name>`. |
|
|
485
|
+
| `skill_override_outdated` | warning | `skill:bases` | The bases file is corrupt. |
|
|
486
|
+
|
|
487
|
+
It is `ok` for a recorded base that still matches. The remediation for a
|
|
488
|
+
changed skill names the command
|
|
489
|
+
`pi-session-mcp-setup --apply --customize-skill <name>`, after you reviewed the
|
|
490
|
+
change (see [Follow a changed shipped skill](#follow-a-changed-shipped-skill)).
|
|
491
|
+
Only skills with a recorded base are compared. Doctor reads the bases file and
|
|
492
|
+
the shipped files and executes nothing. A warning gives exit status `1`; it does
|
|
493
|
+
not block `setup`.
|
|
494
|
+
|
|
495
|
+
## Three states, and a fourth thing
|
|
496
|
+
|
|
497
|
+
Keep these apart:
|
|
498
|
+
|
|
499
|
+
1. **Configured.** `pi_capabilities_get` lists the alias under the profile's
|
|
500
|
+
`skills`. This is configuration intent only. It says nothing about the file.
|
|
501
|
+
2. **Available in the SDK catalog.** The skill passed validation at session
|
|
502
|
+
start and Pi lists it to the model in the system prompt.
|
|
503
|
+
3. **Actually read by the model.** The model decides to read the `SKILL.md`
|
|
504
|
+
with its `read` tool. This is not guaranteed.
|
|
505
|
+
|
|
506
|
+
Task success is separate from all three. A skill that the model read can still
|
|
507
|
+
produce a bad result, and a task can succeed without the skill.
|
|
508
|
+
|
|
509
|
+
## Snapshot semantics
|
|
510
|
+
|
|
511
|
+
The profile and its skill selection are fixed per session. The skill content
|
|
512
|
+
is not snapshotted: the SDK keeps file paths, and the model's later reads may
|
|
513
|
+
see changed files. This also applies to companion files that a skill refers
|
|
514
|
+
to.
|
|
515
|
+
|
|
516
|
+
- Manage skill files and companion files as operator content. Do not change
|
|
517
|
+
them while sessions that use them are active.
|
|
518
|
+
- Close the affected sessions before an update. New sessions then load the new
|
|
519
|
+
content.
|
|
520
|
+
- The configuration fingerprint covers the configuration bytes, not skill
|
|
521
|
+
contents.
|
|
522
|
+
- There is no hot reload, no watcher, no copy store for sessions and no
|
|
523
|
+
versioning. A change
|
|
524
|
+
to `skillCatalog` or `skills` needs a new server process like any other
|
|
525
|
+
configuration change. So does adding or removing an override of a library
|
|
526
|
+
skill, because `builtin:` is resolved when the configuration loads. Editing
|
|
527
|
+
the file of an override that already resolves needs no restart for new
|
|
528
|
+
sessions.
|
|
529
|
+
|
|
530
|
+
## Trust and limits
|
|
531
|
+
|
|
532
|
+
Skills are operator-managed prompt content. The override directory and its
|
|
533
|
+
bases file are operator-trusted configuration next to the configuration file,
|
|
534
|
+
never a workspace; keep them out of every workspace and writable only by you.
|
|
535
|
+
Setup copies the effective orchestration skill into the clients' skill
|
|
536
|
+
directories, where it becomes instructions for the controlling agent, so review
|
|
537
|
+
an override like code. In a `coding` profile a skill's
|
|
538
|
+
instructions are executed with that profile's tools, so review a skill like
|
|
539
|
+
code. A skill grants no rights: the tools of the permission profile stay the
|
|
540
|
+
limit.
|
|
541
|
+
|
|
542
|
+
Skill selection limits the regular skill catalog only. An allowlisted
|
|
543
|
+
extension remains trusted executable code. It can still read files or inject
|
|
544
|
+
prompt text. This is not a sandbox.
|
|
545
|
+
|
|
546
|
+
No MCP tool and no tool argument takes a skill. `pi_session_start` and
|
|
547
|
+
`pi_session_prompt` are unchanged.
|
|
548
|
+
|
|
549
|
+
Pi lists each available skill to the model with the absolute path of its
|
|
550
|
+
`SKILL.md`, so that the model can read it. The model may repeat that path in
|
|
551
|
+
its answer. Capabilities, errors and diagnostics stay path-free, but completed
|
|
552
|
+
`assistantText` is model output and is not sanitized.
|
|
553
|
+
|
|
554
|
+
## Upgrade from 0.8.0
|
|
555
|
+
|
|
556
|
+
### Skill tree fingerprints
|
|
557
|
+
|
|
558
|
+
A fingerprint identifies a skill tree by content. Version 2, stored as
|
|
559
|
+
`v2:<64 hex>`, is a SHA-256 over a domain and version tag, the file count, and
|
|
560
|
+
for each file in path byte order the length-prefixed UTF-8 path and the
|
|
561
|
+
length-prefixed content. The size and file type limits are unchanged. Version 1
|
|
562
|
+
(0.8.0) hashed `path NUL content NUL` for each file. Content may contain NUL
|
|
563
|
+
bytes, so two different trees could share a version 1 value.
|
|
564
|
+
|
|
565
|
+
A version 1 value never proves identity alone. It counts only when a trusted
|
|
566
|
+
reference has that version 1 value and is byte-identical, by its version 2
|
|
567
|
+
value, to the tree in question. The trusted references are the shipped skills of
|
|
568
|
+
the 0.8.0 release (a fixed table in the code) and, for setup's installed copies,
|
|
569
|
+
the current library tree.
|
|
570
|
+
|
|
571
|
+
### What to do after the upgrade
|
|
572
|
+
|
|
573
|
+
1. Run `pi-session-mcp-setup` as a dry-run for your targets, then with
|
|
574
|
+
`--apply`. An unchanged copy of the 0.8.0 controller skill is proven against
|
|
575
|
+
the 0.8.0 table, its ownership record is migrated, and the copy is updated to
|
|
576
|
+
the new shipped skill. A copy that cannot be proven stays untouched, and
|
|
577
|
+
dry-run, apply, remove and rollback report `skill_legacy_unverified` for it.
|
|
578
|
+
Inspect the copy. If it is unchanged setup content that you no longer need,
|
|
579
|
+
delete it yourself and run the operation again: an absent slot clears the
|
|
580
|
+
record. Otherwise keep it.
|
|
581
|
+
2. For customized skills, Doctor resolves 0.8.0 bases against the 0.8.0 table.
|
|
582
|
+
The next `--apply --customize-skill` for any skill rewrites the bases file as
|
|
583
|
+
version 2.
|
|
584
|
+
|
|
585
|
+
Ownership records of skill copies hold `v2:` values in `fingerprint` and
|
|
586
|
+
`replaces`. Registration records are unchanged.
|
|
587
|
+
|
|
588
|
+
### Downgrade
|
|
589
|
+
|
|
590
|
+
0.8.0 rejects the new formats, so it never acts on them. It treats a version 2
|
|
591
|
+
bases file as corrupt (`skill_bases_corrupt`, and the Doctor warning with the
|
|
592
|
+
subject `skill:bases`). It validates the ownership file as a whole and treats a
|
|
593
|
+
skill record with a `v2:` value as invalid, so it rejects the entire file as
|
|
594
|
+
corrupt, registration records included. Before you run 0.8.0 again, repair or
|
|
595
|
+
remove those files.
|
|
596
|
+
|
|
597
|
+
## Migration: profiles that relied on package skills
|
|
598
|
+
|
|
599
|
+
With Pi SDK 1.1.0, an allowlisted extension package's bundled skills reached
|
|
600
|
+
the session although `noSkills` was set. The same held for prompt
|
|
601
|
+
templates and themes that a package shipped. Now an extension allowlist alone
|
|
602
|
+
makes none of its skills available. Prompt templates and themes that packages
|
|
603
|
+
ship are closed as well, through the SDK's public overrides. They were never
|
|
604
|
+
expanded for MCP prompts. Profiles without extensions are not affected.
|
|
605
|
+
|
|
606
|
+
If a profile used a skill that a package shipped:
|
|
607
|
+
|
|
608
|
+
1. Find the package's `SKILL.md` inside Pi's install, normally
|
|
609
|
+
`<Pi agent dir>/npm/node_modules/<package>/…`.
|
|
610
|
+
2. Add a catalog entry with the absolute path of that file. `~` is not
|
|
611
|
+
expanded.
|
|
612
|
+
3. Select the alias in the profile's `skills`.
|
|
613
|
+
4. Run Doctor and start a session to confirm.
|
|
614
|
+
|
|
615
|
+
Keep in mind that a package update can move or change the file. The catalog
|
|
616
|
+
path then needs a check.
|