pi-session-mcp 0.13.0 → 0.13.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.
Files changed (39) hide show
  1. package/.pi-session-mcp-cli/config.js +21 -2
  2. package/.pi-session-mcp-cli/doctor.js +8 -3
  3. package/CHANGELOG.md +73 -0
  4. package/CONTRIBUTING.md +8 -1
  5. package/README.md +4 -2
  6. package/dist/config.d.ts +11 -1
  7. package/dist/config.js +21 -2
  8. package/dist/confined-tools.d.ts +1 -0
  9. package/dist/confined-tools.js +6 -2
  10. package/dist/doctor.js +8 -3
  11. package/dist/main.js +6 -2
  12. package/dist/sdk-pi-adapter.js +3 -2
  13. package/dist/setup-cli.d.ts +1 -2
  14. package/dist/setup-cli.js +0 -3
  15. package/dist/setup-writers-common.d.ts +78 -0
  16. package/dist/setup-writers-common.js +177 -0
  17. package/dist/setup-writers-plan.d.ts +34 -0
  18. package/dist/setup-writers-plan.js +105 -0
  19. package/dist/setup-writers-reconcile.d.ts +8 -0
  20. package/dist/setup-writers-reconcile.js +169 -0
  21. package/dist/setup-writers.d.ts +6 -30
  22. package/dist/setup-writers.js +18 -382
  23. package/dist/wake-hook.d.ts +11 -0
  24. package/dist/wake-hook.js +51 -8
  25. package/docs/acceptance.md +130 -0
  26. package/docs/adr/0009-execution-modes.md +3 -2
  27. package/docs/adr/0012-leased-writer-pool.md +3 -3
  28. package/docs/adr/0013-hardened-read-only-profiles.md +6 -4
  29. package/docs/architecture.md +1 -1
  30. package/docs/client-setup.md +3 -3
  31. package/docs/doctor-design.md +1 -1
  32. package/docs/execution-modes.md +1 -1
  33. package/docs/roadmap.md +13 -5
  34. package/docs/session-mcp.md +5 -3
  35. package/docs/threat-model.md +2 -1
  36. package/docs/tool-contracts.md +4 -2
  37. package/package.json +1 -1
  38. package/skills/pi-session-orchestration/SKILL.md +2 -2
  39. package/skills/pi-session-orchestration/references/start-errors.md +1 -1
@@ -2457,6 +2457,136 @@ Not established for `0.11.6`:
2457
2457
  wrapper's periodic credential copy (#136);
2458
2458
  - the VS Code wake; macOS delivery.
2459
2459
 
