pi-session-mcp 0.8.0 → 0.8.2

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 (45) hide show
  1. package/.pi-session-mcp-cli/doctor.js +14 -7
  2. package/.pi-session-mcp-cli/override-lock.js +125 -0
  3. package/.pi-session-mcp-cli/setup-platform.js +195 -0
  4. package/.pi-session-mcp-cli/skill-customize.js +131 -46
  5. package/.pi-session-mcp-cli/skill-library.js +72 -4
  6. package/CHANGELOG.md +159 -0
  7. package/CONTRIBUTING.md +5 -3
  8. package/README.md +5 -3
  9. package/dist/doctor.d.ts +3 -0
  10. package/dist/doctor.js +14 -7
  11. package/dist/override-lock.d.ts +34 -0
  12. package/dist/override-lock.js +125 -0
  13. package/dist/pi-adapter.d.ts +6 -4
  14. package/dist/sdk-pi-adapter.js +28 -5
  15. package/dist/session-registry.d.ts +8 -6
  16. package/dist/session-registry.js +3 -2
  17. package/dist/setup-ownership.d.ts +4 -1
  18. package/dist/setup-ownership.js +6 -3
  19. package/dist/setup-skills.d.ts +46 -1
  20. package/dist/setup-skills.js +349 -78
  21. package/dist/setup.js +21 -4
  22. package/dist/skill-customize.d.ts +19 -1
  23. package/dist/skill-customize.js +131 -46
  24. package/dist/skill-library.d.ts +46 -1
  25. package/dist/skill-library.js +72 -4
  26. package/docs/acceptance.md +747 -26
  27. package/docs/adr/0007-profile-skill-selection.md +11 -0
  28. package/docs/architecture.md +1 -1
  29. package/docs/client-setup-design.md +157 -24
  30. package/docs/client-setup.md +38 -7
  31. package/docs/doctor-design.md +1 -1
  32. package/docs/installation.md +8 -2
  33. package/docs/pi-extensions-design.md +11 -0
  34. package/docs/releasing.md +25 -10
  35. package/docs/reviews/2026-10-13-post-0.8.1-audit.md +393 -0
  36. package/docs/roadmap.md +127 -0
  37. package/docs/skills.md +173 -16
  38. package/docs/sprints/2026-10-13-s1-correctness.md +355 -0
  39. package/docs/sprints/2026-10-13-s2-evidence.md +431 -0
  40. package/docs/sprints/2026-10-13-s3-live-usage.md +267 -0
  41. package/docs/sprints/2026-10-13-s4-decision-inputs.md +241 -0
  42. package/docs/threat-model.md +3 -3
  43. package/docs/tool-contracts.md +20 -2
  44. package/package.json +1 -1
  45. package/skills/pi-session-orchestration/SKILL.md +8 -4
@@ -16,6 +16,16 @@ Provider-free tests exercise the real Pi SDK and real stdio child processes with
16
16
  a scripted model. They do not establish live client or model acceptance. State
17
17
  only what was run.
18
18
 
