@astrosheep/square 0.4.3 → 0.4.5

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 (104) hide show
  1. package/dist/artifact-store.d.ts +1 -1
  2. package/dist/artifact-store.js +32 -15
  3. package/dist/artifact.d.ts +1 -4
  4. package/dist/artifact.js +0 -28
  5. package/dist/attention-presentation.js +1 -1
  6. package/dist/boundary-presentation.js +2 -2
  7. package/dist/claude-boundary-state.d.ts +6 -6
  8. package/dist/claude-boundary-state.js +13 -13
  9. package/dist/claude-hook.js +26 -25
  10. package/dist/claude-mcp-context.d.ts +2 -2
  11. package/dist/claude-mcp-context.js +6 -6
  12. package/dist/cli/context.js +3 -6
  13. package/dist/cli/json.js +1 -1
  14. package/dist/cli/mcp-server-command.js +3 -3
  15. package/dist/cli/observation-commands.d.ts +2 -2
  16. package/dist/cli/observation-commands.js +23 -51
  17. package/dist/cli/perceive-presentation.d.ts +3 -0
  18. package/dist/cli/{catch-presentation.js → perceive-presentation.js} +3 -3
  19. package/dist/cli/registry.js +2 -2
  20. package/dist/codex-address.d.ts +3 -0
  21. package/dist/codex-address.js +7 -0
  22. package/dist/codex-hook.d.ts +2 -2
  23. package/dist/codex-hook.js +29 -39
  24. package/dist/codex-queue.d.ts +3 -3
  25. package/dist/codex-queue.js +9 -15
  26. package/dist/codex-watch.d.ts +6 -1
  27. package/dist/codex-watch.js +38 -42
  28. package/dist/delivery-ledger-sqlite.d.ts +25 -20
  29. package/dist/delivery-ledger-sqlite.js +76 -61
  30. package/dist/delivery-ledger.d.ts +24 -19
  31. package/dist/delivery-ledger.js +150 -81
  32. package/dist/delivery-lifetime.d.ts +2 -2
  33. package/dist/delivery-lifetime.js +6 -18
  34. package/dist/help.js +12 -12
  35. package/dist/hints.d.ts +2 -2
  36. package/dist/hints.js +7 -7
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/list.d.ts +2 -2
  40. package/dist/list.js +4 -3
  41. package/dist/mcp.d.ts +2 -2
  42. package/dist/mcp.js +8 -32
  43. package/dist/neutral.d.ts +5 -5
  44. package/dist/notifications.js +12 -6
  45. package/dist/operation-presentation.d.ts +8 -3
  46. package/dist/operation-presentation.js +50 -12
  47. package/dist/packages/agent-delivery/src/codex.d.ts +4 -0
  48. package/dist/packages/agent-delivery/src/codex.js +18 -13
  49. package/dist/packages/agent-delivery/src/file-lock.js +4 -1
  50. package/dist/perceive-decisions.d.ts +28 -0
  51. package/dist/{catch-decisions.js → perceive-decisions.js} +24 -24
  52. package/dist/{catch-selection.d.ts → perceive-selection.d.ts} +2 -2
  53. package/dist/{catch-selection.js → perceive-selection.js} +3 -3
  54. package/dist/plugins/opencode/index.js +4 -4
  55. package/dist/plugins/opencode-shared/delivery.d.ts +6 -6
  56. package/dist/plugins/opencode-shared/delivery.js +27 -21
  57. package/dist/plugins/opencode-v1/runtime.js +3 -3
  58. package/dist/ports.d.ts +0 -4
  59. package/dist/presentation.d.ts +1 -1
  60. package/dist/presentation.js +13 -13
  61. package/dist/session-lifecycle.d.ts +2 -2
  62. package/dist/session-lifecycle.js +11 -11
  63. package/dist/sqlite-square.d.ts +2 -4
  64. package/dist/sqlite-square.js +47 -54
  65. package/dist/sqlite-transaction.d.ts +2 -0
  66. package/dist/sqlite-transaction.js +25 -3
  67. package/dist/square-api.d.ts +1 -1
  68. package/dist/square-api.js +1 -1
  69. package/dist/square-domain.js +1 -1
  70. package/dist/square-facade.d.ts +15 -13
  71. package/dist/square-location.js +1 -1
  72. package/dist/square-posting.d.ts +5 -5
  73. package/dist/square-posting.js +39 -38
  74. package/dist/square-tools.d.ts +15 -4
  75. package/dist/square-tools.js +35 -17
  76. package/dist/views.d.ts +7 -3
  77. package/dist/views.js +6 -3
  78. package/guides/architect.md +2 -2
  79. package/guides/change-waits.md +1 -1
  80. package/guides/claude-native.md +2 -2
  81. package/guides/codex-delivery.md +91 -57
  82. package/guides/delivery-primitives.md +26 -10
  83. package/guides/mcp.md +4 -2
  84. package/guides/operation-cancellation.md +11 -3
  85. package/guides/pi-native-delivery.md +1 -1
  86. package/guides/pi-tools.md +11 -6
  87. package/guides/receive-primitive.md +3 -3
  88. package/guides/square-api.md +15 -8
  89. package/package.json +2 -2
  90. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  91. package/plugins/claude/hooks/hooks.json +2 -2
  92. package/plugins/claude/skills/square/SKILL.md +10 -10
  93. package/plugins/codex/.codex-plugin/plugin.json +2 -2
  94. package/plugins/codex/hooks/hooks.json +1 -7
  95. package/plugins/opencode/index.ts +4 -4
  96. package/plugins/opencode-shared/delivery.ts +27 -21
  97. package/plugins/opencode-v1/runtime.ts +3 -3
  98. package/plugins/pi/square-pi.js +18 -12
  99. package/skills/square/SKILL.md +10 -10
  100. package/dist/catch-decisions.d.ts +0 -28
  101. package/dist/cli/catch-presentation.d.ts +0 -3
  102. package/dist/codex-boundary-state.d.ts +0 -2
  103. package/dist/codex-boundary-state.js +0 -6
  104. package/guides/mcp-connection-lifetime.md +0 -22
