pi-herdsman 0.1.0

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.
@@ -0,0 +1,203 @@
1
+ # Supervision reference
2
+
3
+ [Documentation index](../README.md) · [Concept](../concepts/supervision.md)
4
+
5
+ This is the current chief and staff contract for Pi Herdsman. Exact live
6
+ identity and fresh authority checks are authoritative; presentation state and
7
+ metadata are not.
8
+
9
+ ## Role, lease, and lead state
10
+
11
+ `/chief` is available to an eligible lead. The session role is persisted as
12
+ `customType: "pi-herdsman-role"` with `role: "lead"` or `"chief"`. A malformed
13
+ role fails closed and records a durable error. There is at most one active
14
+ chief for an exact `HERDR_SOCKET_PATH`; its descriptor is bound to the exact
15
+ process-lock claim and Pi session identity.
16
+
17
+ Every lead has one private atomic record in the supervision runtime's `leads/`
18
+ directory, keyed by the SHA-256 hash of its exact Pi session ID:
19
+
20
+ ```json
21
+ {
22
+ "version": 1,
23
+ "instanceId": "<lead generation>",
24
+ "piSessionId": "<exact Pi session ID>",
25
+ "pendingAsk": { "askId": "<id>", "question": "<text>" },
26
+ "updatedAt": 0
27
+ }
28
+ ```
29
+
30
+ `pendingAsk` is optional. The latest matching `pi-herdsman-lead-state` session
31
+ entry is authoritative during lead startup. A fresh `instanceId` is created
32
+ for every initialization. The lead record is checked against exact live
33
+ Herdr/Pi identity; missing, malformed, stale, duplicate, or ambiguous evidence
34
+ fails closed. The record is bounded to 2 KiB. Questions are limited to 1,024
35
+ characters and 1,024 UTF-8 bytes.
36
+
37
+ The record does not represent scheduling, capacity, permission, or message
38
+ readiness. Herdr lifecycle observation is normalized to
39
+ `idle|working|blocked|done|unknown`.
40
+
41
+ Chief is a mode of a lead session. While active, its model has exactly the
42
+ `staff` tool. Project/workspace context files and skills are excluded from
43
+ chief model context; workspace-specific work remains the responsibility of
44
+ supervised leads. `/chief leave` restores the session's ordinary tools.
45
+
46
+ ## Lead projection and actions
47
+
48
+ An eligible lead requires one exact live recognized Pi agent, a matching lead
49
+ record, and no chief or validated managed-worker identity. A lead's observed
50
+ runtime state is informational. Every exact-identity-verified live lead has
51
+ `inspect` and `message`, whether it is idle, working, blocked, done, or unknown.
52
+ A pending ask is separate attention state: it projects as `needs_you`, exposes
53
+ the bounded question and ask ID, and adds `reply`.
54
+
55
+ The `staff list` representation contains `lead` (the exact full Pi session ID),
56
+ `display_name` (a presentation-only label), identity fields, `runtime_state`,
57
+ `needs_you`, optional pending-ask fields, `worker_counts`, optional
58
+ `last_activity`, and `available_actions`. The automatic
59
+ `<supervision_state>` context is hard-bounded to 16 KiB and uses
60
+ `leads`, `worker_counts`, and `workers`. Oversized output is truncated only at
61
+ complete lead records and identifies omitted state. Use `staff list` when a
62
+ fresh complete roster is required.
63
+
64
+ The `lead` value is the exact full Pi session ID shown in a fresh supervision
65
+ snapshot or returned by `staff list`; the `display_name` label is never accepted
66
+ as a target.
67
+
68
+ ## Metadata
69
+
70
+ Pi Herdsman may publish best-effort Herdr metadata for display:
71
+
72
+ ```text
73
+ source: pi-herdsman:lead
74
+ pi_herdsman_role=lead
75
+ pi_herdsman_ask=<ask-id>
76
+ pi_herdsman_name=<session name>
77
+ ```
78
+
79
+ Chief mode publishes the role token `chief`. Metadata never grants lead
80
+ eligibility, chief authority, or message authority. Failed metadata
81
+ publication does not change communication authority.
82
+
83
+ ## Chief transport
84
+
85
+ Messages are bounded, versioned JSON files in the target session's hashed
86
+ `inbox/` directory. Each record includes exact sender, target, `leadSessionId`,
87
+ chief lease, kind, ID, text, and `createdAt`; asks and replies also include an
88
+ ask ID. Extra fields are rejected. Transport kinds are:
89
+
90
+ ```text
91
+ chief_message
92
+ lead_message
93
+ lead_ask
94
+ chief_reply
95
+ ```
96
+
97
+ Records are delivered in `createdAt`, then ID order and accepted through Pi
98
+ follow-up delivery. Chief messages may queue while a lead works. Same-session
99
+ restart preserves queued records, accepted IDs are deduplicated, and an
100
+ individual quarantined record does not block a new record for that lead.
101
+ Transient identity, authority, or delivery failures retain records. Exact
102
+ identity and chief lease checks are never weakened.
103
+
104
+ ## `chief`
105
+
106
+ This tool is available only to an ordinary lead. Its strict schemas reject
107
+ extra fields. Both actions require a currently valid chief; descendants use
108
+ `ask_owner`, never `chief`.
109
+
110
+ ### `message`
111
+
112
+ ```json
113
+ { "action": "message", "message": "Build completed." }
114
+ ```
115
+
116
+ Use `message` for meaningful progress, reports, results, warnings, and
117
+ completion. It queues one bounded `chief_message` and does not change lead
118
+ coordination state.
119
+
120
+ ### `ask`
121
+
122
+ ```json
123
+ { "action": "ask", "question": "Should the release include the endpoint?" }
124
+ ```
125
+
126
+ Use `ask` only when a chief decision is genuinely required. One pending ask is
127
+ allowed per lead. The call durably records its ask ID and question, then queues
128
+ the question. It is a terminating coordination call: make it the final tool
129
+ call of the turn and wait rather than guessing.
130
+
131
+ ## `staff`
132
+
133
+ This tool is available only to the active chief. Its target `lead` must be the
134
+ exact full Pi session ID shown as `lead` in a fresh automatic supervision
135
+ snapshot or returned by `staff list`; never use `display_name`.
136
+
137
+ For general state questions and ordinary messages or replies, use the fresh
138
+ automatic supervision snapshot directly; do not call `staff list`, `inspect`,
139
+ or another read command first. The `message` and `reply` actions perform their
140
+ own authoritative validation. Use `list` when the snapshot is stale or
141
+ unavailable, an immediately refreshed roster is materially necessary, or
142
+ diagnosis is required. Use `inspect` only when deeper lead evidence is needed.
143
+
144
+ ### `list`
145
+
146
+ ```json
147
+ { "action": "list" }
148
+ ```
149
+
150
+ Returns a fresh supervision projection and fresh `available_actions`.
151
+
152
+ ### `inspect`
153
+
154
+ ```json
155
+ {
156
+ "action": "inspect",
157
+ "lead": "<exact full Pi session ID shown as lead in a fresh snapshot>"
158
+ }
159
+ ```
160
+
161
+ Inspect is read-only and requires an active chief and eligible exact lead. It
162
+ returns bounded identity-checked recent output and process evidence.
163
+
164
+ ### `message`
165
+
166
+ ```json
167
+ {
168
+ "action": "message",
169
+ "lead": "<exact full Pi session ID shown as lead in a fresh snapshot>",
170
+ "message": "Run checks."
171
+ }
172
+ ```
173
+
174
+ The exact lead must currently expose `message`. Atomic creation of one bounded
175
+ `chief_message` record queues a follow-up and does not wait for completion.
176
+
177
+ ### `reply`
178
+
179
+ ```json
180
+ {
181
+ "action": "reply",
182
+ "lead": "<exact full Pi session ID shown as lead in a fresh snapshot>",
183
+ "askId": "<exact pending ask ID>",
184
+ "message": "Proceed."
185
+ }
186
+ ```
187
+
188
+ The exact lead, unchanged pending ask ID, current lead identity, and chief
189
+ lease must validate. The pending ask is cleared only after accepted delivery.
190
+
191
+ ## UI and failure rules
192
+
193
+ The `/chief` command is state-sensitive. From an ordinary lead, `/chief`
194
+ activates chief mode and shows the ambient widget. While already active as
195
+ chief, `/chief` opens the interactive overview. `/chief leave` leaves chief
196
+ mode and removes the widget.
197
+
198
+ The active chief gets a width-aware compact leads-only ambient widget and a
199
+ native `/chief` overview with peek and focus. Leads are ordered by needs-you,
200
+ working, blocked, idle/done, then unknown. The ambient widget uses
201
+ presentation-only tree branches for visible lead rows, while the native
202
+ overview stays flat. Missing, replaced, ambiguous, or conflicting identity
203
+ fails closed. There is no descendant selector or force-takeover action.
@@ -0,0 +1,57 @@
1
+ # Worker states
2
+
3
+ [Documentation index](../README.md)
4
+
5
+ The public state is a safe-control projection built from live lifecycle and
6
+ durable assignment/convergence evidence. It is not a raw herdr lifecycle string.
7
+
8
+ | State | Meaning |
9
+ | ---------- | ----------------------------------------------------------------------------------------------------- |
10
+ | `working` | An assignment is active. |
11
+ | `blocked` | Active assignment waits for owner attention or another condition. |
12
+ | `settling` | Assignment handoff, completion/result delivery, launch, direct-worker gate, or cleanup is converging. |
13
+ | `unknown` | Exact safe control state cannot be proved. |
14
+
15
+ ## `available_actions` is authoritative
16
+
17
+ A live worker record in `worker list` includes an `available_actions` snapshot.
18
+ Use only operations currently listed there; do not infer control eligibility
19
+ from `state` alone. `steer` means active work accepts steering, `reply` means a
20
+ correlated pending `ask_owner` is valid, and `close` means exact ownership or
21
+ approved orphan recovery permits teardown. `available_actions` never includes
22
+ `delegate`; a worker generation handles one assignment only. Every operation
23
+ revalidates identity, ownership, mailbox state, and lifecycle immediately before
24
+ mutation.
25
+
26
+ A delegating worker may be blocked while direct worker work is pending and still accept
27
+ steering when `steer` is listed. Descendant visibility does not imply authority;
28
+ records outside the controller's direct ownership can have an empty action list.
29
+
30
+ ## `blocked` and owner questions
31
+
32
+ A worker waiting on a valid `ask_owner` reply projects as `blocked` after its ask
33
+ turn settles. Answer through the exact direct owner using `reply.worker`.
34
+
35
+ ## `settling`
36
+
37
+ Examples include an uncompleted task handoff, pending final result delivery,
38
+ direct-worker gating, terminal cleanup, result persistence recovery, and startup
39
+ or integration handoff. Do not assign another task to a settling worker.
40
+
41
+ ## `unknown`
42
+
43
+ Unknown is intentional fail-closed behavior. Unreadable, oversized, malformed,
44
+ or validation-failing mailbox state is reported with a bounded diagnostic and an
45
+ empty `available_actions` list. Do not substitute pane idleness, elapsed time,
46
+ model metadata, missing activity, a guessed session, or an old worker identity.
47
+
48
+ ## Inactivity fields
49
+
50
+ A qualifying `working` worker may also report `stale`, `inactive_ms`, and
51
+ `last_activity_at`. This advisory does not change the state or prove a hang.
52
+
53
+ ## See also
54
+
55
+ - [Lifecycle](../concepts/lifecycle.md)
56
+ - [Recovery](../guides/recovery.md)
57
+ - [`worker` API](worker.md)
@@ -0,0 +1,201 @@
1
+ # `worker` API
2
+
3
+ [Documentation index](../README.md) · [supervision reference](supervision.md)
4
+
5
+ `worker` is the structured model-facing API for managed workers. It has exactly six actions:
6
+
7
+ ```text
8
+ list
9
+ delegate
10
+ steer
11
+ reply
12
+ close
13
+ inspect
14
+ ```
15
+
16
+ Unknown fields and unsupported selector combinations fail with `invalid_request`.
17
+ The tool is registered only for the lead controller and authorized delegating worker
18
+ controllers.
19
+
20
+ ## `delegate`
21
+
22
+ Delegation has exactly two strict variants. The required field (`definition` or
23
+ `session`) selects the variant; there is no target discriminator.
24
+ Every variant rejects additional properties.
25
+
26
+ ### Definition
27
+
28
+ ```json
29
+ {
30
+ "action": "delegate",
31
+ "definition": "implementer",
32
+ "task": "Implement the approved change"
33
+ }
34
+ ```
35
+
36
+ Allowed fields are `action`, `definition`, `task`, optional `label`, `cwd`,
37
+ `files`, `fork`, and `timeoutMs`. The definition is resolved from
38
+ the effective roster and delegating worker controllers may use only their allowlisted
39
+ definitions. Project definitions still require trusted project approval.
40
+ `fork`, when supplied, is an exact saved Pi session path or full UUID used as
41
+ the source for a new derived context; otherwise a new Pi session is launched.
42
+ Each accepted definition delegation creates one worker generation for one
43
+ assignment. The terminal result is delivered once and the worker is cleaned up.
44
+
45
+ ### Session
46
+
47
+ ```json
48
+ {
49
+ "action": "delegate",
50
+ "session": "<exact .jsonl path or full UUID>",
51
+ "task": "Continue the investigation"
52
+ }
53
+ ```
54
+
55
+ Allowed fields are `action`, `session`, `task`, optional `files`, and
56
+ `timeoutMs`. The exact saved session supplies its cwd, definition identity, and
57
+ historical Pi context. Session delegation always creates a new worker generation
58
+ for one assignment; it never assigns work to an existing worker. The saved
59
+ definition must currently resolve to an enabled, authorized effective
60
+ definition, whose current configuration is used for the new generation.
61
+ Concurrent or otherwise conflicting managed representations of the exact
62
+ session fail closed. The controller's own active Pi session cannot be delegated
63
+ to itself; use definition delegation with `fork` when a separate derived
64
+ context is required.
65
+
66
+ All successful delegation results use `action: "delegate"` and include
67
+ `worker`, `definition`, request, session, and startup evidence where available.
68
+ Delegation returns after durable acceptance, not completion. A terminal result
69
+ also makes the exact session identity prominent so it can be used with a later
70
+ `delegate.session` call.
71
+
72
+ ## `list`
73
+
74
+ Request:
75
+
76
+ ```json
77
+ { "action": "list" }
78
+ ```
79
+
80
+ No selectors or other fields are accepted. A successful result includes the
81
+ effective `agent_definitions` roster and visible worker records.
82
+
83
+ Each actionable live worker record includes:
84
+
85
+ | Field | Meaning |
86
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
87
+ | `worker` | Exact live logical worker identity to copy into `steer.worker`, `reply.worker`, or `close.worker`. It is not a continuation identity. |
88
+ | `state` | Safe lifecycle state for observability. |
89
+ | `available_actions` | Snapshot of operations currently eligible for this controller. |
90
+ | `workspace_id`, `pane_id`, `tab_id`, `tab_label` | Herdr identity evidence. |
91
+ | `cwd`, `pi_session_id`, `pi_session_path` | Worker location and Pi session evidence. |
92
+ | `owner_session_id` | Exact direct owner Pi session. |
93
+ | `agent_definition` | Effective definition name. |
94
+ | `active_request_id`, `last_activity_at`, `stale`, `inactive_ms` | Assignment and advisory activity evidence. |
95
+ | `parent_label`, `orphan` | Visible direct-owner ancestry and proven orphan recovery evidence. |
96
+ | `cleanup_error`, `result_error`, `diagnostic`, `tokens` | Bounded recovery and presentation evidence when present. |
97
+
98
+ `available_actions` is authoritative model guidance for the current snapshot.
99
+ Do not infer eligibility from `state`. Active work may list `steer`; a valid
100
+ correlated pending `ask_owner` may list `reply`; exact direct ownership may list
101
+ `close`. `available_actions` never lists `delegate`: a worker cannot receive a
102
+ second assignment. Descendant visibility does not grant control. Lead orphan
103
+ recovery may expose only `close`. Unknown and recovery-only records are
104
+ non-actionable. Every operation rechecks identity, ownership, mailbox state, and
105
+ lifecycle immediately before mutation.
106
+ The public record does not expose `steerable`.
107
+
108
+ Lead controllers see the complete effective definition roster and workers visible
109
+ through their ownership boundary. Delegating workers see only allowed enabled
110
+ leaf definitions and their visible workers. Unknown mailbox diagnostics remain
111
+ non-actionable.
112
+
113
+ ## `inspect`
114
+
115
+ ```json
116
+ { "action": "inspect", "worker": "implementer-1" }
117
+ ```
118
+
119
+ `inspect` accepts only `action` and the exact live worker label. It is available
120
+ only to that worker's direct owner, and only when the worker is a current,
121
+ unambiguous managed identity. The result is read-only and contains the exact
122
+ session/pane identity, a bounded tail of the most recent 40 unwrapped terminal
123
+ lines (at most 8 KiB), and advisory foreground process evidence when available.
124
+ Its model-facing text includes the worker, session, pane, useful foreground
125
+ commands, and recent activity; raw process and recent-output evidence remains
126
+ in the structured result details.
127
+ The identity is checked again after capture; if the pane or Pi session was
128
+ replaced, inspection fails closed. Inspection does not change worker state,
129
+ mailbox records, lifecycle, or available controls.
130
+
131
+ ## `files` and `timeoutMs`
132
+
133
+ `files` is valid on all `delegate` variants and on `steer` and `reply`; it is not
134
+ valid on `list` or `close`. Paths are resolved from the controller cwd, checked
135
+ as readable regular files, canonicalized with `realpath`, and embedded only
136
+ when the exact message limit permits. Otherwise they remain canonical references.
137
+
138
+ `timeoutMs` is valid on definition and session delegation and must be an integer
139
+ from `5001` through `300000`. The startup budget reserves one bounded diagnostic
140
+ window. Current message limits are governed by effective global/project/default
141
+ settings and the fixed mailbox protocol ceiling. Managed mailbox records use
142
+ protocol version 3, and control requests use the marker prefix
143
+ `__PI_HERDSMAN_WORKER_V3__:`.
144
+
145
+ ## `steer`
146
+
147
+ ```json
148
+ {
149
+ "action": "steer",
150
+ "worker": "implementer-1",
151
+ "message": "Also update the focused regression.",
152
+ "files": [".pi-herdsman/review.md"]
153
+ }
154
+ ```
155
+
156
+ Use only when `steer` is listed in `available_actions`. Steering changes the
157
+ current assignment and does not create another final result.
158
+
159
+ ## `reply`
160
+
161
+ ```json
162
+ {
163
+ "action": "reply",
164
+ "worker": "implementer-1",
165
+ "message": "Use option B."
166
+ }
167
+ ```
168
+
169
+ Use only when `reply` is listed in `available_actions` for a valid correlated
170
+ pending `ask_owner` question. The reply continues the same assignment and
171
+ contains its request, ask, assignment, and session correlation evidence.
172
+
173
+ See [`ask_owner` API](ask-owner.md).
174
+
175
+ ## `close`
176
+
177
+ ```json
178
+ { "action": "close", "worker": "implementer-1" }
179
+ ```
180
+
181
+ Only `action` and `worker` are accepted. Close requires exact direct ownership,
182
+ or the lead-only evidence-backed orphan recovery condition. Closing abandons a
183
+ pending owner question; closing a delegating worker cascades through directly
184
+ owned workers first. Cleanup remains fail-closed when exact identity or ownership
185
+ cannot be proved.
186
+
187
+ ## Result delivery and errors
188
+
189
+ An accepted delegated task remains the internal mailbox `kind: "task"` request
190
+ and has one correlated final result. Delivery goes to the exact owning Pi
191
+ session and occurs exactly once. Model-visible completion wording uses
192
+ `worker=<worker>`, `definition=<definition>`, `session=<id>`,
193
+ `request=<id>`, and status. Details retain durable `workerLabel`,
194
+ `agentDefinition`, `piSessionId`, `piSessionFile`, result paths, elapsed time,
195
+ context usage, truncation, and persistence-error evidence. The worker is cleaned
196
+ up after the terminal result is delivered; the Pi session remains available for
197
+ continuation.
198
+
199
+ Tool failures return structured details for normal public errors. See
200
+ [Errors](errors.md), [worker states](worker-states.md), and
201
+ [workers and identity](../concepts/workers.md).
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "pi-herdsman",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Asynchronous workers for Pi in herdr.",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "keywords": [
8
+ "pi-package",
9
+ "pi",
10
+ "pi-coding-agent",
11
+ "pi-extension",
12
+ "workers",
13
+ "multi-agent",
14
+ "orchestration",
15
+ "delegation",
16
+ "supervision",
17
+ "herdr",
18
+ "pi-herdsman"
19
+ ],
20
+ "pi": {
21
+ "extensions": [
22
+ "./dist/index.js"
23
+ ],
24
+ "skills": [
25
+ "."
26
+ ]
27
+ },
28
+ "scripts": {
29
+ "test": "node --experimental-test-module-mocks --experimental-strip-types --test --test-timeout=10000",
30
+ "check": "node scripts/check.mjs",
31
+ "build": "node scripts/build.mjs",
32
+ "package:audit": "node scripts/package-audit.mjs",
33
+ "release:check": "npm run check && npm run build && npm run package:audit && npm publish --dry-run --ignore-scripts",
34
+ "prepack": "npm run build"
35
+ },
36
+ "peerDependencies": {
37
+ "@earendil-works/pi-ai": "*",
38
+ "@earendil-works/pi-coding-agent": "*",
39
+ "@earendil-works/pi-tui": "*",
40
+ "typebox": "*"
41
+ },
42
+ "devDependencies": {
43
+ "@earendil-works/pi-ai": "^0.84.2",
44
+ "@earendil-works/pi-coding-agent": "^0.84.2",
45
+ "@earendil-works/pi-tui": "^0.84.2",
46
+ "esbuild": "^0.28.2",
47
+ "typebox": "^1.3.7"
48
+ },
49
+ "engines": {
50
+ "node": ">=22.19.0"
51
+ },
52
+ "files": [
53
+ "README.md",
54
+ "SKILL.md",
55
+ "LICENSE",
56
+ "docs",
57
+ "dist"
58
+ ],
59
+ "publishConfig": {
60
+ "registry": "https://registry.npmjs.org/"
61
+ }
62
+ }