2460
+ ### v0.13.0 post-release evidence
2461
+
2462
+ Recorded on 2026-10-28 for the published release `0.13.0`.
2463
+
2464
+ Tag binding: a fresh clone of the annotated tag `v0.13.0` (tag object
2465
+ `8c2d513ccac17916fdf7cf3fc36b3ccd454138ed`) peels to the merge commit
2466
+ `d1c63dac3b996952976aab4b5ad11665e7108fa3` of #171, and
2467
+ `git describe --tags --exact-match` reports `v0.13.0`. CI on the merge commit
2468
+ (run 40757781881) and on the tag (run 40759098803) passed on the first attempt.
2469
+
2470
+ - Level 1 on the tag clone after `npm ci`, from 21:01 to 21:03 UTC with
2471
+ Node.js `26.12.1` and npm `12.2.1`: typecheck, `build:cli`, the test run
2472
+ (125 files, 3936 passed, 14 skipped, with
2473
+ `NODE_OPTIONS=--unhandled-rejections=strict`), `build` and
2474
+ `git diff --check` exited with `0`, and the status stayed clean. Doctor
2475
+ reported `packageVersion` `0.13.0` and exited with `2` because no
2476
+ configuration was set (`config_missing`).
2477
+ - `pi-session-mcp@0.13.0` on npm: 916 files, shasum
2478
+ `866d0ecfa3b4e1a71462d291b1776897229f7827`, `gitHead` `4521d39` (the head of
2479
+ #171, whose tree equals the merge commit). `npm pack` of the tag clone gives
2480
+ the same shasum and file count.
2481
+ - Published npm package, Level 2 from a fresh prefix, 21:03 to 21:05 UTC:
2482
+ 160 of 160 with delivery off and 228 of 228 with `--events spool`; real
2483
+ registrations and built files unchanged, no process left, leak check passed.
2484
+ Clients: Codex CLI `0.162.1` and Claude Code `2.1.312`. The install smoke on
2485
+ the published package reported `smoke_passed` with version `0.13.0`.
2486
+ - The GitHub release `v0.13.0` was published the same day.
2487
+
2488
+ Operator upgrade of the second machine (Linux) from `0.12.1` to `0.13.0` on
2489
+ 2026-10-28 from 20:34 UTC, following
2490
+ [Installation](installation.md#container-writers), with Node.js `24.22.0`:
2491
+
2492
+ - Both client targets were removed with `0.12.1`, then
2493
+ `npm install -g pi-session-mcp@0.13.0`.
2494
+ - Four container repositories with 14 writers were migrated by repeating their
2495
+ provisioning commands with unchanged settings and `--apply`: 2, 4, 4
2496
+ (operator image, `--cache go`) and 4 (operator image) writers. Every writer
2497
+ reported `writer_accepted`.
2498
+ - `--apply` and `--verify` of both client targets passed (`mcp_verified`), the
2499
+ open point of the pre-release record, and `--writer <name> --verify` passed
2500
+ for all 14 writers. Doctor reported no error.
2501
+
2502
+ Operator upgrade of the workstation from `0.12.1` to `0.13.0` on 2026-10-28
2503
+ from 20:47 UTC, with the same steps: no writer container ran at the start;
2504
+ five container repositories with 18 writers (2, 4, 4 with `--cache go`, 4 with
2505
+ base `dev`, 4 with `--cache uv`, three of them with operator images) reported
2506
+ `writer_accepted`; client-target `--apply` and `--verify` passed for
2507
+ `claude-code:user` and `codex:user` (`mcp_verified`, `skill_verified`, and
2508
+ `hook_verified` for the wake hook); `--writer <name> --verify` passed for all
2509
+ 18 writers. Doctor reported no error.
2510
+
2511
+ Live check of `shell: "sandboxed"` on both machines, the open point of the
2512
+ pre-release record. Two read-only profiles were added to each configuration,
2513
+ copies of the existing review profiles with `"shell": "sandboxed"`, one per
2514
+ provider family. Doctor reported `sandbox_unavailable` and
2515
+ `workspace_git_unavailable` as `ok`. A stdio driver against the installed
2516
+ server started one session per profile on the pi-session-mcp workspace (a plain
2517
+ checkout, not a linked worktree) and sent one prompt with five steps. All four
2518
+ sessions completed with the same results:
2519
+
2520
+ - `git log -1 --format=%h` through `bash` printed the checkout's head commit.
2521
+ - `touch sandbox-probe.txt && ls sandbox-probe.txt` succeeded in the sandbox;
2522
+ afterwards the file did not exist on the host and `git status` of the host
2523
+ checkout was clean.
2524
+ - `getent hosts example.com || echo NO_NETWORK` printed `NO_NETWORK`.
2525
+ - `echo HOME=$HOME` printed `HOME=/tmp/home`.
2526
+ - `read` of `/etc/hostname` returned `Path is outside the allowed read roots`.
2527
+
2528
+ Finding from these checks: the first workstation edit left out the required
2529
+ profile field `default`. Doctor then reported only `config_invalid` with the
2530
+ generic remediation and did not name the profile or the field; parsing the file
2531
+ with the package's configuration schema named both. With `"default": false`
2532
+ added, Doctor reported no error.
2533
+
2534
+ Not established for `0.13.0`: the sandbox on a host that restricts unprivileged
2535
+ user namespaces; Git inside the sandbox on a linked worktree in live use (the
2536
+ bubblewrap-gated tests cover it); the macOS upgrade; Level 3.
2537
+
2538
+ ### v0.13.1 pre-release acceptance
2539
+
2540
+ `v0.13.1` was accepted on 2026-10-29 from 06:40 to 06:48 UTC on its release
2541
+ candidate `89a366e`, on Linux (`x64`) with Node.js `26.12.1`, npm `12.2.1`,
2542
+ Codex CLI `0.162.1` and Claude Code `2.1.312`. Level 2 passed in the working
2543
+ tree and for the packed tarball, each with delivery off and with delivery on.
2544
+ Level 1 passed except `npm audit`. After the candidate, one lockfile-only
2545
+ commit moved the development-path `@hono/node-server` 2.1.1 → 2.1.5; Level 1
2546
+ was run again on it after `npm ci` (same counts). The packed package and the
2547
+ working-tree build that Level 2 used do not contain that package. Later commits
2548
+ on the release pull request change only this record.
2549
+
2550
+ The patch release ships #173, #176, #177, #179 and #180 under an unchanged MCP
2551
+ contract. The setup report schema is unchanged; a broken kept writer now
2552
+ reports its own code on its target instead of `writer_reconcile_failed`.
2553
+
2554
+ - Level 1 in a clean worktree of the candidate after `npm ci`: every command
2555
+ exited with `0`, except `npm audit`; `git status --short` printed nothing.
2556
+ - The test run, with `NODE_OPTIONS=--unhandled-rejections=strict`, reported
2557
+ 136 files, 3948 passed and 14 skipped, and no unhandled error.
2558
+ - `npm audit --omit=dev` exited with `1` and names only the known `undici`
2559
+ finding through `@earendil-works/pi-coding-agent` 1.4.0, now with eight
2560
+ advisories ([#120](https://github.com/plagor44-ux/pi-session-mcp/issues/120)).
2561
+ `npm audit` also named `@hono/node-server` 2.1.1 in the development path
2562
+ (GHSA-rmxm-3fg6-px4f), patched in the lockfile afterwards as above.
2563
+ - `npm pack` listed 922 files (tarball shasum
2564
+ `93f9c5bc9e268af7e0be5e395d97558ec801668a`, identical in two packs). A scan
2565
+ of the packed files for private names, hosts and paths found none; its only
2566
+ matches for `/home/` are the already redacted paths in this file and in the
2567
+ six `docs/evaluation/extension-functions-2026-10-17/cursor/` evidence files
2568
+ that earlier releases shipped unchanged.
2569
+ - Doctor reported `packageVersion` `0.13.1`. It exited with `2` because no
2570
+ configuration was set (`config_missing`).
2571
+ - Level 2 in the working tree: 160 of 160 checks passed with delivery off and
2572
+ 228 of 228 with `--events spool`.
2573
+ - Packed-tarball Level 2 from a fresh prefix: 160 of 160 with delivery off and
2574
+ 228 of 228 with `--events spool`. The install smoke from another fresh prefix
2575
+ reported `smoke_passed` with version `0.13.1`.
2576
+ - In every Level 2 run the real client registrations were unchanged, no process
2577
+ remained, the leak check passed and the disposable directories were removed.
2578
+ - Podman-gated writer tests on the candidate (Podman `6.1.4`): 7 of 7 passed.
2579
+ - Bubblewrap-gated sandbox tests (`test/sandbox-shell.bwrap.test.ts`, bubblewrap
2580
+ `0.13.1`): 12 of 12 passed, none skipped.
2581
+ - Review: #179, #180 and #181 had an independent review (same model family as
2582
+ the author) with no blocking findings; its follow-ups were fixed before the
2583
+ merge of #184. The final test-file split commit was checked by comparing the
2584
+ sorted test names before and after (464, identical).
2585
+
2586
+ Not established for `0.13.1`: a live wake-hook race, a live reconcile with a
2587
+ broken writer, client-target `--verify` through the installed package, which
2588
+ follows the upgrade; Level 3.
2589
+
2460
2590
  ### v0.13.0 pre-release acceptance
2461
2591
 
2462
2592
  `v0.13.0` was accepted on 2026-10-28 from 19:30 to 19:36 UTC on its release
@@ -105,8 +105,9 @@ This decision does not itself bump the package version or authorize publication.
105
105
  it passes, then require contained provider-free acceptance bound to wrapper,
106
106
  package version, image ID, Podman version, network and cache.
107
107
  6. **Credential lifetime.** Launcher checks every 60 seconds. Only selected
108
- OAuth tokens expired or within 2 minutes of expiry trigger host login
109
- warmup (invalid/missing expiry also triggers it); measured warmup refreshes
108
+ OAuth tokens expired or within 2 minutes of expiry (raised to 10 minutes
109
+ in [#142](https://github.com/plagor44-ux/pi-session-mcp/issues/142), see
110
+ [Execution modes](../execution-modes.md)) trigger host login warmup (invalid/missing expiry also triggers it); measured warmup refreshes
110
111
  expired/almost expired tokens only. It then re-copies credentials, with
111
112
  OAuth refresh tokens emptied. Direct verify disables refresh with
112
113
  `PI_WRITER_NO_CREDENTIAL_REFRESH=1`, makes no session/provider request and
@@ -1,8 +1,8 @@
1
1
  # ADR 0012: One registration with a leased writer pool
2
2
 
3
- **Status:** Accepted (2026-10-28, maintainer decision) for release 0.12.0;
4
- implementation tracked in
5
- [#157](https://github.com/plagor44-ux/pi-session-mcp/issues/157). Amends
3
+ **Status:** Accepted (2026-10-28, maintainer decision); implemented in
4
+ [#157](https://github.com/plagor44-ux/pi-session-mcp/issues/157) and released
5
+ in 0.12.0. Amends
6
6
  [ADR 0002](0002-embedded-pi-sdk.md) (container sessions are relayed to a Pi
7
7
  session in a writer process; host sessions stay embedded),
8
8
  [ADR 0008](0008-coding-profile-isolation.md) (adopts its option 4 in container
@@ -1,6 +1,6 @@
1
1
  # ADR 0013: Hardened read-only profiles
2
2
 
3
- **Status:** Accepted (2026-10-28). Amends
3
+ **Status:** Accepted (2026-10-28); released in 0.13.0. Amends
4
4
  [ADR 0006](0006-pi-extension-allowlist.md) and
5
5
  [ADR 0010](0010-read-only-extension-tools.md). Issue #169.
6
6
 
@@ -28,9 +28,11 @@ paths inside the allowed read roots:
28
28
  - the directory of each selected skill file, because the model loads skills
29
29
  with `read` and they live outside the workspace. If that directory equals or
30
30
  contains the operator's home directory, the configuration file's directory
31
- or the Pi agent directory (`~/.pi`), only the skill file itself is a root,
32
- so a catalog entry such as `./SKILL.md` next to the configuration does not
33
- expose the configuration.
31
+ (and, for a symlinked configuration file, its target's directory), `~/.pi`
32
+ or Pi's agent directory (`~/.pi/agent`, or `PI_CODING_AGENT_DIR`), only the
33
+ skill file itself is a root, so a catalog entry such as `./SKILL.md` next to
34
+ the configuration or Pi's credentials does not expose them. The real file of
35
+ a symlinked skill file is a root as well, so the model can read it.
34
36
 
35
37
  The server replaces the SDK's built-in definitions with definitions built from
36
38
  the root exports `createReadToolDefinition`, `createGrepToolDefinition`,
@@ -47,7 +47,7 @@ reconciled only when the registration still matches that binding. A changed
47
47
  release fails closed and cannot silently inherit or replace another release's
48
48
  registration.
49
49
 
50
- `pi_capabilities_get` projects the validated workspace and execution-profile maps plus the immutable configuration metadata captured while loading the file. It returns aliases plus the configured permission/provider/model/thinking intent, the configured extension specs and the selected skill aliases, sorted by alias, `configuration: { fingerprint, reloadPolicy: "restart-required" }` and `events: { delivery: "spool" | "off" }`. The fingerprint is SHA-256 over the exact loaded file bytes, including formatting; it is not a current-file freshness check. The projection makes no provider, authentication, filesystem, network, server-reachability, or catalog-state probe, so it cannot assert availability.
50
+ `pi_capabilities_get` projects the validated workspace and execution-profile maps plus the immutable configuration metadata captured while loading the file. It returns workspace aliases with their execution `mode` (plus `writers` and `defaultBase` for container workspaces) and profile aliases with the configured permission/provider/model/thinking intent, the configured extension specs, `grantedExtensionTools`, `shell` (`none` or `sandboxed`) and the selected skill aliases, sorted by alias, `configuration: { fingerprint, reloadPolicy: "restart-required" }` and `events: { delivery: "spool" | "off" }`. The fingerprint is SHA-256 over the exact loaded file bytes, including formatting; it is not a current-file freshness check. The projection makes no provider, authentication, filesystem, network, server-reachability, or catalog-state probe, so it cannot assert availability.
51
51
 
52
52
  ## Leased container writers
53
53
 
@@ -302,7 +302,7 @@ Create an unversioned JSON configuration file such as `pi-session-mcp.json`:
302
302
  }
303
303
  ```
304
304
 
305
- Configuration is strict. A profile has exactly `default`, `permissionProfile`, `provider`, `model`, and `thinkingLevel`, plus the optional `mcpServers`, `extensions` and `skills` described in [Installation](installation.md) and [Pi skills](skills.md); aliases follow the configured alias naming rules. At least one profile and exactly one default are required, and that default must be `read-only`. `thinkingLevel` is one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max`. An optional top-level `events` field, exactly `{ "delivery": "spool" }` or `{ "delivery": "off" }`, controls turn-event delivery for the Claude Code wake (`spool` enables it; `off`, the default when the field is absent, writes nothing); any other shape fails startup with `invalid_event_delivery`. Workspace paths resolve relative to the configuration file. Clients can select only configured aliases, never an arbitrary working directory.
305
+ Configuration is strict. A profile has exactly `default`, `permissionProfile`, `provider`, `model`, and `thinkingLevel`, plus the optional `mcpServers`, `extensions`, `grantedExtensionTools`, `shell` and `skills` described in [Installation](installation.md), [Pi skills](skills.md) and [ADR 0013](adr/0013-hardened-read-only-profiles.md); aliases follow the configured alias naming rules. At least one profile and exactly one default are required, and that default must be `read-only`. `thinkingLevel` is one of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max`. An optional top-level `events` field, exactly `{ "delivery": "spool" }` or `{ "delivery": "off" }`, controls turn-event delivery for the Claude Code wake (`spool` enables it; `off`, the default when the field is absent, writes nothing); any other shape fails startup with `invalid_event_delivery`. Workspace paths resolve relative to the configuration file. Clients can select only configured aliases, never an arbitrary working directory.
306
306
 
307
307
  Use placeholders until a locally available provider/model pair is known. Do not put keys, tokens, credential objects, headers, base URLs, or authentication paths in this file.
308
308
 
@@ -373,8 +373,8 @@ Claude Code enforces each tool's declared JSON Schema (`additionalProperties: fa
373
373
 
374
374
  ## Expected flow and lifecycle deadlines
375
375
 
376
- 1. Call `pi_capabilities_get` with `{}` and select explicit workspace and read-only execution-profile aliases from the returned config-derived lists.
377
- 2. Call `pi_session_start` with those aliases. The server resolves the configured provider/model through its shared `ModelRuntime` (a profile with extensions gets a fresh runtime for each session), loads and validates the profile's selected skills, checks existing local Pi authentication and availability, creates with explicit model/thinking/tools, and verifies the effective SDK result.
376
+ 1. Call `pi_capabilities_get` with `{}` and select a workspace alias and an execution-profile alias from the returned config-derived lists.
377
+ 2. Call `pi_session_start` with those aliases (without `executionProfile` the default profile is used; `base` applies only to a coding profile on a container workspace). The server resolves the configured provider/model through its shared `ModelRuntime` (a profile with extensions gets a fresh runtime for each session), loads and validates the profile's selected skills, checks existing local Pi authentication and availability, creates with explicit model/thinking/tools, and verifies the effective SDK result.
378
378
  3. Call `pi_session_prompt` with the returned `sessionId` and a read-only prompt. It returns after accepted preflight with a `turnId` in `running` state.
379
379
  4. Poll `pi_turn_get` with that `sessionId` and `turnId` until `completed`, `failed`, or `aborted`, with a deadline no longer than three minutes. There is no `pi_turn_wait` tool. With event delivery active (`events.delivery` is `spool` in `pi_capabilities_get`) and the wake hook installed, a Claude Code controller waits for the wake instead and reads the turn once.
380
380
  5. Call `pi_session_close` when the session is no longer needed.
@@ -27,7 +27,7 @@ and owners are:
27
27
  | `version_mismatch` | Package and lock versions differ; this is a warning and does not apply to an npm installation, which has no lockfile | `package version` |
28
28
  | `config_missing` | `PI_SESSION_MCP_CONFIG` is not set, or the file it names is absent | `configuration` |
29
29
  | `config_unreadable` | The supported configuration path cannot be read | `configuration` |
30
- | `config_invalid` | Production `loadConfig` rejects the configuration | `configuration` |
30
+ | `config_invalid` | Production `loadConfig` rejects the configuration. One check per schema issue location, at most five, sorted | `configuration:<location>`, a dotted path of schema field names, aliases and array indexes such as `configuration:executionProfiles.review.default`; an unknown key that is not a schema field name, and any other key that is not a valid alias, is shown as `<key>`, because it could be a path or a secret. `configuration` when the error has no location |
31
31
  | `workspace_missing` | A resolved configured workspace does not exist | validated workspace alias |
32
32
  | `workspace_not_directory` | A resolved workspace is not a directory | validated workspace alias |
33
33
  | `workspace_unreadable` | A resolved workspace cannot be read | validated workspace alias |
@@ -271,7 +271,7 @@ listed below; dynamic planned and MCP verification outcomes are listed explicitl
271
271
  | `writer_unchanged` | Provisioned settings already match |
272
272
  | `writer_settings_changed` | Existing writer settings or its rendered configuration differ from the current ones; no silent replacement, no acceptance and no registration change, and an apply is refused before the mode is written ([Isolation setup](isolation-setup.md)) |
273
273
  | `registration_divergent` | Writer registration is foreign or differs from its ownership record; it is retained and the writer stays in legacy launch mode |
274
- | `writer_reconcile_failed` | Unexpected reconciliation failure |
274
+ | `writer_reconcile_failed` | Unexpected reconciliation failure of shared setup state (configuration, ownership); a failure of one kept writer is reported on that writer's target with its own code, and the other writers are still reconciled |
275
275
  | `writer_operation_failed` | Unclassified lifecycle/orchestrator failure |
276
276
  | `hook_install_failed` | The wake hook step of a writer failed unexpectedly; other `hook_*` and `settings_*` codes are in [Client setup](client-setup.md#wake-hook) |
277
277
  | `container_profile_unsupported` | Profile or selected skills cannot be rendered safely in boundary |
package/docs/roadmap.md CHANGED
@@ -18,11 +18,19 @@ mean they are implemented or that their gates passed.
18
18
  0.12.0 together with #151 and #154, released the same day and installed with
19
19
  a live relayed coding session; 0.12.1 fixes client-target verify (#160).
20
20
  Both machines run 0.12.1, and #151 and #154 passed their live checks. The
21
- opt-in `--clean all` (#162) follows as an unreleased change.
22
- - 2026-10-28: [ADR 0013](adr/0013-hardened-read-only-profiles.md) (#169),
23
- implemented and unreleased: workspace-confined read tools for every read-only
24
- profile and the opt-in bubblewrap shell (`shell: "sandboxed"`). It changes the
25
- public contract and needs minor release 0.13.0.
21
+ opt-in `--clean all` (#162) shipped in 0.13.0.
22
+ - 2026-10-28: [ADR 0013](adr/0013-hardened-read-only-profiles.md) (#169):
23
+ workspace-confined read tools for every read-only profile and the opt-in
24
+ bubblewrap shell (`shell: "sandboxed"`), released in minor release 0.13.0
25
+ together with #162, #163, #165 and #166.
26
+ - 2026-10-29: the post-0.13.0 review findings in one pull request, unreleased:
27
+ stale waiter-lock reclamation in the wake hook
28
+ ([#179](https://github.com/plagor44-ux/pi-session-mcp/issues/179)), per-writer
29
+ reconcile failures ([#180](https://github.com/plagor44-ux/pi-session-mcp/issues/180))
30
+ and the split of `setup-writers.ts` and the largest test files
31
+ ([#181](https://github.com/plagor44-ux/pi-session-mcp/issues/181)). #120 still
32
+ waits for a Pi SDK release: 1.4.0 is the newest and still pins `undici` 8.10.2,
33
+ which `npm audit` now reports with eight advisories.
26
34
 
27
35
  The explicit 2026-10-17 user request adds a bounded development-only
28
36
  [token-footprint measurement](sprints/2026-10-17-token-footprint.md), following
@@ -146,9 +146,11 @@ files outside them through the model's read tools. Prefer query-style tools
146
146
  with free-form input is still a channel for whatever the workspace contains.
147
147
  The MCP server itself is trusted local code and is not confined.
148
148
  A skill directory that equals or contains the operator's home, the configuration
149
- file's directory or `~/.pi` is not a read root; only the skill file itself is,
150
- so a catalog entry such as `./SKILL.md` next to the configuration does not
151
- expose the configuration.
149
+ file's directory (or its symlink target's directory), `~/.pi` or Pi's agent
150
+ directory (`~/.pi/agent` or `PI_CODING_AGENT_DIR`) is not a read root; only the
151
+ skill file itself is, so a catalog entry such as `./SKILL.md` next to the
152
+ configuration or Pi's credentials does not expose them. The real file of a
153
+ symlinked skill file is a read root too, and only that file.
152
154
 
153
155
  Only local stdio tools are covered here. HTTP/SSE/OAuth transports, sampling,
154
156
  elicitation, roots negotiation, separate resource/prompt APIs and global extension
@@ -48,7 +48,8 @@ Pi Session MCP trusts the local process that launches and speaks MCP over inheri
48
48
  fresh tmpfs, so only the truncated output is available. `ls` omits entries
49
49
  that are symlinks pointing outside the read roots, without a notice. A skill
50
50
  directory that equals or contains the operator's home, the configuration
51
- directory or `~/.pi` contributes only the skill file as a read root. On
51
+ directory (or its symlink target's), `~/.pi` or Pi's agent directory
52
+ contributes only the skill file as a read root. On
52
53
  timeout or abort the server kills bubblewrap and the PID namespace takes every
53
54
  process of the sandbox with it. The start probe is cancelled with the start
54
55
  request. A granted research
@@ -40,7 +40,7 @@ records name the package version and the build they ran on, see
40
40
  ```json
41
41
  {
42
42
  "ok": true,
43
- "server": { "name": "pi-session-mcp", "version": "0.13.0" },
43
+ "server": { "name": "pi-session-mcp", "version": "0.13.1" },
44
44
  "configuration": {
45
45
  "fingerprint": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
46
46
  "reloadPolicy": "restart-required"
@@ -201,14 +201,16 @@ Public MCP errors are stable and sanitized. Their messages do not include inputs
201
201
  | `base_not_applicable` | Controller action: remove `base` unless starting a coding profile on a container workspace. No session was created; do not switch profiles to bypass policy. |
202
202
  | `writer_not_ready` | The writer launcher cannot establish current readiness; operator must run repository setup/acceptance. All refusal-server tools return this error. |
203
203
  | `container_runtime_unavailable` | The writer launcher found no usable rootless Podman; all refusal-server tools refuse work, with no host fallback. |
204
+ | `writer_fenced` | The writer launcher could not confirm that no container of the writer is still running; all refusal-server tools refuse work. Through the host relay a start reports this as `writer_unavailable` with reason `none_admitted`. |
204
205
  | `server_stopping` | Shutdown has begun, so a new session cannot be admitted. |
205
206
 
206
- Lifecycle errors include `unknown_workspace`, `unknown_session`, `session_running`, `prompt_rejected`, `prompt_timeout`, `abort_failed`, `abort_timeout`, and `turn_failed`. Timeout messages are stable: `Pi prompt preflight timed out` and `Pi abort timed out`.
207
+ Lifecycle errors include `unknown_workspace`, `unknown_session`, `unknown_turn`, `session_running`, `prompt_rejected`, `prompt_timeout`, `abort_failed`, `abort_timeout`, and `turn_failed`. Timeout messages are stable: `Pi prompt preflight timed out` and `Pi abort timed out`.
207
208
 
208
209
  Invalid execution-profile configuration prevents startup, so it cannot be an MCP response. In that case stderr receives a structured, sanitized `startup_failed` diagnostic with one of these stable codes; it contains no raw parser message or configuration path.
209
210
 
210
211
  | Startup diagnostic code | Meaning |
211
212
  | --- | --- |
213
+ | `config_path_required` | `PI_SESSION_MCP_CONFIG` is not set or empty; there is no default configuration file. |
212
214
  | `invalid_execution_profile_config` | The execution-profile configuration violates its invariants or strict shape, including `grantedExtensionTools` on a coding profile or a profile without extensions, more than 32 grants, duplicate, unsafe, MCP-reserved or built-in grant names, an unknown or duplicate selected skill alias, two selected skill aliases with the same path, or an invalid `skillCatalog` entry (including a malformed `builtin:` name). |
213
215
  | `invalid_thinking_level` | A configured thinking level is outside the supported enum. |
214
216
  | `invalid_execution_modes` | The execution modes file is invalid or unreadable, including an unknown alias, an unrecognized shape, or an invalid container profile selection. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-session-mcp",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Local stdio MCP server for controlled Pi coding-agent sessions",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -10,7 +10,7 @@ You control Pi worker sessions through the pi-session-mcp tools. You choose only
10
10
  ## 1. Discover first
11
11
 
12
12
  - Call `pi_capabilities_get` before anything else in a run. Use only the workspace and profile aliases it lists. Never invent an alias or pass a path.
13
- - Each profile lists `permissionProfile` (`read-only` or `coding`), `extensions`, `grantedExtensionTools` and `skills`. These are configuration intent only: grants name configured extension tools, not proven availability; `skills` names configured skill aliases, not proof that a session loaded the skill or that the model will read it.
13
+ - Each profile lists `permissionProfile` (`read-only` or `coding`), `extensions`, `grantedExtensionTools`, `shell` (`sandboxed` gives a read-only profile a network-free sandbox shell, `none` no shell) and `skills`. These are configuration intent only: grants name configured extension tools, not proven availability; `skills` names configured skill aliases, not proof that a session loaded the skill or that the model will read it.
14
14
  - Capabilities do not prove that a provider or model is reachable. A successful `pi_session_start` shows that the session was created with the selected provider, model and thinking level, and that local authentication, the extensions, external MCP servers and selected skills passed their start checks. It does not prove that the provider accepts requests: credentials, quota and network show only when a turn runs.
15
15
 
16
16
  ## 2. Scope each task
@@ -110,7 +110,7 @@ You integrate. Workers never integrate each other's changes. Resolve conflicts b
110
110
  - `abort_timeout` is not a successful abort. The turn may still be running or may finish normally. Decide an observation and cleanup budget before you abort, for example a fixed number of polling rounds within a few minutes. Poll `pi_turn_get` until the turn is terminal or the budget is spent, then close the session with `pi_session_close`. If the close fails or does not finish, stop using that workspace, treat it as unverified and report it. Never wait without a bound.
111
111
  - If `pi_session_start` fails, classify the error by its `code` alone. Never decide by the message, provider text or any other free text, and never infer a cause. Read [references/start-errors.md](references/start-errors.md) only now; it lists each known code in exactly one class. Any code not listed there is Unknown. Until the code is classified, do not retry and do not switch profiles. If the reference cannot be read, do not retry at all: report the code and stop that task. Always report the code.
112
112
  - `writer_unavailable` is a capacity/state signal, not a reason to switch profiles. Wait for sessions/cleanup or collect and finish writers; use its structured reason and counts as described in the error reference. A lost writer session must be closed and its work inspected before a fresh start.
113
- - If the pi-session-mcp tools are missing entirely, the server did not start. Its stderr names a `startup_failed` diagnostic (`invalid_execution_profile_config`, `invalid_thinking_level`, `invalid_execution_modes`, `invalid_event_delivery` or `event_spool_unavailable`). No MCP server is available; the operator must fix the configuration.
113
+ - If the pi-session-mcp tools are missing entirely, the server did not start. Its stderr names a `startup_failed` diagnostic (`config_path_required`, `invalid_execution_profile_config`, `invalid_thinking_level`, `invalid_execution_modes`, `invalid_event_delivery` or `event_spool_unavailable`). No MCP server is available; the operator must fix the configuration.
114
114
 
115
115
  ## 10. Close every session
116
116
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Load this file only after a `pi_session_start` call has failed. Classify the error by its `code` alone. Never decide by the message, provider text or any other free text, and never infer a cause. Each code below is in exactly one class.
4
4
 
5
- - Operator needed (do not retry and do not switch to another profile; report the code and stop that task): `unknown_execution_profile`, `unknown_workspace`, `workspace_mode_forbids_coding`, `unknown_provider`, `unknown_model`, `model_unavailable`, `thinking_level_unavailable`, `local_authentication_missing`, `execution_selection_mismatch`, `skill_load_failed`, `sandbox_unavailable`, `extension_not_installed`, `extension_version_mismatch`, `extension_tool_conflict`, `extension_tool_missing`, `external_mcp_no_tools`, `external_mcp_grant_tool_missing`, `external_mcp_activation_mismatch`, `writer_not_ready`, `container_runtime_unavailable`, `server_stopping`. Writer readiness needs repository setup and acceptance; runtime unavailability needs usable rootless Podman. The last code means the server is shutting down: a new server process is needed, not a retry.
5
+ - Operator needed (do not retry and do not switch to another profile; report the code and stop that task): `unknown_execution_profile`, `unknown_workspace`, `workspace_mode_forbids_coding`, `unknown_provider`, `unknown_model`, `model_unavailable`, `thinking_level_unavailable`, `local_authentication_missing`, `execution_selection_mismatch`, `skill_load_failed`, `sandbox_unavailable`, `extension_not_installed`, `extension_version_mismatch`, `extension_tool_conflict`, `extension_tool_missing`, `external_mcp_no_tools`, `external_mcp_grant_tool_missing`, `external_mcp_activation_mismatch`, `writer_not_ready`, `writer_fenced`, `container_runtime_unavailable`, `server_stopping`. Writer readiness needs repository setup and acceptance; a fenced writer needs the operator to confirm that its container is gone; runtime unavailability needs usable rootless Podman. The last code means the server is shutting down: a new server process is needed, not a retry.
6
6
  - Controller action (do not blindly retry or switch profiles; collect and reset the writer for uncollected work, or wait for or close the open coding session for a busy writer; resolve pool state, lost sessions or inapplicable base before a fresh start): `writer_uncollected`, `writer_busy`, `writer_unavailable`, `writer_session_lost`, `base_not_applicable`.
7
7
  - Transient (retry at most once after a pause, then report): `external_mcp_unavailable` (an external MCP server that cannot connect, times out or breaks the protocol), `extension_load_failed` (an invalid package, but also a start timeout), `local_authentication_unavailable` (local authentication could not be resolved within its deadline).
8
8
  - Unknown (report the code; at most one retry in a fresh session): `pi_session_creation_failed`. Any code not listed above is also unknown.