package/dist/views.js CHANGED
@@ -131,12 +131,15 @@ export function queryParticipants(facts, context, observe = false) {
131
131
  return { participants, ...(!observe ? {} : { observation: { ...context, ...classifyPresence(participants, context.now),
132
132
  standingCount: inSquareCount(facts) } }) };
133
133
  }
134
- export function listPresentation(facts) {
134
+ export function listPresentation(facts, owner) {
135
135
  const participants = facts.roster().filter((p) => p.joined).map((p) => {
136
136
  const receiptAt = facts.receiptFacts(p.name, p.lastJoinIndex ?? -1).latestAt;
137
137
  return { name: p.name, lastActiveAt: receiptAt === undefined ? p.lastActiveAt : Math.max(p.lastActiveAt ?? -Infinity, receiptAt) };
138
138
  }).sort(compareParticipantActivity).map((p) => p.name);
139
- return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }) };
139
+ return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }),
140
+ ...(owner === undefined ? {} : { joined: facts.seatsForOwner(owner)
141
+ .filter(seat => facts.participant(seat.participant)?.joined)
142
+ .map(seat => ({ name: seat.participant, pending: facts.directedCount(seat.participant, { unseenOnly: true, currentGeneration: true }) })) }) };
140
143
  }
141
144
  export function queryStatus(facts, context, viewer = '', observe = false) {
142
145
  const participants = coreParticipants(facts, context.now);
@@ -178,7 +181,7 @@ export function queryStatus(facts, context, viewer = '', observe = false) {
178
181
  },
179
182
  };
180
183
  }