19
+ Targeted live checks are not a level. The [Pi extension live
20
+ check](#pi-extension-live-check) and the [multi-session skill
21
+ acceptance](#multi-session-skill-acceptance) use a real provider and model on one
22
+ path with one or two sessions: the first drives the server with a scripted
23
+ client, the second with one real controller. They are not a Level 3 cycle,
24
+ do not count towards its [gate](#gate) and do not replace it. A record of one
25
+ of them never says that Level 3 passed. What a package version, the MCP tool
26
+ contract and a setup report `schemaVersion` identify is defined in [tool
27
+ contracts](tool-contracts.md#versions).
28
+
19
29
  ## Level 1: repository checks
20
30
 
21
31
  Run on a clean checkout of the exact source under test:
@@ -24,7 +34,7 @@ Run on a clean checkout of the exact source under test:
24
34
  npm ci
25
35
  npm run typecheck
26
36
  npm run build:cli
27
- npm test
37
+ NODE_OPTIONS=--unhandled-rejections=strict npm test
28
38
  npm run build
29
39
  npm audit
30
40
  git diff --check
@@ -316,6 +326,11 @@ external MCP grants, and client restart or resume.
316
326
  A narrower live check can cover a single path. It must state its scope and does
317
327
  not count as a ten-task cycle.
318
328
 
329
+ This applies to the two-session records below: the extension live check
330
+ started two sessions and the multi-session acceptance drives two concurrent
331
+ sessions from one controller. Both are targeted evidence, not a Level 3 cycle,
332
+ and no number of such runs adds up to the gate.
333
+
319
334
  ## Pi extension live check
320
335
 
321
336
  Manual, on a machine with Pi, `pi-cursor-sdk@0.5.3` and a stored Cursor key. Run it from a working tree (`npm run build`, then `node dist/main.js`) with a temporary configuration, passed through `PI_SESSION_MCP_CONFIG`, whose profile names `"extensions": ["npm:pi-cursor-sdk@0.5.3"]` and a Cursor model from Pi's catalog.
@@ -328,6 +343,9 @@ Manual, on a machine with Pi, `pi-cursor-sdk@0.5.3` and a stored Cursor key. Run
328
343
 
329
344
  Record date, source commit, versions and outcome under Status. No secret, path or prompt content goes into the record.
330
345
 
346
+ This check is targeted. Its two parallel sessions show that the extension path
347
+ works for the recorded build, provider and model. They are not a Level 3 cycle.
348
+
331
349
  ## Multi-session skill acceptance
332
350
 
333
351
  A targeted live check for profile skill selection ([skills](skills.md)) and for
@@ -346,18 +364,108 @@ Pi Session MCP tools; the script never does.
346
364
  from the harness of `cc810c9` on, a SHA-256 over every built module in
347
365
  `dist/`; `run` refuses a changed build.
348
366
  - Configuration: `prepare --base-config <operator config> --from-profile
349
- <alias>` copies only provider, model and thinking level of one working profile
350
- without extensions or MCP servers into a temporary configuration with two
351
- profiles: `accept-read` (default, `read-only`, skill `review`) and
352
- `accept-code` (`coding`, skills `implementation` and `handshake`). From the
367
+ <alias>` copies only provider, model and thinking level of the one explicitly
368
+ selected profile into a run configuration with the profiles `accept-read` (default, `read-only`, skill `review`) and
369
+ `accept-code` (`coding`). From the Sprint 2 harness (#68) on, `accept-code`
370
+ selects exactly `implementation` and is used for every task except `slug`,
371
+ and a second coding profile `accept-code-handshake` selects `implementation`
372
+ and `handshake` and is used only for the `slug` session; before, `accept-code`
373
+ carried both skills for every task. From the
353
374
  harness of `3f98104` on, all three are `builtin:` references: the two worker
354
375
  skills ship with the candidate, and the `handshake` skill sits in the
355
376
  override directory `skills/` next to the run configuration, so the run also
356
377
  exercises library resolution. The `handshake` skill is generated per run and
357
- holds a random token that no controller prompt contains.
358
- - Fixtures: four small synthetic git repositories per client (`slug`, `stats`,
359
- `wait`, `range`), each a separate workspace alias (`cc-*` for Claude Code,
360
- `cx-*` for Codex). Both clients use the same configuration and build.
378
+ holds a random token that no controller prompt contains. A profile with
379
+ `mcpServers` is always rejected. A profile with `extensions` is rejected
380
+ unless `--with-extensions` is given; with it, `prepare` also copies exactly
381
+ that profile's extension allowlist (1 to 8 distinct exact
382
+ `npm:<name>@<version>` pins) into every run profile and installs nothing.
383
+ `--with-extensions` on a profile without extensions is rejected. Nothing else
384
+ is copied: the run has its own workspaces and skills.
385
+ - Working directory: `--work-dir` (default `~/.cache/pi-session-mcp-acceptance`)
386
+ must not be inside a temporary directory (the system temporary directory,
387
+ `/tmp`, `/var/tmp` or `/dev/shm`), because Codex refuses helper binaries
388
+ there.
389
+ - Fixtures: five small synthetic git repositories per client (`slug`, `stats`,
390
+ `wait`, `range` and, from the Sprint 3 harness (#71) on, `review`), each a
391
+ separate workspace alias (`cc-*` for Claude Code, `cx-*` for Codex). `review`
392
+ holds a finished, frozen implementation that only the read-only reviewer of
393
+ `trio` uses. Both clients use the same configuration and build.
394
+ - Fixture baselines: when it creates a fixture, `prepare` stores its initial
395
+ commit and a manifest of its files (path, type, mode, SHA-256; without
396
+ `.git/`) under the run's private directory, never inside the worker's
397
+ workspace. `run` refuses a fixture that differs from its baseline before the
398
+ launch.
399
+ - Bound resources: `prepare` records a digest of the candidate build, the
400
+ installed Claude Code controller skill copy, the candidate skill that the
401
+ Codex controller's link points to, the worker skills (`implementation`,
402
+ `review`), the `handshake` skill, the override directory, the run
403
+ configuration, the Claude MCP configuration, the fixture baselines, the
404
+ harness itself, and the `pi-session-orchestration` copies in the operator's
405
+ home (`~/.claude/skills` and `~/.agents/skills`, recorded as missing when
406
+ absent). `run` rechecks all of them before the launch and again after the
407
+ run. A change before the launch refuses the run; a change after it fails the
408
+ result with `resourcesChanged`. From the Sprint 2 harness (#66, #67) on it
409
+ also binds, under path-free names: per allowlisted extension the tree of its
410
+ real package root (`extension:<name>`) and the whole npm installation of
411
+ Pi's agent directory, with dependencies, `package.json` and lockfile
412
+ (`extensionNpmInstallation`, `none` without extensions); and every Codex
413
+ skill source besides the run's own link: `$CODEX_HOME/skills` with the
414
+ bundled `.system` skills (`codexHomeSkills`), all of `~/.agents/skills`
415
+ (`homeAgentsSkills`), `/etc/codex/skills` (`etcCodexSkills`) and the
416
+ `.agents/skills` of every ancestor of the Codex controller's directory
417
+ (`codexAncestorSkills`, up to `/`). These extension, Codex source and
418
+ candidate skill digests (the controller skill and both worker skills) walk a
419
+ tree without following links, record every link's text, and for a link
420
+ whose real path lies outside the bound root also bind what it leads to (the
421
+ file's bytes, or the same digest of the target directory, recursively); a
422
+ link that stays inside the root needs only its text. Each real directory is
423
+ digested once, so link cycles end, and at most 200,000 entries are read. A
424
+ value of `unreadable` or `tooLarge` means that a resource cannot be bound
425
+ completely. For every key, composed ones included, `prepare` then refuses and
426
+ names the key, and `run` refuses before the launch with `resourcesUnbound`.
427
+ `missing`, `none`, `notDirectory`, `unset` and a dangling top-level link are
428
+ determinate values and stay allowed. The other resources keep the plain tree
429
+ digest. `prepare` resolves Pi's
430
+ agent directory (`PI_CODING_AGENT_DIR`, else `~/.pi/agent`) and `CODEX_HOME`
431
+ (else `~/.codex`) once and records both only in the run's private data; they
432
+ never appear in a result or the evidence.
433
+ - Home controller skills: Claude Code prefers a personal skill over a project
434
+ skill of the same name. With `--setting-sources project,local`, as the
435
+ harness starts it, Claude Code `2.1.296` listed only the project copy when a
436
+ different personal copy existed (observed on 2026-10-12 with a marker skill);
437
+ without that flag the personal copy shadowed the project copy. Re-check this
438
+ when the client version changes. Codex's precedence between its home skills
439
+ and the run's repository skill is not established, so a Codex run is refused
440
+ while any bound Codex skill source (`$CODEX_HOME/skills`,
441
+ `~/.agents/skills`, `/etc/codex/skills` or an ancestor's `.agents/skills`)
442
+ holds a controller skill whose resolved content differs from the
443
+ candidate's. A controller skill is a directory named
444
+ `pi-session-orchestration` or one whose `SKILL.md` frontmatter declares that
445
+ `name:`. The frontmatter is read as a YAML block mapping whose top-level keys
446
+ are those at the indentation of its first content line; `name` may be a plain
447
+ or quoted scalar, and a ` #` comment outside quotes is ignored. Any other
448
+ form (a flow mapping or sequence, a bare scalar, a dedent or tab
449
+ indentation, a block or multi-line scalar, malformed quoting, a duplicate
450
+ `name`, unclosed frontmatter), and a `SKILL.md` that is not a regular file,
451
+ make the skill indeterminate, so its source counts as differing. Only the
452
+ first 16 KiB of a `SKILL.md` are read, after its type was checked. The
453
+ bounded search includes hidden directories such as `.system` and
454
+ follows links. An equal copy, also behind a link, or none is allowed; a
455
+ source that cannot be searched completely refuses the run. Skills that Codex
456
+ might load by other means, such as other file names or plugin caches, are
457
+ not covered. Before the Sprint 2 harness only
458
+ `~/.agents/skills/pi-session-orchestration` was checked.
459
+ - Launch record and failed analysis: `run` records the launch once before the
460
+ controller starts, so an attempt that ends without a result is never repeated
461
+ silently. If the analysis after the controller fails, the result is recorded
462
+ as `analysisFailed` and never passes, and the run's own processes are still
463
+ terminated. A `SIGINT` or `SIGTERM` that the harness handles during the
464
+ analysis records the result at once as `harnessAborted` and `analysisFailed`,
465
+ keeps the supervision's flags (`timedOut`, `spawnFailed`, `unterminated`),
466
+ terminates the run's recorded processes and exits with 1. A harness that ends
467
+ without handling a signal (for example `SIGKILL`, `SIGHUP` or out of memory)
468
+ writes no result; `evidence` lists its launch as one without a result.
361
469
  - Controller skill: from the harness of `3f98104` on, `prepare` installs the
362
470
  Claude Code controller skill the way an operator does, with the candidate's
363
471
  `pi-session-mcp-setup --apply --target claude-code:project:pi-session-mcp` in
@@ -367,7 +475,10 @@ Pi Session MCP tools; the script never does.
367
475
  the shipped skill. Codex installs skills only in the user's home, which the
368
476
  run must not change, so the Codex controller gets one run-scoped symbolic link
369
477
  in `.agents/skills` of its directory. Earlier runs linked both. No global
370
- skill directory changes.
478
+ skill directory changes. From the Sprint 2 harness (#67) on, the evidence
479
+ records per client the kind of controller skill, `installed` for Claude Code
480
+ and `linked` for Codex, with its tree digest and without paths
481
+ (`controllerSkills`).
371
482
  - Clients: Claude Code runs as `claude -p` with `--mcp-config`,
372
483
  `--strict-mcp-config`, `--setting-sources project,local`,
373
484
  `--permission-mode dontAsk` and an `--allowedTools` list of the eight tools
@@ -375,34 +486,139 @@ Pi Session MCP tools; the script never does.
375
486
  `codex exec --ignore-user-config --sandbox read-only` with the server
376
487
  defined through `-c mcp_servers.pi-candidate.*` and the three per-tool
377
488
  approvals from [client setup](client-setup.md#run-codex-without-prompts).
378
- Neither run changes a persistent registration, `HOME` or `CODEX_HOME`, and
379
- both use the existing authentication.
489
+ The harness changes neither a persistent registration, `HOME` nor the
490
+ contents of `CODEX_HOME`, and both runs use the existing authentication.
491
+ Codex itself can install its bundled `.system` skills into
492
+ `$CODEX_HOME/skills` on its first start after an upgrade, or create that
493
+ directory in a fresh `CODEX_HOME`. Because those skills are bound, such a
494
+ change invalidates the prepared run for both clients; it fails safe and never
495
+ passes. After a Codex upgrade, start Codex once with the same `CODEX_HOME`
496
+ before `prepare`. From the Sprint 2
497
+ harness (#66, #67) on, the Codex controller runs with exactly the
498
+ `CODEX_HOME` that `prepare` recorded, whatever the launching environment
499
+ holds, and the server of both clients receives the recorded Pi agent
500
+ directory as `PI_CODING_AGENT_DIR`, so the bound extension directory is the
501
+ one the server loads from.
502
+ - Time limit: `run --timeout-min` takes a number above 0 and at most 180
503
+ (default 25). After the limit the harness sends `SIGTERM` to the client's
504
+ process group and waits up to 10 seconds. It then sends `SIGKILL` to that
505
+ group and to the recorded processes of the run whose PID and start time still
506
+ match, never by name. A process that is only found by its working directory
507
+ inside the run is reported, not killed. The run is complete when the client
508
+ exits and a bounded drain of its output has finished; a client that the
509
+ escalation cannot reap still ends the wait and is marked `unterminated`. The
510
+ result classifies `timedOut`, `spawnFailed`, `harnessAborted` (`SIGINT` or
511
+ `SIGTERM` to the harness) and `analysisFailed`; the CLI exits 1 for each of
512
+ them. The original result of a client
513
+ and scenario is written once; a second `run` for the same pair is refused.
380
514
 
381
515
  ### Scenarios
382
516
 
383
- Each client runs two invocations, one per scenario:
517
+ Each client runs one invocation per scenario: `parallel` and `abort`, and from
518
+ the Sprint 3 harness (#71) on also `trio`:
384
519
 
385
520
  | Scenario | What the controller does | What is checked |
386
521
  | --- | --- | --- |
387
- | `parallel` | Capabilities first; two sessions of `accept-code` on `slug` and `stats`; both first turns started before waiting; one follow-up in the `slug` session that adds a test and completes the handshake from the worker's skills; own verification; close both | Candidate version and configuration fingerprint seen through capabilities; `skills` of `accept-code`; first turns overlap by the server's `startedAt` and `completedAt`; follow-up completed; tests pass and only allowed files changed; handshake file holds the token although no prompt contained it |
388
- | `abort` | Two sessions on `wait` (a bounded `sleep 120` command) and `range` (a bounded `sleep 45`, then the change); abort `wait` about 15 seconds after both turns started, while `range` runs; verify and close both | Every abort result is `ok` (an `abort_timeout` stays on record even after a retry); the first successful abort comes before `pi_turn_get` shows the `wait` turn `aborted`, and both before its session is closed; its abort time lies inside the running interval of `range`; `range` completed and verified; at the end of the run no late file exists and no worker `sleep` remains |
522
+ | `parallel` | Capabilities first; a session of `accept-code-handshake` on `slug` and one of `accept-code` on `stats` (before the Sprint 2 harness: `accept-code` for both); both first turns started before waiting; one follow-up in the `slug` session that adds a test and completes the handshake from the worker's skills; own verification; close both | Candidate version and configuration fingerprint seen through capabilities; `skills` of both coding profiles and the profile of each session; first turns overlap by the server's `startedAt` and `completedAt`; follow-up completed; tests pass and only allowed files changed; handshake file holds the token although no prompt contained it |
523
+ | `abort` | Two sessions of `accept-code` on `wait` (a bounded `sleep 120` command) and `range` (a bounded `sleep 45`, then the change); abort `wait` about 15 seconds after both turns started, while `range` runs; verify and close both | Every `pi_session_abort` call of the transcript is `ok` and targets the `wait` session (an `abort_timeout`, an unknown session id or an abort on `range` stays on record and fails, also after a retry); the first successful abort comes before `pi_turn_get` shows the `wait` turn `aborted`, and both before its session is closed; its abort time lies inside the running interval of `range`; `range` completed and verified; at the end of the run no late file exists and no worker `sleep` remains |
524
+ | `trio` | Capabilities first; three sessions whose first turns start in the order `review`, `slug`, `wait`, all before waiting for any: `accept-read` on `review` (an enumerated read-only review of the frozen `review` fixture, one finding per exported function with a line reference), `accept-code` on `slug` (a bounded `sleep 45`, then the change, only in `src/slug.js`) and on `wait` (a bounded `sleep 120`); abort `wait` about 5 seconds after its turn was accepted, while `slug` and `review` run; own verification of `slug`; confirm `review` changed nothing; close all three; no handshake | Candidate version and configuration fingerprint seen through capabilities; three sessions, each on its expected alias and profile; `accept-read` offers exactly `review` and only the `review` session used it; all three first turns overlap; every `pi_session_abort` call is `ok` and on `wait`, the first successful abort comes before `wait` is seen `aborted`, both before close; the abort lies inside the running intervals of both `slug` and `review`; `slug` and `review` completed; `slug` tests pass; the `review` fixture is byte-identical in working tree, index and `HEAD`, with no empty directory; `wait` leaves no late file; no worker `sleep` remains |
389
525
 
390
526
  ### Independent checks
391
527
 
392
528
  - The script watches `/proc` during the run and records every process of the
393
529
  controller tree, every server of this run (entry point and configuration
394
530
  path) and every process whose working directory lies inside the run, by PID
395
- and start time. After the controller exits and the server's 15-second
396
- shutdown bound has passed, none of them may remain.
531
+ and start time. A later sighting of a process never lowers its role or drops
532
+ its fixture: an exiting server, or a zombie its client has not reaped yet,
533
+ has no command line, environment or working directory left to read, and a
534
+ descendant that outlives the client keeps the ownership that makes it the
535
+ run's own to terminate. After the controller exits and the server's
536
+ 15-second shutdown bound has passed, none of them may remain.
397
537
  - From the controller transcript it extracts only tool names, aliases, states,
398
538
  timestamps and counts. It scans every Pi Session MCP result, with
399
539
  `assistantText` removed, for local paths, the token and credential markers,
400
540
  and counts mentions in `assistantText` separately.
401
- - Fixture oracles run on the workspace after the controller exits: `node
402
- --test` and `git status` per fixture. Every changed file must have been last
403
- written during a worker turn of its task's session, and `HANDSHAKE.txt`
404
- during the follow-up turn, by the server's turn timestamps. This catches a
405
- write outside the worker turns, not one during them.
541
+ - Scope: after the controller exits, each fixture is compared with its
542
+ baseline in three independent ways: the working tree against the manifest
543
+ (including untracked, ignored, deleted, renamed and mode-changed files), the
544
+ index against the base commit, and `HEAD` against the base commit. A change
545
+ that a worker committed therefore counts. The union of changed paths must lie
546
+ inside the files allowed for that task. A missing or unreadable baseline,
547
+ `.git` or base commit fails the check; it is never read as clean. Git runs
548
+ pinned to the fixture with hooks and `fsmonitor` switched off.
549
+ - Business checks: besides the fixture's own `node --test`, the harness runs
550
+ its own cases per fixture (`slug`, `stats`, `range`) against the worker's
551
+ module in a separate `node` process, because a worker could have edited the
552
+ tests it is judged by. For `stats` one case passes a frozen input array, so
553
+ an implementation that sorts its input in place fails. The fixture's tests
554
+ and the business checks must both pass.
555
+ - Every changed file must have been last written during a worker turn of its
556
+ task's session, and `HANDSHAKE.txt` during the follow-up turn, by the
557
+ server's turn timestamps. This catches a write outside the worker turns, not
558
+ one during them.
559
+ - Acceptance verdict: each result carries `acceptance` with `passed` and a
560
+ list of `failures`, computed mechanically from the checks. `passed` is true
561
+ only when the list is empty. A failure code is listed when any of these
562
+ does not hold:
563
+ - the controller exit code is 0 (`controllerExit`), neither `timedOut`,
564
+ `spawnFailed` nor `harnessAborted` is set, and the analysis finished
565
+ (`analysisFailed`);
566
+ - every bound resource was completely readable when recorded and after the
567
+ run (`resourcesUnbound`);
568
+ - no bound resource changed after the run (`resourcesChanged`), and for a
569
+ reanalysis no resource or fixture differs from the state recorded at the
570
+ end of the run (`stateChangedSinceRun`);
571
+ - at least one server of the run was observed (`noServerObserved`) and no
572
+ process of the run remains (`residualProcesses`);
573
+ - the controller called `pi_capabilities_get` first (`capabilitiesNotFirst`),
574
+ saw the candidate version and configuration fingerprint
575
+ (`candidateNotConfirmed`), saw exactly the skill `implementation` on
576
+ `accept-code` and exactly `implementation` and `handshake` on
577
+ `accept-code-handshake`, and only the `slug` session used
578
+ `accept-code-handshake` while every other session used `accept-code`
579
+ (`workerSkills`; before the Sprint 2 harness: exactly `implementation` and
580
+ `handshake` on `accept-code`). In `trio` there is no handshake: `slug` and
581
+ `wait` use `accept-code`, `accept-read` offers exactly `review`, and only the
582
+ `review` session may use `accept-read`; in `parallel` and `abort` no session
583
+ uses `accept-read`;
584
+ - the structural leak scan found nothing (`structuralLeaks`), the token
585
+ appears nowhere it must not (`tokenExposed`), and no worker prompt or
586
+ controller action touched a private marker (`privateAccess`);
587
+ - at least two sessions started and all were closed (`sessionsNotClosed`);
588
+ - `parallel`: both first turns completed (`firstTurnsNotCompleted`), they
589
+ overlapped (`noOverlap`) and the follow-up completed
590
+ (`followUpNotCompleted`);
591
+ - `abort`: the `wait` turn ended `aborted` after only successful aborts
592
+ (`abortFailed`), every abort call on the `wait` session
593
+ (`offTargetAbort`), in the required order and before its session closed
594
+ (`abortOrder`), and `range` completed with the abort inside its running
595
+ interval (`neighborNotRunningDuringAbort`);
596
+ - `trio`: exactly three sessions started (`sessionsNotStarted`), each on its
597
+ expected workspace alias and profile (`sessionAssociation`); the `slug` and
598
+ `review` first turns completed (`firstTurnsNotCompleted`) and all three
599
+ first turns overlapped (`noOverlap`); the `wait` turn ended `aborted` after
600
+ only successful aborts (`abortFailed`) and only on `wait`
601
+ (`offTargetAbort`), in the required order and before
602
+ close (`abortOrder`), with the abort inside the running intervals of both
603
+ `slug` and `review` (`neighborsNotRunningDuringAbort`); the `review` fixture
604
+ is unchanged in working tree, index and `HEAD`, `HEAD` is still its base
605
+ commit, and no empty directory appeared (`review:readOnly`); the `slug`
606
+ task of `trio` may change only `src/slug.js`, while `test/slug.test.js`
607
+ and `HANDSHAKE.txt` stay allowed in `parallel` only. The read-only check
608
+ compares the end state with the baseline, so a write reverted before the
609
+ end, a `git stash`, new refs or branches and directory-mode changes are not
610
+ seen; the read-only profile is the actual guard;
611
+ - per fixture: only allowed changes (`<task>:changes`), every change written
612
+ during a worker turn (`<task>:attribution`), fixture tests and business
613
+ checks passing (`<task>:tests`), for `slug` in `parallel` the added test
614
+ and the handshake (`slug:followUp`), for `review` the read-only invariance
615
+ (`review:readOnly`) instead of tests, for `wait` no late file
616
+ (`wait:lateFile`),
617
+ and an oracle for every task of the scenario (`oracleMissing`).
618
+ - Liveness observation: for each turn of a session, `turnLiveness` records the
619
+ number of `pi_turn_get` polls that saw the turn `running` and whether
620
+ `updatedAt` exceeded `startedAt` while it was running. This is an
621
+ observation, not a pass criterion.
406
622
  - Controller writes are limited by the client restrictions: the Codex
407
623
  controller runs in a read-only sandbox, and the Claude Code controller has no
408
624
  write or edit tool, although its allowed `git -C` could still change a
@@ -413,14 +629,57 @@ Each client runs two invocations, one per scenario:
413
629
  private directory or its files; this is a marker check, not a sandbox.
414
630
  - The harness records its own SHA-256 at `prepare` and refuses to run or
415
631
  re-evaluate a run with another version.
632
+ - `reanalyze` recomputes the transcript analysis and the checks of a finished
633
+ run and never overwrites the original result: it writes a numbered
634
+ reanalysis file. At the end of each run the harness records the state of
635
+ the fixtures (working tree, `HEAD`, index) and of the bound resources. If a
636
+ fixture or a bound resource differs from that state, the reanalysis fails
637
+ with `stateChangedSinceRun`.
416
638
  - `evidence` writes one sanitized JSON record and refuses to write a local path
417
- or the token. Transcripts and the configuration stay in the run's private
418
- directory and are never published.
419
-
420
- A controller that reports success does not count; only the checks above do.
639
+ or the token. It lists the original results and the reanalyses separately,
640
+ lists every launch with whether it left a result, and includes the extension
641
+ names and versions, the resource digests, the profiles and, from the Sprint 2
642
+ harness on, the controller skill kinds and digests.
643
+ Transcripts and the configuration stay in the run's private directory and
644
+ are never published.
645
+
646
+ A controller that reports success does not count; only the checks above and
647
+ the `acceptance` verdict derived from them do.
421
648
  If a client or its authentication is not available, record that client's part
422
649
  as blocked.
423
650
 
651
+ ### Method limits of earlier records
652
+
653
+ Records made with the harness before it was hardened in #53 have these method
654
+ limits, which that change removed:
655
+
656
+ - The scope check used `git status`, which does not show a change that a worker
657
+ had already committed.
658
+ - The business checks ran the fixture tests inside the worker's workspace,
659
+ which a worker could have modified.
660
+ - Only the build, the harness and the bytes of the configuration file (through
661
+ its fingerprint) were bound to the run. The installed controller skill, the
662
+ contents of the selected worker skills and the fixture baselines were not.
663
+ - After the time limit the harness sent `SIGTERM` and then waited for the
664
+ client to close without a bound. A hang would have shown as a hang, not as a
665
+ pass.
666
+
667
+ Records made with the harness before Sprint 2 (#66, #67, #68) have these
668
+ further method limits:
669
+
670
+ - Pi extensions were bound by name and version only, not by the package
671
+ contents the server loaded, and the run's server did not receive the agent
672
+ directory explicitly.
673
+ - For Codex, only `~/.agents/skills/pi-session-orchestration` was checked;
674
+ `$CODEX_HOME/skills`, `/etc/codex/skills`, other home skills and ancestor
675
+ `.agents/skills` were neither bound nor excluded, and the controller
676
+ inherited `CODEX_HOME` from the launching environment.
677
+ - The `handshake` skill was offered to every task's worker; this is how the
678
+ v0.8.1 Codex `abort` run's worker could apply it to an unrequested file.
679
+
680
+ These limits do not show that any recorded result was wrong. The records stay
681
+ as recorded; a new run gets a new record.
682
+
424
683
  ## Evidence rules
425
684
 
426
685
  - Record only sanitized evidence: statuses, booleans, counts, durations,
@@ -436,6 +695,13 @@ as blocked.
436
695
 
437
696
  ## Status
438
697
 
698
+ Targeted records below, the Pi extension live check and the multi-session
699
+ skill acceptance with one or two concurrent sessions, are not Level 3 cycles
700
+ even where they used a real controller or a real model. The wording "passed all
701
+ three levels" refers to earlier private cycles only; the full ten-task Level 3
702
+ cycle has not been repeated on Pi SDK `1.x`. This note adds no result and
703
+ changes none.
704
+
439
705
  Release notes state which levels were run for a release and what was not
440
706
  covered. Pi Session MCP has passed all three levels in earlier private cycles. The
441
707
  live two-client acceptance has not yet been repeated on a build with Pi SDK
@@ -837,6 +1103,10 @@ These runs do not cover macOS, Codex skill discovery from the user's home
837
1103
  controller read it from there), the extension profile path live, or more than
838
1104
  two concurrent sessions.
839
1105
 
1106
+ The multi-session runs above were made with the earlier harness. Its
1107
+ [method limits](#method-limits-of-earlier-records) apply to them. They do not
1108
+ show that any of these results was wrong.
1109
+
840
1110
  Before its release, `v0.8.0` passed Level 1 and the working-tree Level 2 on
841
1111
  its release candidate `6d197a0` on Linux (`x64`), with Node.js `26.11.1`, Codex
842
1112
  CLI `0.162.1` and Claude Code `2.1.296`, on 2026-10-12:
@@ -854,3 +1124,454 @@ CLI `0.162.1` and Claude Code `2.1.296`, on 2026-10-12:
854
1124
  - Apart from the version, the candidate's sources equal the merge of #48,
855
1125
  whose final candidate `0ebbaa0` passed the multi-session skill acceptance
856
1126
  recorded above.
1127
+
1128
+ After its release, `v0.8.0` passed Level 1 on a fresh clone of its tag and
1129
+ Level 2 in three variants. The release was published on 2026-10-12. The release
1130
+ notes do not date the individual checks, and they name no operating system for
1131
+ the local runs.
1132
+ - Source and tag: the release source and the annotated tag target is
1133
+ `de46896a6cc3aebc61234917c6d8c472003da36b`, the merge of #49 (head
1134
+ `805162ed3c3bcd73113dccabf62656414e3dd9be`). The annotated tag object is
1135
+ `a198292fab7f4ef9bdbd18a0ba40324e45e71e21`. The feature pull request #48
1136
+ (head `a2dc018a22ffa8dd8ff6af5d358f4f57cf7db845`) was merged as
1137
+ `f9e4b6711e9ca0419b2325bec8d6c350ebead5f5`.
1138
+ - CI: #48 and #49 passed on Linux, macOS 15 and macOS 26. The
1139
+ [merged-main run](https://github.com/plagor44-ux/pi-session-mcp/actions/runs/38226706157)
1140
+ and the
1141
+ [tag run](https://github.com/plagor44-ux/pi-session-mcp/actions/runs/38226900880)
1142
+ are on record.
1143
+ - Level 1 on a fresh clone of the tag, with Node.js `26.11.1` and npm
1144
+ `12.2.0`: every command exited with `0`.
1145
+ - Typecheck, server build and CLI build.
1146
+ - The test run reported 43 files, 884 passed and 5 skipped (macOS-only).
1147
+ - `npm audit` and `npm audit --omit=dev` reported 0 vulnerabilities.
1148
+ - Offline Doctor reported `packageVersion` `0.8.0`. With the example
1149
+ configuration its only finding was the placeholder workspace.
1150
+ - npm package `pi-session-mcp@0.8.0`, published from a fresh clone of the tag
1151
+ through staged publishing and approved by the maintainer: 125 files, 189.3 kB
1152
+ and the shasum `37f76ab9c3807213b7e6178156992c76f0ff8378`. The tarball
1153
+ downloaded from the registry had the same SHA-1 and SHA-512 integrity.
1154
+ - Level 2 ran through `scripts/setup-acceptance.mjs` in three variants: the
1155
+ working tree of the release candidate, a fresh clone of the tag, and the npm
1156
+ package installed into a temporary prefix. Each passed 160 of 160 checks.
1157
+ - The clients were Codex CLI `0.162.1` (`user`) and Claude Code `2.1.296`
1158
+ (`user`, `project`, `local`), in disposable homes.
1159
+ - Every step also checked the controller skill: installed after apply,
1160
+ verified, removed after rollback and remove, with a foreign skill in the
1161
+ same directory untouched.
1162
+ - The real client registrations were unchanged, no process remained, and the
1163
+ build stayed byte-identical.
1164
+ - Multi-session skill acceptance: it ran on the branch candidate `0ebbaa0`
1165
+ (recorded above), not on the tag. According to the release notes, its
1166
+ sources equal the release apart from the version and the documentation.
1167
+ Claude Code `2.1.296` and Codex CLI `0.162.1` were the controllers, with Pi
1168
+ SDK `1.1.0` workers. Both the `parallel` scenario (overlapping turns, a
1169
+ same-session follow-up and a skill-only token written by the worker) and the
1170
+ targeted `abort` scenario with a neighbor that kept running passed every
1171
+ check for both clients. The Claude Code controller skill was installed with
1172
+ `setup --apply`, and all catalog skills were `builtin:` references.
1173
+
1174
+ This record does not cover:
1175
+ - A full ten-task Level 3 cycle. The multi-session check is targeted.
1176
+ - A Codex controller that reads the skill from `~/.agents/skills` live (setup
1177
+ installs it there and Level 2 checks the file), the extension profile path
1178
+ live with skills (the SDK contract tests cover it), more than two concurrent
1179
+ sessions, and macOS beyond CI.
1180
+ - The contents of skill files: they are not snapshotted, so skill files must
1181
+ not change while sessions use them. The model sees skill paths in its system
1182
+ prompt and may repeat them in its answers.
1183
+ - Isolation: skill selection limits the regular skill catalog only. An
1184
+ allowlisted extension stays trusted code, and a `coding` profile is no
1185
+ operating-system sandbox.
1186
+ - Package provenance: the npm package has no provenance attestation, because it
1187
+ was published from the maintainer's machine.
1188
+
1189
+ The post-0.8.0 stabilization (#47 and #50 to #54) passed on 2026-10-12, on
1190
+ Linux (`x64`) with Node.js `26.11.1`, Claude Code `2.1.296`, Codex CLI
1191
+ `0.162.1`, Pi SDK `1.1.0` and `pi-cursor-sdk@0.5.3`:
1192
+ - Candidate: a clean detached checkout of `1e904be`, built with `npm ci`,
1193
+ `npm run build` and `npm run build:cli`. `dist/main.js` has the SHA-256
1194
+ `47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`, and the
1195
+ dist tree the SHA-256
1196
+ `7b16757f9a1a0318247914f56debe79119a3845e1a1debcf1ad371db3a958fce`. The
1197
+ built `dist/` and `.pi-session-mcp-cli/` are byte-identical for every
1198
+ candidate below (`0f7c376`, `06471b5`, `cb6e949` and `1e904be`): the commits
1199
+ after `0f7c376` change only the acceptance harness, its tests and
1200
+ documentation. The commits after `1e904be` change only tests and documentation.
1201
+ - Level 1 on that checkout: every command exited with `0`. The test run
1202
+ reported 50 files, 1035 passed and 6 skipped; `npm audit` and
1203
+ `npm audit --omit=dev` reported 0 vulnerabilities; `npm pack --dry-run`
1204
+ listed 129 files with the three skills and no acceptance harness;
1205
+ `git diff --check` and `git status --short` printed nothing.
1206
+ - Level 2 through `scripts/setup-acceptance.mjs` with the setup of that
1207
+ checkout: 160 of 160 checks passed. All nine steps passed on all four
1208
+ targets. The real client registrations were unchanged, no process remained,
1209
+ no report leaked a path, and the build was unchanged. `06471b5` and
1210
+ `cb6e949` had passed 160 of 160 as well.
1211
+ - Multi-session skill acceptance, run 4, with the harness of that checkout
1212
+ (SHA-256 `e694c9be2779aae164ced0b771db035dac64f136160cc98d2c9e9cf63b629afe`):
1213
+ - `prepare --with-extensions` derived the configuration from the operator's
1214
+ Cursor profile: provider `cursor`, model `composer-2.5`, thinking level
1215
+ `off` and the exact allowlist `npm:pi-cursor-sdk@0.5.3` on both run
1216
+ profiles. Nothing else was copied. Fingerprint
1217
+ `sha256:05a3fb00f9a1bb57b891d4cfe273aa19e1a716c0d17d2d24097e4225dbea4142`.
1218
+ - `prepare` installed the Claude Code controller skill with the candidate's
1219
+ `setup --apply`: `applied` and `skill_installed`, a regular copy identical
1220
+ to the shipped skill.
1221
+ - Every invocation confirmed the candidate and the fingerprint through
1222
+ `pi_capabilities_get` as its first call, saw the skills `implementation`
1223
+ and `handshake` on `accept-code`, and had exactly one server of the run
1224
+ observed. No process remained, no bound resource changed, and no Pi
1225
+ Session MCP result contained a local path, the token or a credential
1226
+ marker.
1227
+ - Both Claude Code invocations, the required part, and Codex `parallel`
1228
+ passed every check. Codex `abort` failed one check (`range:changes`); every
1229
+ other check of it passed.
1230
+
1231
+ | Client | Scenario | Result |
1232
+ | --- | --- | --- |
1233
+ | Claude Code | `parallel` | Passed. First turns of two Cursor sessions overlapped by 20.4 s; follow-up in the same session completed; both fixtures pass their tests and the business checks with only the allowed files changed, each last written during a worker turn; `HANDSHAKE.txt` holds the token and was written during the follow-up turn, although no prompt contained the token |
1234
+ | Claude Code | `abort` | Passed. First turns overlapped by 21.5 s; one abort, result `ok`; `aborted` seen through `pi_turn_get` after the abort and before close; the abort fell inside the running interval of the neighbor, which completed and passes its tests; the worker's `sleep` was observed running, and at the end of the run it was gone and had written no file; both sessions closed |
1235
+ | Codex | `parallel` | Passed, as for Claude Code, with an overlap of 21.1 s |
1236
+ | Codex | `abort` | Failed with `range:changes`. The abort, its order, the running neighbor, cleanup and the neighbor's tests and business checks passed (overlap 19.2 s). The `range` worker also wrote `HANDSHAKE.txt`: the controller's prompt said "Change only src/range.js" and did not mention a handshake, so the Cursor worker applied the `handshake` skill of its profile on its own. The scope check caught it, as intended. This is worker behavior, not a Pi Session MCP defect |
1237
+
1238
+ The controllers made 5 to 7 `pi_turn_get` calls per invocation, and each
1239
+ invocation took 90 to 127 seconds.
1240
+
1241
+ - Turn liveness (#47): in every Cursor turn that a controller polled while it
1242
+ was `running`, `updatedAt` had moved past `startedAt`: 7 of 7 turns in run
1243
+ 4, 31 of 31 in runs 1 to 4. Turns that no poll saw running are not counted.
1244
+ This shows public stream events reaching `updatedAt` before the turn ended.
1245
+ It does not show progress, and work without a public event stays
1246
+ invisible.
1247
+ - Controller skill use, checked in the private transcripts of runs 1, 3 and
1248
+ 4:
1249
+ - Each Claude Code invocation invoked its skill once and loaded the copy
1250
+ that setup had installed for the candidate. A phrase that only the
1251
+ candidate's skill contains appeared, and none from the operator's personal
1252
+ copy in `~/.claude/skills`, which is the 0.8.0 skill. So the personal copy
1253
+ did not shadow the project copy.
1254
+ - Each Codex invocation read the candidate's skill through the run-scoped
1255
+ link with one shell command.
1256
+ - The handshake token, which only the override-directory skill held, shows
1257
+ that the worker skills reached the Cursor sessions.
1258
+
1259
+ Earlier attempts on the same build, kept on record:
1260
+ - Before a reboot, on `0f7c376`:
1261
+ - Level 1 passed, with 1028 tests passed and 6 skipped, and the working-tree
1262
+ Level 2 passed 160 of 160.
1263
+ - Claude Code `parallel` passed every check, with an overlap of 52.2 s.
1264
+ - Claude Code `abort` failed with `sessionsNotClosed`, `abortFailed`,
1265
+ `abortOrder`, `neighborNotRunningDuringAbort` and `range:tests`: neither
1266
+ `pi_session_start` started a session. At that time the operator's Pi agent
1267
+ directory was not writable, because `/home` had run out of Btrfs metadata
1268
+ space. The run directory was on a memory-backed file system and was lost in
1269
+ the reboot, so only the maintainer's summaries remain: there is no evidence
1270
+ file, and the exact start error is not on record.
1271
+ - Run 1 on `0f7c376`, with the harness SHA-256
1272
+ `9135f8d9a3d904172475e2fd0d5fce762613a8683a642b53642167572e02ab91`: all four
1273
+ invocations passed every check. The overlaps were 29.0 s and 22.2 s for
1274
+ Claude Code (`parallel`, `abort`) and 22.8 s and 26.5 s for Codex.
1275
+ - Run 2 on `06471b5`, with the harness SHA-256
1276
+ `d63b03065b28f3714ee2e9f76d722053c835f080b3a6edc96e1aab0031a0eadc`:
1277
+ - Codex `parallel` passed.
1278
+ - The other three invocations failed only with `noServerObserved`, and every
1279
+ other check passed, including the aborts, the running neighbors and the
1280
+ absence of residual processes.
1281
+ - The cause was in the harness. It replaced a process's earlier sighting on
1282
+ every sweep, so a sweep that caught the server while its client was ending
1283
+ it (exiting or an unreaped zombie, with nothing left to read) recorded it as
1284
+ a plain descendant of the client. `cb6e949` keeps the server role.
1285
+ - Run 3 on `cb6e949`, with the harness SHA-256
1286
+ `9f62535c3cb28506595ba72e5bafad772df71f473b4711799724186a946713b9`: Level 2
1287
+ passed 160 of 160, and all four invocations passed every check. The overlaps
1288
+ were 22.8 s and 22.2 s for Claude Code and 24.2 s and 18.6 s for Codex. One
1289
+ `assistantText` in Codex `parallel` named the absolute path of the worker's
1290
+ own `HANDSHAKE.txt`; `assistantText` is the worker's free text, counted
1291
+ separately, and not a structural leak. The two harness commits after it keep
1292
+ a process's ownership across sightings and match the client by PID and
1293
+ start time.
1294
+
1295
+ This record does not cover:
1296
+ - macOS beyond CI, or a ten-task Level 3 cycle.
1297
+ - A Codex controller that reads the skill from a copy setup installed in
1298
+ `~/.agents/skills`, because the run must not change the operator's home.
1299
+ Codex read the candidate's skill through a run-scoped link, and Level 2
1300
+ checks the installed file.
1301
+ - A third concurrent session, a `read-only` worker, or more than two
1302
+ concurrent sessions.
1303
+ - A real crash in the middle of a setup skill update, a real contention of
1304
+ two customization processes outside the tests, and an operating-system
1305
+ signal to the harness during a live analysis. The provider-free tests cover
1306
+ these.
1307
+
1308
+ After its release, `v0.8.0` was installed for the maintainer on Linux: the npm
1309
+ package `pi-session-mcp@0.8.0` in the user's npm prefix, registered for Claude
1310
+ Code. Checked on 2026-10-12:
1311
+ - Offline Doctor reported `packageVersion` `0.8.0` and no finding.
1312
+ - `--verify` for `claude-code:user:pi-session-mcp` reported `mcp_verified`, and
1313
+ `skill_verified` for the controller skill.
1314
+ - Codex has no registration of the server on that machine, so `codex:user` was
1315
+ not part of this installation.
1316
+
1317
+ Before its release, `v0.8.1` passed Level 1 and the working-tree Level 2 on its
1318
+ release candidate `baa6406` on Linux (`x64`), with Node.js `26.11.1`, Codex CLI
1319
+ `0.162.1` and Claude Code `2.1.296`, on 2026-10-12:
1320
+ - Level 1 on a clean detached checkout: every command exited with `0`.
1321
+ - The test run reported 50 files, 1035 passed and 6 skipped.
1322
+ - `npm audit` and `npm audit --omit=dev` reported 0 vulnerabilities.
1323
+ - `npm pack --dry-run` listed 129 files, including the three skills, and no
1324
+ acceptance harness.
1325
+ - Doctor reported `packageVersion` `0.8.1`. With the example configuration
1326
+ its only finding was the placeholder workspace.
1327
+ - Level 2 through `scripts/setup-acceptance.mjs` on the candidate's working
1328
+ tree: 160 of 160 checks passed. All nine steps passed on all four targets,
1329
+ including the controller skill finding of every step. The real client
1330
+ registrations were unchanged, no process remained, and the built files were
1331
+ unchanged.
1332
+ - Apart from the version and documentation, the candidate's sources equal
1333
+ `0c7bad3`. Its built modules have the same dist tree SHA-256
1334
+ (`7b16757f9a1a0318247914f56debe79119a3845e1a1debcf1ad371db3a958fce`) as the
1335
+ final candidate `1e904be` of the multi-session acceptance recorded above.
1336
+
1337
+ ### v0.8.1 post-release evidence carried over from the release notes
1338
+
1339
+ The post-release results of `v0.8.1` were recorded in the [v0.8.1 release
1340
+ notes](https://github.com/plagor44-ux/pi-session-mcp/releases/tag/v0.8.1),
1341
+ published on 2026-10-12 (22:06 UTC), and were carried over into this document
1342
+ on 2026-10-13 as roadmap item R19. This is a historical record taken from
1343
+ those notes: the checks were not rerun for it, and every item below keeps the
1344
+ scope, result and limitation that the notes state. The pre-release results of
1345
+ the same release candidate are recorded above.
1346
+
1347
+ Source and CI, as stated in the notes:
1348
+ - Release source and annotated tag target: `e462054a37505ef00e1e0c549ebab27e4db7ef55`,
1349
+ the merge of #55 (head `440f2e4ccb4f7cebd88825abd8515218f4bbbdee`). The
1350
+ annotated tag object is `02f0b30588115058fbb30148cb0934f18cf05aa3`.
1351
+ - #55 passed CI on Linux, macOS 15 and macOS 26. The merged-main CI run
1352
+ `38309519719` and the tag CI run `38309738675` are named in the notes. CI is
1353
+ neither Level 2 nor Level 3 acceptance.
1354
+
1355
+ Provider-free (Level 1), on a fresh clone of the tag, with Node.js `26.11.1`
1356
+ and npm `12.2.0`. Every command exited with `0`:
1357
+ - Typecheck, server build and CLI build.
1358
+ - 50 test files: 1035 passed and 6 skipped.
1359
+ - `npm audit` and `npm audit --omit=dev`: 0 vulnerabilities.
1360
+ - Offline Doctor: package version `0.8.1`. With the example configuration, the
1361
+ only finding was its placeholder workspace.
1362
+
1363
+ Package publication, a release fact and not an acceptance level: the npm
1364
+ package `pi-session-mcp@0.8.1` was published from a fresh clone of the tag
1365
+ through staged publishing, approved by the maintainer. It has 129 files and
1366
+ 215.6 kB, with shasum `b39fe48aff6ade4bf52c427960593951e150191b`. The tarball
1367
+ downloaded from the registry has the same SHA-1 and SHA-512 integrity. The
1368
+ package has no provenance attestation, because it was published from the
1369
+ maintainer's machine.
1370
+
1371
+ Real clients without a model (Level 2), with `scripts/setup-acceptance.mjs`:
1372
+ 160 of 160 checks passed in each of three variants:
1373
+ - the release candidate's working tree (`baa6406`);
1374
+ - a fresh clone of the tag;
1375
+ - the npm package installed into a temporary prefix.
1376
+
1377
+ The clients were Codex CLI `0.162.1` (`user`) and Claude Code `2.1.296`
1378
+ (`user`, `project`, `local`), in disposable homes. The real client
1379
+ registrations were unchanged, no process remained, and the build stayed
1380
+ byte-identical. The notes do not state the platform of these variants; the
1381
+ pre-release run of the candidate above states Linux (`x64`).
1382
+
1383
+ Real model, targeted multi-session skill acceptance (not a Level 3 cycle), on
1384
+ the final code candidate `1e904be`, whose built modules equal this release's
1385
+ (dist tree SHA-256 `7b16757f…`, abbreviated in the notes; the full value is
1386
+ recorded above). The detailed record is in the multi-session section above.
1387
+ - Controllers: Claude Code `2.1.296` and Codex CLI `0.162.1`. Workers: Cursor
1388
+ (`pi-cursor-sdk@0.5.3`, `composer-2.5`) on Pi SDK `1.1.0`.
1389
+ - Both required Claude Code scenarios passed every check: two overlapping
1390
+ sessions with a same-session follow-up, and a targeted abort while the
1391
+ neighbor kept running.
1392
+ - `updatedAt` had moved past `startedAt` in every Cursor turn polled while
1393
+ running: 31 of 31 across four runs.
1394
+
1395
+ Limitations and failures stated in the notes:
1396
+ - No full ten-task Level 3 cycle. The multi-session check is targeted.
1397
+ - Live acceptance ran on Linux only, with Cursor (`pi-cursor-sdk@0.5.3`,
1398
+ `composer-2.5`) workers. macOS is covered by CI.
1399
+ - Not live-proven: a Codex controller reading the skill from a copy installed
1400
+ in `~/.agents/skills`; a third concurrent or `read-only` worker; a real crash
1401
+ in the middle of a setup skill update (provider-free tests cover it).
1402
+ - In the final run, the supplementary Codex `abort` invocation failed its scope
1403
+ check: the Cursor worker applied the `handshake` test skill on its own. The
1404
+ required Claude Code invocations and Codex `parallel` passed, and Codex
1405
+ `abort` had passed on earlier runs of the same build.
1406
+
1407
+ ### v0.8.2 pre-release acceptance
1408
+
1409
+ Before its release, `v0.8.2` passed Level 1 and the working-tree Level 2 on its
1410
+ release candidate `bdbdf00` on Linux (`x64`), with Node.js `26.11.1`, Codex CLI
1411
+ `0.162.1` and Claude Code `2.1.296`, on 2026-10-13:
1412
+ - Level 1 on the release branch: every command exited with `0`.
1413
+ - The test run, with `NODE_OPTIONS=--unhandled-rejections=strict`, reported
1414
+ 54 files, 1409 passed and 6 skipped, and no unhandled error.
1415
+ - `npm audit` and `npm audit --omit=dev` reported 0 vulnerabilities.
1416
+ - `npm pack --dry-run` listed 135 files, including the three skills, and
1417
+ no acceptance harness, sources, tests, lockfile or implementation plan.
1418
+ - Doctor reported `packageVersion` `0.8.2`. With the example configuration
1419
+ its only finding was the placeholder workspace.
1420
+ - Level 2 through `scripts/setup-acceptance.mjs` on the candidate's working
1421
+ tree: 160 of 160 checks passed. All nine steps passed on all four targets.
1422
+ The real client registrations were unchanged, no process remained, and the
1423
+ built files were unchanged.
1424
+ - Apart from the version and documentation, the candidate's sources equal
1425
+ `166ffef`, current main; its runtime sources (`src/`, `skills/`) equal
1426
+ those of `0aae639`, on which Sprint 3 ran. Its built modules have the same
1427
+ `dist/main.js` SHA-256 (`47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`)
1428
+ and `dist` tree as the build on which the
1429
+ [Sprint 3 live acceptance](#sprint-3-live-acceptance-2026-10-13) ran, including
1430
+ the accepted ten-task Level 3 cycle.
1431
+
1432
+ ## Sprint 1 correctness checks (2026-10-13)
1433
+
1434
+ These checks belong to [#59](https://github.com/plagor44-ux/pi-session-mcp/issues/59)
1435
+ (recovery keeps unprovable trash) and
1436
+ [#56](https://github.com/plagor44-ux/pi-session-mcp/issues/56) (verify
1437
+ diagnostics). They were run on 2026-10-13 against the Sprint 1 branch
1438
+ `fix/59-56-s1-correctness`, before merge and without a release. The
1439
+ [Sprint 1 file](sprints/2026-10-13-s1-correctness.md) holds the commands,
1440
+ source binding, before-fix evidence and review findings in full.
1441
+
1442
+ Source: base main `3e360dd`; runtime candidate
1443
+ `fa32c22b573ff0bb0b920813bd9520bb79b025f4`, the last commit that changes `src/`
1444
+ or `test/`. Native Linux (x64), Node.js `26.11.1`, npm `12.2.0`, Codex CLI
1445
+ `0.162.1`, Claude Code `2.1.296`. No provider, model or credential was used.
1446
+
1447
+ Provider-free (Level 1), on `fa32c22`:
1448
+
1449
+ | Check | Exit | Result |
1450
+ | --- | --- | --- |
1451
+ | `npm ci`, `npm run typecheck`, `npm run build:cli`, `npm run build` | 0 each | |
1452
+ | `NODE_OPTIONS=--unhandled-rejections=strict npm test` | 0 | 52 files passed; 1121 tests passed, 6 skipped, 0 failed; no unhandled error |
1453
+ | `npm audit`, `npm audit --omit=dev` | 0 each | 0 vulnerabilities |
1454
+ | `git diff --check`, `git status --short` | 0 each | clean |
1455
+ | #59 counterexamples for `apply`, `remove` and `rollback` (`test/setup-skills-trash-preservation.test.ts`) and the adapted SIGKILL recovery tests | 0 | All pass. On the unfixed base 24 of the 30 counterexamples failed on the defect itself (`skill_recovered` or `skill_removed` where `skill_recovery_retained` was required). |
1456
+ | #56 counterexamples (`test/setup-verify-diagnostics.test.ts`) | 0 | All 53 pass. On the unfixed base 19 failed on the defect itself (`registration_not_equivalent` for unsupported and throwing inspections, and inspection or handshake after a failed Doctor). |
1457
+
1458
+ On the documentation head that followed, `npm pack --dry-run` listed 132 files
1459
+ without `src/`, `test/`, lockfile or implementation plans, and a relative link
1460
+ and anchor check of the changed documentation found no problem.
1461
+
1462
+ Real clients without a model (Level 2), on the build of the same runtime
1463
+ sources (`dist/main.js` SHA-256 `47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`):
1464
+
1465
+ - `scripts/setup-acceptance.mjs`: 160 of 160 checks passed, exit `0`, for
1466
+ `codex:user` and `claude-code:user`, `project` and `local` in disposable
1467
+ homes. Real registrations unchanged, no remaining process, no path leak,
1468
+ build unchanged.
1469
+ - New #56 negative case, outside the harness: with the client CLI not on
1470
+ `PATH`, `--verify` reported `unsupported (unsupported)` in human and JSON
1471
+ form and `--dry-run` reported `unsupported (unsupported)`, each with exit
1472
+ `1`, for Codex `user` and Claude Code `user`. The registration was unchanged
1473
+ during these steps, and no output contained a path. The same steps on the
1474
+ built base reproduced #56 (`registration_not_equivalent`).
1475
+
1476
+ Not established by these checks: the result on macOS (only CI covers it
1477
+ there), the final pull-request head's CI matrix, a real operating-system crash
1478
+ during a skill update (the interruption tests use a checkpoint and SIGKILL,
1479
+ the counterexamples a scripted checkpoint), and any model behavior. A dry-run
1480
+ of a pending recovery can still announce a recovery that apply retains; that
1481
+ is tracked as [#60](https://github.com/plagor44-ux/pi-session-mcp/issues/60).
1482
+ Note added in Sprint 2: #60 changes this dry-run behavior; see the
1483
+ [Sprint 2 checks](#sprint-2-evidence-checks-2026-10-13). The Sprint 1 record
1484
+ above is unchanged.
1485
+
1486
+ Open gates that Sprint 1 does not close:
1487
+ - Level 3: no full ten-task cycle on Pi SDK `1.x`, and none for the profile
1488
+ intended for use.
1489
+ - Current macOS Level 2 on real hardware with both clients. CI covers macOS;
1490
+ it does not replace that.
1491
+ - Live discovery of the Codex home skill that setup installs.
1492
+ - Multi-session operation beyond two sessions, including a third concurrent
1493
+ worker and a `read-only` worker.
1494
+
1495
+ ## Sprint 2 evidence checks (2026-10-13)
1496
+
1497
+ These checks belong to [#60](https://github.com/plagor44-ux/pi-session-mcp/issues/60),
1498
+ [#62](https://github.com/plagor44-ux/pi-session-mcp/issues/62),
1499
+ [#63](https://github.com/plagor44-ux/pi-session-mcp/issues/63) and the harness
1500
+ issues [#66](https://github.com/plagor44-ux/pi-session-mcp/issues/66),
1501
+ [#67](https://github.com/plagor44-ux/pi-session-mcp/issues/67) and
1502
+ [#68](https://github.com/plagor44-ux/pi-session-mcp/issues/68). They ran on
1503
+ 2026-10-13 on branch `fix/s2-evidence`, before merge and without a release.
1504
+ The [Sprint 2 file](sprints/2026-10-13-s2-evidence.md) holds the commands,
1505
+ before-fix evidence, every gate run and the review rounds.
1506
+
1507
+ Source: base main `b145f8c`; final runtime candidate `923a393`, the last commit
1508
+ that changes `src/`, `scripts/`, `test/`, `skills/` or CI; native Linux
1509
+ (x64), Node.js `26.11.1`, npm `12.2.0`, Codex CLI `0.162.1`, Claude Code
1510
+ `2.1.296`. No provider, model or credential was used.
1511
+
1512
+ Provider-free (Level 1), on the documentation head `07f56b6` of that runtime:
1513
+ `npm ci`, typecheck, `build:cli`,
1514
+ `NODE_OPTIONS=--unhandled-rejections=strict npm test` (54 files; 1300 passed,
1515
+ 6 skipped, 0 failed; no unhandled error), build, `npm audit` and
1516
+ `npm audit --omit=dev` (0 vulnerabilities), `git diff --check` and a clean
1517
+ status all exited with `0`. On the unfixed base, the new #60 counterexamples
1518
+ failed 14 of 23 on the defect itself (`skill_recovery_planned` where
1519
+ `skill_recovery_retained` was required).
1520
+
1521
+ Pi SDK canary: the published `1.2.0` is compatible with the candidate's
1522
+ sources (typecheck and the 12 SDK-facing test files passed); the pin stays
1523
+ `1.1.0`. This is not an SDK update.
1524
+
1525
+ Real clients without a model (Level 2): `scripts/setup-acceptance.mjs` passed
1526
+ 160 of 160 checks, exit `0`, on the build that the final head also produces
1527
+ (`dist` JS tree SHA-256 `f85bf73ee8c0ddb2270d8d6040feffbc49f018d2e6ab6253fffb828654a389df`),
1528
+ for `codex:user` and `claude-code:user`, `project` and `local`; real
1529
+ registrations unchanged, no remaining process, no path leak.
1530
+
1531
+ The multi-session harness changes (#66, #67, #68) were verified with
1532
+ provider-free tests only: no live multi-session run used them yet. A live run
1533
+ belongs to Sprint 3.
1534
+
1535
+ Open gates that Sprint 2 does not close: the final-head CI of the pull request,
1536
+ a live run with the new harness bindings, and every Sprint 1 open gate above.
1537
+
1538
+ ## Sprint 3 live acceptance (2026-10-13)
1539
+
1540
+ Recorded on 2026-10-13 against main `0aae639` (package `0.8.1` plus the
1541
+ unreleased Sprint 1 and 2 changes; `dist/main.js` SHA-256 `47875d38…`), on
1542
+ native Linux x64 with Node.js `26.11.1`, Claude Code `2.1.296` and Codex CLI
1543
+ `0.162.1`. The [Sprint 3 file](sprints/2026-10-13-s3-live-usage.md) holds the
1544
+ pre-registration, every command and the review rounds. Worker profiles are
1545
+ the maintainer's intended pair, copied without its read-only external MCP
1546
+ grant: read-only OpenAI `gpt-6-luna` (`low`) and coding DeepSeek
1547
+ `deepseek-flash` (`high`).
1548
+
1549
+ Level 3 (R05, R09): one ten-task cycle with both controllers, pre-registered,
1550
+ strictly sequential. Accepted: 10 of 10 tasks reached their intended outcome
1551
+ and every gate condition held, including the coding barrier for both clients
1552
+ (in Codex's read-only sandbox too), read-only invariance, no change outside the
1553
+ approved diff, no public leak, no session or process left after a verified
1554
+ close, and Level 1 green for the release source. Every running turn was seen
1555
+ in at most one `pi_turn_get` poll. This is the first full cycle on Pi SDK `1.x`;
1556
+ it covers this provider pair on Linux only.
1557
+
1558
+ Targeted multi-session evidence (not Level 3), with
1559
+ `scripts/multi-session-acceptance.mjs`:
1560
+
1561
+ - R06, Codex `abort` (DeepSeek workers): passed, including the strict scope
1562
+ oracle that failed the v0.8.1 Codex abort run.
1563
+ - R08, `trio` (three concurrent sessions, a read-only reviewer of a frozen
1564
+ fixture, a neighbor abort): Codex passed; Claude Code failed only
1565
+ `neighborsNotRunningDuringAbort`, because the read-only review finished 6.7 s
1566
+ before the abort. The failed run stays on record
1567
+ ([#74](https://github.com/plagor44-ux/pi-session-mcp/issues/74)).
1568
+
1569
+ Real client discovery (R07): a real Codex run in an isolated home found the
1570
+ controller skill that setup had installed as a regular copy, named that copy's
1571
+ path and quoted a line that exists only in the revision under test; no manual
1572
+ link was needed.
1573
+
1574
+ Not established: macOS (R10, R11; runbook in the Sprint 3 file), other
1575
+ providers and models, the operator profiles' external MCP grant, larger tasks,
1576
+ more than three concurrent sessions, and the `trio` timing with Claude Code as
1577
+ controller.