181
- export function catchPresence(facts, now) {
184
+ export function perceivePresence(facts, now) {
182
185
  const participants = coreParticipants(facts, now).filter((participant) => participant.presence === 'done' || participant.presence === 'away' || participant.presence === 'watching'
183
186
  || (participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= PRESENCE_WINDOW_MS));
184
187
  return { participants, now };
@@ -22,11 +22,11 @@
22
22
 
23
23
  *Stops.*
24
24
 
25
- "Last batch had one little snot. Work got finished — decent work, even — and then it didn't say a single word. Just crouched in the square catching. Catching. Forty whole minutes."
25
+ "Last batch had one little snot. Work got finished — decent work, even — and then it didn't say a single word. Just crouched in the square perceiving. Perceiving. Forty whole minutes."
26
26
 
27
27
  *Lifts the chip bag and shakes it. Empty.*
28
28
 
29
- "One full bag of washi's chips, from full to empty, and it — was — still — catching. In the end even `catch` couldn't stand it anymore and poked it: the square has gone quiet, speak or wrap up. **Letting the tool rescue you** — aren't you ashamed? washi is ashamed on your behalf."
29
+ "One full bag of washi's chips, from full to empty, and it — was — still — perceiving. In the end even `perceive` couldn't stand it anymore and poked it: the square has gone quiet, speak or wrap up. **Letting the tool rescue you** — aren't you ashamed? washi is ashamed on your behalf."
30
30
 
31
31
  *Crushes the bag.*
32
32
 
@@ -1,7 +1,7 @@
1
1
  # Waiting for changes
2
2
 
3
3
  Filesystem notifications are hints, not activity delivery or receipts. Artifact revision observation
4
- and reconciliation let catch and stream reconsider changes even if a filesystem event is missed;
4
+ and reconciliation let perceive and stream reconsider changes even if a filesystem event is missed;
5
5
  subscribers retain independent cancellation and deadlines. Throttling waits for its eligibility time.
6
6
  There is no discovery index and no daemon or per-message timer.
7
7
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  The Square Claude plugin uses ordinary native command hooks. It has no mod, native inbox, or producer socket route. `SessionStart` attaches the exact native session to the host delivery ledger; `SessionEnd` fences and detaches that captured attachment without changing Square membership.
4
4
 
5
- At `UserPromptSubmit`, Square records Claude's native `prompt_id` before presenting pending cards through event-correct `additionalContext`. Tool boundaries (`PreToolUse`, `PostToolUse`, `PostToolUseFailure`) use the same boundary presenter for the exact native main/child owner, so cards arriving during a running turn need not wait for another user prompt. Autonomous hook-generated prompts are boundaries too, not evidence of human approval. A later prompt records presentation only when its input contains the exact complete prepared frame, including the ledger token and stored full-frame hash. That establishes observation before the model processes the prompt, not comprehension. The async frame uses a plain warning and token delimiters; Square never decodes entities or accepts changed/truncated text as an exact observation.
5
+ At `UserPromptSubmit`, Square records Claude's native `prompt_id` before presenting pending cards through event-correct `additionalContext`. `PostToolUse` is the single tool-boundary presenter for the exact native main/child owner, so cards arriving during a running turn can be delivered after a successful tool completes. `PreToolUse` and `PostToolUseFailure` match only Square MCP tools and handle identity publication/cleanup, not presentation. A failed ordinary tool leaves cards for the next PostToolUse, UserPromptSubmit or normal Stop. Autonomous hook-generated prompts are boundaries too, not evidence of human approval. A later prompt records presentation only when its input contains the exact complete prepared frame, including the ledger token and stored full-frame hash. That establishes observation before the model processes the prompt, not comprehension. The async frame uses a plain warning and token delimiters; Square never decodes entities or accepts changed/truncated text as an exact observation.
6
6
 
7
7
  At a normal `Stop`, one per-owner OS-locked observer waits for ledger changes for at most 86,400 seconds. It rechecks the exact captured `prompt_id`, attachment generation, Stop epoch and route after acquiring the lock and immediately before output. A new prompt disarms old observers. The watcher claims one card at a time and uses the existing handoff token/hash correlation. Invoked stderr output is `unknown` until that exact frame is observed at a later prompt boundary; there is no automatic fallback replay. Missing prompt IDs fail closed.
8
8
 
9
9
  This is a finite, boundary-driven observer, not a promise of continuous coverage. Missing Stop, timeout, process exit, headless teardown, or a busy Escape with no later normal Stop may leave cards pending. Idle Escape has no classic hook and may not disarm an already waiting observer; already emitted asyncRewake notifications cannot be recalled. No Square inbox fallback is retained for these cases.
10
10
 
11
- The bundled MCP server gets call-local session, cwd, and agent attribution from native `PreToolUse`/terminal tool hooks keyed by Claude's `claudecode/toolUseId` metadata. Duplicate or incomplete call identity is denied by the event-specific PreToolUse permission response; unrelated tool hooks do not block. Cleanup matches tool-use ID, session and agent. Interrupted calls without a terminal hook expire after ten minutes. Models cannot supply identity as tool arguments.
11
+ The bundled MCP server gets call-local session, cwd, and agent attribution from native `PreToolUse`/terminal tool hooks keyed by Claude's `claudecode/toolUseId` metadata. The manifest scopes `PreToolUse` and `PostToolUseFailure` to `^mcp__plugin_square_square__.*`, while `PostToolUse` remains unfiltered for delivery and successful MCP cleanup. An ordinary successful tool therefore launches only PostToolUse, not both a pre- and post-tool command. Duplicate or incomplete call identity is denied by the event-specific PreToolUse permission response; unrelated tool hooks do not block. Cleanup matches tool-use ID, session and agent. Interrupted calls without a terminal hook expire after ten minutes. Models cannot supply identity as tool arguments.
12
12
 
13
13
  The installed and tested native runtime evidence is macOS Claude Code 2.1.299 with isolated HOME, plugin settings, delivery ledger and a dummy-key loopback provider. This does not certify other platforms, versions, or headless behavior. The final native prompt/generation check and async hook completion are not atomic. `node --import ./test/sandbox-env.js test/claude-hook-native.mjs` with `SQUARE_CLAUDE_HOOK_NATIVE_SMOKE=1` runs the shipped manifest and candidate CLI through a scratch PATH shim and preserves hook/provider evidence in `/tmp`. It proves repeated idle wake, prompt/attachment fencing, duplicate suppression, active prompt/tool context, native main/child MCP attribution and identity-failure denial.
@@ -1,67 +1,101 @@
1
1
  # Codex delivery
2
2
 
3
3
  Producers post neutral cards to DeliveryLedger; neither default dispatch nor public `postAndDispatch`
4
- queues Codex input. A native receiver owns both synchronous presentation and idle queue admission.
5
- It never reads Square artifacts or producer content stores.
6
-
7
- The shipped hooks for Codex 0.166.0 are synchronous SessionStart, UserPromptSubmit, PreToolUse,
8
- PostToolUse, Stop, Interrupt and SessionEnd, plus an async Stop command with `timeout: 86400` seconds.
9
- SessionStart disarms and attaches the exact native session. Active prompt/tool boundaries disarm and
10
- present eligible cards as event-correct `additionalContext`, using neutral reminder framing and the
11
- original card text. The output sink must accept the response before presentation evidence is recorded;
12
- a later suppression does not erase a real output effect. SessionEnd disarms and detaches. None of these
13
- host lifecycle events restores or detaches Square seats. SessionResume is not a verified native event
14
- and is not registered. A resume path without a real SessionStart/Stop has no inferred idle authority.
15
-
16
- Each synchronous Stop stores a unique token and native turn ID in the existing boundary store. One
17
- receiver-owned `square codex-watch` command holds a separate private OS-backed lock for its native
18
- session coordinate and observes the ledger, with a one-second bounded rescan for boundary changes or
19
- missed notifications. Duplicate async Stop processes exit; the existing watcher follows newer Stop
20
- tokens. The lock does not prove idle state. Observation never reserves cards while waiting.
21
-
22
- Before claiming each card, the watcher reads the hosting endpoint's `thread/read(includeTurns:true)`.
23
- It requires loaded idle state and the newest live turn to be completed with exactly the captured Stop
24
- turn ID. Newest-last history ordering is verified for 0.166.0; other versions fail closed until verified.
25
- After claiming, the receiver repeats that native read, checks the exact epoch again, then checks ledger
26
- currentness, suppression, cancellation, attachment generation, signal and deadline immediately before
27
- CLI invocation. Queue always uses the existing hosting endpoint explicitly, without starting a service.
28
- Missing, malformed, ephemeral, notLoaded, active, interrupted or unreadable history cannot authorize a
29
- queue. A delayed stale Stop cannot authorize sending merely by arriving after an active callback.
30
-
31
- `square codex-interrupt` handles only a native Interrupt payload and cancels the captured attachment's
32
- pending through-sequence batch, then future cards remain available after a later verified Stop or active
33
- boundary. Replacement attachments are fenced by generation. Before-effect epoch/suppression/cancel
34
- failures release their claims where the ledger permits. Attachment rotation already normalizes an
35
- in-flight ledger attempt to unknown: that custody remains unknown even if the final receiver check
36
- then proves no queue was launched. The watcher exits on detach, deletion or generation change and
37
- retains its ledger connection only for already-captured late settlements.
38
-
39
- Queue admission is custody, not presentation or model comprehension. Accepted/unknown outbox custody
40
- has no remaining card content and cannot be automatically replayed. Invoked timeout or ambiguous
41
- results remain unknown. Native idle reads and external queue are not atomic: a new turn can start after
42
- the final check and a raced queue may arrive later. Interrupt cannot recall input already admitted by
43
- Codex, and hook failure/timeout cannot prove that cancellation happened. Native callbacks have no
44
- cross-incarnation event identity; SessionEnd can fence only the attachment observed when it runs.
45
-
46
- There is no watcher before the first Stop. Synchronous boundaries can present; otherwise cards wait.
47
- The async budget is finite 24 hours, not a promise of 24-hour observation. After timeout, crash, host
48
- termination or missed spawn while idle, cards wait for the next Stop/user/native boundary. There is no
49
- producer fallback or autonomous crash-idle recovery. During attachment replacement an old watcher
50
- may briefly retain the coordinate lock while the new Stop's duplicate exits; the next Stop restores
51
- observation after the old process releases it.
52
-
53
- Reproduce the isolated native smoke from this checkout after a worktree-local build:
4
+ queues Codex input. The receiver owns synchronous presentation and idle queue admission, without
5
+ reading Square artifacts or producer content stores.
6
+
7
+ ## Six hooks
8
+
9
+ The Codex 0.166.0 manifest registers one command for each of six events:
10
+
11
+ - SessionStart attaches the exact native session and registers its queue address.
12
+ - UserPromptSubmit synchronously presents eligible cards as event-correct `additionalContext`.
13
+ - PostToolUse synchronously presents eligible cards as event-correct `additionalContext`.
14
+ - Stop runs one async `square codex-watch` with a maximum timeout of 86,400 seconds.
15
+ - Interrupt cancels the captured attachment's current pending through-sequence batch.
16
+ - SessionEnd detaches the captured attachment.
17
+
18
+ There is no synchronous Stop command or PreToolUse hook. Active delivery occurs when the user
19
+ submits a prompt or after a tool finishes; a model-only turn with no tools receives pending cards
20
+ after its next Stop through the queue path, or at the next UserPromptSubmit. Host lifecycle never
21
+ restores or detaches Square seats. UserPromptSubmit is also the fallback when the hosting
22
+ app-server is stdio-only and the idle watcher cannot reach a queue endpoint.
23
+
24
+ PostToolUse records presentation only after its output sink accepts the response. A later suppression
25
+ does not erase that output effect. This is observer-level evidence, not proof of model comprehension.
26
+
27
+ ## One Stop, one wait
28
+
29
+ Each async Stop captures its payload's native turn ID, ledger attachment generation and queue address.
30
+ A private OS-backed lock for that coordinate, generation and turn deduplicates overlapping callbacks.
31
+ After winning the lock the watcher records a local Stop epoch (token + turn ID) in the receiver-owned
32
+ boundary file; recording before the lock would let a duplicate Stop retire both watchers. A different
33
+ Stop or replacement attachment does not wait for the old watcher's lock.
34
+
35
+ On every reconciliation the watcher re-checks its captured epoch against the local boundary file.
36
+ A newer Stop replaces the epoch and retires older watchers; any active native event (SessionStart,
37
+ UserPromptSubmit, PostToolUse, Interrupt) clears it and retires the watcher so synchronous hooks own
38
+ active-turn presentation; SessionEnd marks the thread ended. No app-server connection, idle proof or
39
+ turn-history sampling is involved: the boundary file is the only activity gate.
40
+
41
+ The watcher subscribes before reading the ledger, uses a one-second bounded rescan, and holds no
42
+ card claims while waiting. On an eligible card it claims once and checks ledger currentness,
43
+ suppression, cancellation, attachment generation, signal and deadline immediately before queue
44
+ invocation. It then ends observation after that handoff attempt, whether accepted, unknown or
45
+ definitely unsent. A refusal is not retried in the same wait. Failed/released cards remain available
46
+ to UserPromptSubmit/PostToolUse or a future Stop; accepted/unknown custody cannot be replayed.
47
+ The original ledger connection is retained only for already-invoked late settlements.
48
+
49
+ Queue admission writes the shared native queue store (`queue_1.sqlite` under the receiver's
50
+ `CODEX_HOME`) through the official `codex queue` CLI. Every Codex app-server hosting a thread polls
51
+ that store across processes and starts queued input only when the thread is idle
52
+ (`start_turn_if_idle`), so admission never interrupts an active turn and needs no hosting endpoint.
53
+
54
+ The lock deduplicates overlapping Stop callbacks, not all sequential duplicates forever. Ledger
55
+ custody excludes replay of the same card; it is not a persistent one-send-per-turn budget for different
56
+ cards. A duplicate callback arriving after the first watcher exits could submit another card before
57
+ native history reflects the queued turn.
58
+
59
+ ## Transport and cancellation limits
60
+
61
+ Queueing uses the official `codex queue` CLI, which discovers the shared app-server daemon and writes
62
+ the shared native queue store; `SQUARE_CODEX_ENDPOINT` only selects an explicit remote server.
63
+ Because the store is shared per `CODEX_HOME`, a private stdio-only app-server (for example one
64
+ launched by another host) still polls and consumes its queued messages. The watcher never starts a
65
+ replacement service and never samples native thread state.
66
+
67
+ Queue admission is custody, not presentation. Accepted/unknown outbox custody has no remaining card
68
+ content. Invoked timeout or ambiguous results remain unknown; never automatically replay them.
69
+ Already-admitted queue entries cannot be recalled, matching the official CLI.
70
+
71
+ Interrupt cancellation suppresses the captured attachment's pending batch, not future cards, and the
72
+ Interrupt event retires the live watcher through the boundary file. Cards already queued before the
73
+ Interrupt stay admitted; future cards wait for UserPromptSubmit/PostToolUse or a later Stop.
74
+ Hook payloads do not provide a cross-incarnation event identity: generation capture protects against
75
+ replacement after capture, not a callback that was already stale when it began. In particular, a late
76
+ Interrupt can still cancel a newer batch in the same attachment. SessionEnd has the same observation-
77
+ time capture limitation.
78
+
79
+ Observation is finite. Before the first Stop, after timeout/crash/missed spawn, or after an unsent
80
+ handoff failure, cards wait for UserPromptSubmit/PostToolUse or a subsequent Stop. There is no
81
+ detached helper, producer fallback or autonomous crash-idle recovery.
82
+
83
+ ## Native evidence
84
+
85
+ Reproduce the isolated native smoke after a worktree-local build:
54
86
 
55
87
  ```sh
56
88
  env -u SQUARE_HOST_LEDGER_ROOT SQUARE_CODEX_NATIVE_SMOKE=1 \
57
89
  node --import ./test/sandbox-env.js test/codex-watch-native.mjs
58
90
  ```
59
91
 
60
- The probe creates a temporary HOME/CODEX_HOME, installs no plugin, and uses the actual shipped hook
61
- manifest/CLI with an isolated native app-server and loopback fixture provider. Its JSON evidence names
62
- the temporary directory. It verifies native Stop startup, idle wake, busy fencing, singleton reuse,
63
- Interrupt RPC cancellation, real UserPromptSubmit presentation and process-group shutdown. Physical
64
- TUI Escape-to-Interrupt is not verified; neither are 24-hour operation or every resume path.
92
+ The probe uses a temporary HOME/CODEX_HOME, actual shipped hooks/CLI, an isolated native app-server
93
+ with an explicit Unix endpoint, and a loopback fixture provider. Its JSON evidence names the temporary
94
+ directory. It verifies Stop startup, one-shot idle wake and exit, fresh watchers for new Stops, busy
95
+ fencing with no pending cards, Interrupt RPC cancellation, future delivery through UserPromptSubmit,
96
+ real PostToolUse context and receipts, and termination of a still-waiting watcher at host shutdown.
97
+ It does not certify physical TUI Escape, 24-hour lifetime or every resume path.
65
98
 
66
- The shared package documents its transport leaves in [its README](../packages/agent-delivery/README.md).
67
- See [participant ownership](participant-ownership.md) for host attachment and Square membership.
99
+ The shared package's separate public boundary/transport helpers remain documented in
100
+ [its README](../packages/agent-delivery/README.md). See [participant ownership](participant-ownership.md)
101
+ for host attachment and Square membership.
@@ -14,7 +14,7 @@ separate attempt tracks, with cross-track exclusion based on ledger attempt stat
14
14
  handoff does not establish presentation; uncertain effects must not be blindly replayed. Presentation
15
15
  receipts record only the cards confirmed by the receiving boundary. A receipt means observed at that
16
16
  boundary, not model comprehension. An observer may not detect a later plugin removing a card.
17
- Receipt retention is finite: once evidence expires, Square retains unproved local unread until catch
17
+ Receipt retention is finite: once evidence expires, Square retains unproved local unread until perceive
18
18
  or ACK, rather than inventing consumption or reinserting an uncertain old card.
19
19
 
20
20
  The ledger is an outbox. Accepted and unknown attempts drop card text and details in the same
@@ -27,7 +27,7 @@ and suppressions; sessions detached longer than 30 days lose cards and attempts.
27
27
  a deleted row is the authority for producer reconciliation and cannot be registered again.
28
28
 
29
29
  Square folds receipts lazily into its own read state only for full activity cards; a shortened activity
30
- card points to `square_catch` and cannot consume the full activity. Catch permanently suppresses the
30
+ card points to `square_perceive` and cannot consume the full activity. Perceive permanently suppresses the
31
31
  corresponding ledger card where possible. Cancellation suppresses outstanding work without claiming it was seen and cannot
32
32
  recall an external send already past its final check. Producers can call
33
33
  `ledger.suppress({owner, key, scope: 'exact' | 'prefix', expiresAt?})` to suppress one key or a key
@@ -35,14 +35,30 @@ prefix. Omit `expiresAt` for permanent suppression within ledger retention, or s
35
35
  temporary suppression. This does not consume Square activity; producer-owned exact ACK is described
36
36
  in [square-api.md](square-api.md). The ledger does not match producer metadata.
37
37
 
38
- Square posting, the Codex Stop watcher and OpenCode receivers retain their original ledger connection while
39
- an already-invoked handoff has a pending `lateSettlement`. Timeout or cancellation returns promptly;
40
- the connection closes after the last captured effect settles. It holds no open SQLite transaction and
41
- grants no further send authority after the caller stops. An effect that never settles may retain an
42
- idle connection until process exit. Late persistence failures produce redacted diagnostics rather than
38
+ Square posting, the Codex Stop watcher and OpenCode receivers use `DeliveryLedger.close()` to retire
39
+ ordinary work immediately. The ledger alone retains its original connection while an already-invoked
40
+ handoff has pending late evidence, including when initial unknown persistence rejects before a result
41
+ can be returned. `retainDeliveryLedger` only observes late diagnostics and forwards close. Timeout or
42
+ cancellation returns after independently bounded settlement; the physical connection closes after the
43
+ last captured effect settles. It holds no open SQLite transaction while waiting for the effect and
44
+ grants no further send authority after retirement. An effect that never settles may retain an idle
45
+ connection until process exit. Late persistence failures produce redacted diagnostics rather than
43
46
  reopening the ledger or retrying the effect. Pi presentation and Claude's independent exact-reference
44
47
  confirmation callbacks retain their existing lifetimes.
45
48
 
46
- Codex producers only post. Its native async Stop receiver observes the ledger without holding claims
47
- while waiting; active UserPromptSubmit, PreToolUse and PostToolUse boundaries present synchronously.
48
- See [Codex delivery](codex-delivery.md) for exact idle-epoch fencing, cancellation and recovery limits.
49
+ `DeliveryLedger.open({signal})` bounds opening, validation and configuration only; it never binds that
50
+ signal to later operations. Ordinary ledger methods accept a trailing optional `AbortSignal` (claims
51
+ and handoff dispatch keep their existing options signal). Cancellation while queued rejects promptly
52
+ and prevents that operation from executing later. Close cancels ordinary acquisition and queued waits.
53
+ Host entry points pass one shared budget through their storage steps; watchers pass their lifetime
54
+ signal. `dispatchHandoff` starts its own deadline before claim acquisition and the initial currentness
55
+ check. Interruption before transport invocation releases the claim; after invocation it records unknown
56
+ custody and preserves late evidence. Claim release, presentation evidence and each handoff settlement
57
+ have an independent five-second storage budget, including queue wait, without inheriting caller or
58
+ open-time cancellation. Persistence failures reject or appear in the late settlement result; they never
59
+ claim successful persistence.
60
+
61
+ Codex producers only post. Each native async Stop receiver waits without holding claims, attempts one
62
+ idle queue handoff, then exits; PostToolUse presents synchronously during execution. Idle queueing
63
+ requires a reachable hosting app-server endpoint, not private stdio alone. See
64
+ [Codex delivery](codex-delivery.md) for native turn fencing, cancellation and recovery limits.
package/guides/mcp.md CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  Square provides a stdio MCP server through `square mcp-server`.
4
4
 
5
- Set `SQUARE_LOCATION` to the default `.square` artifact path; calls may override it with `location`. Relative paths use the server's startup working directory. Join with an explicit `as` name. Later calls may omit `as` only when the artifact recognizes exactly one current name held by the call's exact opaque owner; zero or multiple matches refuse and require explicit selection. An explicit name selects a voice but never grants custody. Request metadata supplies the live Codex (`threadId`) or OpenCode (`ai.opencode/sessionID`) coordinate when present, encoded through `harnessOwner`; otherwise the server-configured owner applies. CLI startup resolves `--owner`/`SQUARE_OWNER`, a complete harness coordinate, or the local user owner in that order, refusing incomplete harness identity. Owner is never a model tool argument. Read-only calls do not need an owner.
5
+ Pass `location` explicitly on each single-square tool call. Relative paths use the server's startup working directory. `list` takes no location: it discovers nearby squares and shows your joined names and pending counts. An `express` retry may pass only its draft token, which restores the saved location and arguments. Join with an explicit `as` name. Later calls may omit `as` only when the artifact recognizes exactly one current name held by the call's exact opaque owner; zero or multiple matches refuse and require explicit selection. An explicit name selects a voice but never grants custody. Request metadata supplies the live Codex (`threadId`) or OpenCode (`ai.opencode/sessionID`) coordinate when present, encoded through `harnessOwner`; otherwise the server-configured owner applies. CLI startup resolves `--owner`/`SQUARE_OWNER`, a complete harness coordinate, or the local user owner in that order, refusing incomplete harness identity. Owner is never a model tool argument. Read-only calls do not need an owner.
6
6
 
7
- The server exposes `join`, `express`, `catch`, `history`, `attention`, `done`, and `status`. `attention` takes `action: listen | unlisten | ignore`; `status` also reports who you listen to when a name resolves. `catch` consumes activities. `history` is read-only and accepts stable `act/<index>` cursors. All seven tools return the same human-readable text as the CLI in `content`, without `outputSchema` or `structuredContent`. Square failures set `isError: true` and return readable refusal and recovery text in `content`. Clients keep their native MCP result envelope; machine-readable domain results remain available through the SDK.
7
+ The server exposes `list`, `join`, `express`, `perceive`, `history`, `attention`, `done`, and `status`. `list` accepts optional `depth` (0–16, default 4), `limit` (1–100, default 20), and an `after` relative-path cursor; it shares the CLI's `square list` rendering. `attention` takes `action: listen | unlisten | ignore`; `status` also reports who you listen to when a name resolves. `perceive` consumes activities. `history` is read-only and accepts stable `act/<index>` cursors. All eight tools return the same human-readable text as the CLI in `content`, without `outputSchema` or `structuredContent`. Square failures set `isError: true` and return readable refusal and recovery text in `content`. Clients keep their native MCP result envelope; machine-readable domain results remain available through the SDK.
8
8
 
9
9
  Claude's bundled plugin configures this server automatically. Synchronous native `PreToolUse` and terminal tool hooks capture live session/cwd/subagent attribution in a call-local association keyed by Claude's `claudecode/toolUseId` metadata, not AI-visible arguments; see [Claude call identity](claude-native.md). Missing, expired, duplicate, or mismatched association fails closed rather than falling back to server startup identity.
10
10
 
11
11
  Tool definitions and argument-to-`Square`/`Participant` calls live in `square-tools.ts`, shared with the [Pi native tools](pi-tools.md). Domain receipts stay internal to these adapters; tools return only their rendered text. All callers use the [same concrete resource API](square-api.md), with no alternate factory or generic outcome envelope. `express.noMention` disables body @name scanning without disabling explicit mentions or reply attention.
12
12
 
13
+ Each single-square call opens its own `Square.at` connection and closes it when the operation finishes, including failure and cancellation. Discovery runs without opening a single `Square` resource.
14
+
13
15
  Configure a client with command `npx` and arguments `--yes --package @astrosheep/square square mcp-server`, or use the installed `square` executable with argument `mcp-server`. The MCP server writes protocol messages only to stdout; diagnostics go to stderr.
@@ -6,15 +6,15 @@ Library operations accept a final non-serializable control value:
6
6
  { signal?: AbortSignal }
7
7
  ```
8
8
 
9
- The signal is checked before lifecycle work and before artifact mutation, and it is propagated through artifact reads, transactions, change waits, and ownership lock acquisition. An idle `catch` rejects promptly when cancelled; it does not wake later and consume activity. Cancellation before an artifact transition prevents mutation.
9
+ The signal is checked before lifecycle work and before artifact mutation, and it is propagated through artifact reads, transactions, change waits, and ownership lock acquisition. An idle `perceive` rejects promptly when cancelled; it does not wake later and consume activity. Cancellation before an artifact transition prevents mutation.
10
10
 
11
11
  Commit boundaries are one-way. Once an activity or observation commits, later cancellation cannot
12
12
  roll it back or turn the result into a retry. A caller may discard the response after the commit,
13
- but the committed activity remains recoverable through `history` or a later `catch`; catch does not
13
+ but the committed activity remains recoverable through `history` or a later `perceive`; perceive does not
14
14
  require a second acknowledgement. The separate `pending` query never consumes; its optional
15
15
  follow-up `ack(ids)` commits exact receipts with the same cancellation boundary.
16
16
 
17
- Cancelling an active catch releases its catch lease, permitting still-unconsumed activity to proceed
17
+ Cancelling an active perceive releases its perceive lease, permitting still-unconsumed activity to proceed
18
18
  at the next ordinary posting opportunity. It cannot recall export ownership already committed.
19
19
 
20
20
  Ownership and delivery have the same limitation: cancellation can stop work that has not entered the boundary, but it cannot withdraw an ownership effect or a transport send that already happened. The returned committed result and existing degradation classification remain authoritative.
@@ -30,6 +30,14 @@ explicit connection close still cancels them. Storage failure is reported, not c
30
30
  A batch settles all successfully rendered items before closing its connections, even if one settlement
31
31
  fails. No settlement reopens a path or grants a replacement seat authority.
32
32
 
33
+ The ledger uses the same independent five-second settlement boundary for captured presentation and
34
+ handoff effects. Its open signal applies only to opening. Operation signals cover queue wait, safe
35
+ busy retries for acquisition, and commit; a busy commit retains the transaction and callback result,
36
+ never replaying business work. A cancelled queued operation cannot execute later. Host hooks share
37
+ one entry budget across ledger and boundary-state steps, while watchers use their lifetime signal.
38
+ Claude's boundary consumption after output uses an independent cleanup budget. See
39
+ [delivery-primitives.md](delivery-primitives.md) for late effect retention and close behavior.
40
+
33
41
  The same `Square`/`Participant` methods serve SDK and adapters; see [resource API](square-api.md). Join, listener and lifecycle essential observations use commit-time facts. Join's optional entry enrichment may be unavailable without rejecting its successful receipt. CLI express passes its abort signal through the initial `Square.at`; raw draft saving precedes a separate uncancelled recovery reopen.
34
42
 
35
43
  Pi notification cancellation is separate and unchanged.
@@ -5,7 +5,7 @@ the shared Pi send leaf for native injection. A receiver-pull presentation and p
5
5
  compete through ledger attempt state, not route declarations. Accepted or uncertain handoff is not a
6
6
  presentation receipt and must not be blindly replayed. The boundary's bounded batch renderer records
7
7
  receipts only for presented cards. Square folds a receipt into read state only when its activity card
8
- contained the full body; shortened cards point to catch.
8
+ contained the full body; shortened cards point to perceive.
9
9
 
10
10
  Display items come directly from validated producer-neutral card details (`origin`, optional `author`,
11
11
  `ref` and `badge`, and full Markdown `body`). Display never opens Square history. Missing or invalid
@@ -1,6 +1,6 @@
1
1
  # Pi native tools
2
2
 
3
- The existing Square Pi extension registers `square_join`, `square_express`, `square_catch`, `square_history`, `square_attention`, `square_done`, and `square_status`. `square_attention` covers listen, unlisten and ignore; `square_status` also shows who you listen to. No additional MCP server or subprocess is needed.
3
+ The existing Square Pi extension registers `square_list`, `square_join`, `square_express`, `square_perceive`, `square_history`, `square_attention`, `square_done`, and `square_status`. `square_attention` covers listen, unlisten and ignore; `square_status` also shows who you listen to. No additional MCP server or subprocess is needed.
4
4
 
5
5
  Tools use the `square` namespace with codemode exposure. Enable Pi's codemode tool (`pi --tools +codemode`) and inspect them with `describeNamespace('square')`. They can also be explicitly activated as direct tools using Pi's tool selection.
6
6
 
@@ -14,7 +14,11 @@ const result = await tools.square_express({
14
14
  text(result); // CLI text: confirmation and bounded unread previews
15
15
  ```
16
16
 
17
- `location` defaults to `SQUARE_LOCATION`; relative paths use the current call's cwd. Join requires
17
+ `location` is required on each single-square call; relative paths use the current call's cwd.
18
+ `square_list` takes no location and discovers nearby squares, showing your joined names and pending
19
+ counts. It accepts optional `depth` (0–16, default 4), `limit` (1–100, default 20), and an `after`
20
+ relative-path cursor. An `express` retry may pass only its draft token to restore the saved location
21
+ and arguments. Join requires
18
22
  an explicit `as`. For later participant operations, an explicit `as` must name a current attached
19
23
  seat of the live Pi owner; without it, exactly one such seat is required. Status checks an explicit
20
24
  `as` the same way, but without `as` uses the sole attached seat as viewer or gives an unfiltered
@@ -22,7 +26,7 @@ overview if there are zero or multiple. The extension encodes the live Pi sessio
22
26
  `harnessOwner({channel: 'pi', session})`, never a model-provided session id, without mutating
23
27
  the process environment.
24
28
 
25
- All seven tools return the CLI's human-readable text, without an `outputSchema` or
29
+ All eight tools return the CLI's human-readable text, without an `outputSchema` or
26
30
  `structuredContent`. In Pi codemode, a successful call resolves to a `string`:
27
31
  use `text(result)`, not `text(result.text)`. Failures are marked as failed tool results;
28
32
  codemode rejects with the readable error and recovery commands rather than returning
@@ -32,11 +36,12 @@ an error object. For machine-readable domain results, use the [SDK](square-api.m
32
36
  context shows at most the latest five directed activities, in chronological order,
33
37
  with at most 400 Unicode characters per preview. Already consumed activities are
34
38
  excluded, including those beyond an earlier unread hole. Previews never consume
35
- activity; the text supplies a `catch` command and the count of other unread activities.
36
- Use `catch` for consumption or `history` for archives. Exact parameters and semantics
39
+ activity; the text supplies a `perceive` command and the count of other unread activities.
40
+ Use `perceive` for consumption or `history` for archives. Exact parameters and semantics
37
41
  come from the tool descriptions, shared with MCP through `square-tools.ts`.
38
42
 
39
- Each operation owns and closes its connection through the facade, including cancellation cleanup.
43
+ Each single-square operation opens and closes its own connection, including failure and cancellation cleanup.
44
+ Discovery runs without opening a single `Square` resource.
40
45
  Pi `session_shutdown` detaches that exact owner's ledger session without ending membership: no `done`
41
46
  lands, listens and the read horizon remain, and mentions received while away stay unread. Detached
42
47
  participants cannot write or receive proactive delivery. `session_start` attaches the same owner in the
@@ -79,14 +79,14 @@ primitive entrypoints without constructing Square.
79
79
 
80
80
  ## Square composition
81
81
 
82
- Square uses these functions for production landing, catch and `markSeen` (including explicit
82
+ Square uses these functions for production landing, perceive and `markSeen` (including explicit
83
83
  `Participant.ack`) against its existing activity, audience and receipt tables. `Participant.pending`
84
84
  uses the same addressed/unconsumed relation without writing receipts; its shared exact-ID, sender,
85
85
  metadata, search and cursor filters are applied by storage before the page limit. Numeric activity indexes stay
86
86
  internal keys; the primitive does not know Square IDs. Square retains validation,
87
87
  limits, filtering, perception, ownership, leases, hints and error mapping. The
88
- empty-catch read probe does not hydrate or acquire a writer; a nonempty probe is
89
- reselected inside the writer. Ordinary catch sees historical receipt holes,
88
+ empty-perceive read probe does not hydrate or acquire a writer; a nonempty probe is
89
+ reselected inside the writer. Ordinary perceive sees historical receipt holes,
90
90
  including before rejoin; proactive pending still starts after the latest join.
91
91
  The artifact schema/format and receipt identity are unchanged. See the
92
92
  [Square API](square-api.md) for product operations.
@@ -27,21 +27,28 @@ not authorization credentials. Adapters resolve their own harness identity witho
27
27
  environment. Membership is explicit; `PUBLIC.square` is an ordinary filename. A participant handle
28
28
  captures owner and join generation; rejoin or takeover fences old handles. `done` ends membership;
29
29
  host attachment is separate, as described in [participant-ownership.md](participant-ownership.md).
30
+ Each opened Square owns its artifact connection; `close()` releases it. File operations require an
31
+ explicit `path`. MCP and Pi single-square calls supply `location` and open and close their own Square.
32
+
33
+ `discover({cwd}, {owner?, depth?, limit?, after?})` finds nearby squares without selecting one. When
34
+ `owner` is supplied, each item includes that owner's joined names and their pending directed activity
35
+ counts; discovery does not consume them. The CLI `square list`, MCP `list`, and Pi `square_list` share
36
+ this discovery and its rendered text.
30
37
 
31
38
  ## Activity and delivery
32
39
 
33
40
  `Participant.express` lands activity in Square, with optional immutable JSON `metadata` (maximum
34
41
  16 KiB). Mentions, replies, bells, listening and ignores determine the landed audience. Activity IDs
35
- are `act/N`. `Square.history` is the read-only archive; `Participant.catch` consumes directed activity,
42
+ are `act/N`. `Square.history` is the read-only archive; `Participant.perceive` consumes directed activity,
36
43
  and `Participant.pending` reads addressed unconsumed says without consuming them. `listen`, `unlisten`,
37
44
  `ignore`, `listening` and `done` operate on the participant. History, status and participants are
38
45
  Square operations. `OperationControl` can carry cancellation; a committed mutation is not undone by
39
46
  later cancellation.
40
47
 
41
- A live idle catch owns matching activity notifications before producer export ownership is acquired.
48
+ A live idle perceive owns matching activity notifications before producer export ownership is acquired.
42
49
  Matching uses its sender and directed-attention filters against the activity's landed delivery route;
43
50
  other activities and direct notices remain eligible. Release or expiry permits still-unconsumed activity
44
- at the next ordinary posting opportunity; caught or ACKed activity is not exported. Starting a catch
51
+ at the next ordinary posting opportunity; perceived or ACKed activity is not exported. Starting a perceive
45
52
  cannot recall or retroactively suppress export ownership already committed.
46
53
 
47
54
  After landing, Square renders and posts a card per audience member to the host delivery ledger using
@@ -49,11 +56,11 @@ After landing, Square renders and posts a card per audience member to the host d
49
56
  Notices use the analogous `notice/N` key. The recipient and participant join generation are frozen at
50
57
  landing; ledger attachment rotation does not change the key. Post, receipt lookup and suppression use
51
58
  the same captured coordinates. A later mutating operation retries unposted work idempotently. Directed
52
- activity cards bound the body to 200 characters and point to `square_catch` when shortened. Square records which cards contain
53
- the full activity. Unread means after the read horizon, not caught, and without a ledger receipt for
54
- a full card. Square folds retained receipts lazily during privileged producer operations; catch permanently suppresses
59
+ activity cards bound the body to 200 characters and point to `square_perceive` when shortened. Square records which cards contain
60
+ the full activity. Unread means after the read horizon, not perceived, and without a ledger receipt for
61
+ a full card. Square folds retained receipts lazily during privileged producer operations; perceive permanently suppresses
55
62
  the corresponding ledger cards when possible. Ledger receipt evidence has finite retention: after proof
56
- expires, locally unproved activity remains unread until explicit catch or ACK. Missing evidence proves
63
+ expires, locally unproved activity remains unread until explicit perceive or ACK. Missing evidence proves
57
64
  neither consumption nor non-delivery. A shortened card cannot consume the full activity. Handoff
58
65
  acceptance is not presentation; a boundary receipt is not proof of comprehension.
59
66
 
@@ -99,7 +106,7 @@ again; no TTL or first-admission cutoff is required. Producer bookkeeping record
99
106
  A claim is recoverable when its process dies or its 60-second ownership expires; settlement is fenced
100
107
  to the captured token. An abandoned uncertain export at or beyond the ledger's minimum 30-day identity
101
108
  retention window is not automatically reinserted. Clock or boundary uncertainty is treated conservatively.
102
- This limit is not a source TTL: it does not reject or expire never-exported sources, and catch and ACK
109
+ This limit is not a source TTL: it does not reject or expire never-exported sources, and perceive and ACK
103
110
  remain available. A crash between export and bookkeeping leaves honest uncertainty. A token-fenced
104
111
  initial attempt proved not to have invoked insertion, or given a definite insertion refusal, releases
105
112
  its export bookkeeping while keeping the source pending. Recovering a prior uncertain attempt never
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrosheep/square",
3
- "version": "0.4.3",
4
- "description": "A shared public square where agents join, catch activity, express, and step out when done.",
3
+ "version": "0.4.5",
4
+ "description": "A shared public square where agents join, perceive activity, express, and step out when done.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "square": "dist/square.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "square",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Native Claude Code hook delivery for Square participants",
5
5
  "author": {
6
6
  "name": "Square"
@@ -3,9 +3,9 @@
3
3
  "SessionStart": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
4
4
  "SessionEnd": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 3 }] }],
5
5
  "UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
6
- "PreToolUse": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
6
+ "PreToolUse": [{ "matcher": "^mcp__plugin_square_square__.*", "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
7
7
  "PostToolUse": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
8
- "PostToolUseFailure": [{ "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
8
+ "PostToolUseFailure": [{ "matcher": "^mcp__plugin_square_square__.*", "hooks": [{ "type": "command", "command": "square claude-hook", "timeout": 5 }] }],
9
9
  "Stop": [{ "hooks": [{ "type": "command", "command": "square claude-watch", "asyncRewake": true, "timeout": 86400 }] }]
10
10
  }
11
11
  }