taskchef 7.22.4 → 7.22.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "7.22.4",
3
+ "version": "7.22.5",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/README.md CHANGED
@@ -16,6 +16,7 @@ request -> recorded TaskChef task -> Codex executor -> request/result turn timel
16
16
  | --- | --- |
17
17
  | Install, configure, dispatch, inspect, and recover | This README |
18
18
  | Follow the normative agent contract and MCP interfaces | [Specification](docs/spec.md) |
19
+ | Understand dashboard start, upgrade, and shutdown | [Dashboard lifecycle](docs/dashboard-lifecycle.md) |
19
20
  | Understand implementation flows and trust boundaries | [Workflows](docs/workflows.md) |
20
21
  | Compare TaskChef with FirstMate | [FirstMate comparison research](docs/firstmate-taskchef-comparison.md) |
21
22
  | Review deferred ideas | [Backlog](BACKLOG.md) |
@@ -61,6 +62,8 @@ AGENTS.md managed dispatcher instructions plus user additions
61
62
  taskchef.json schema-2 Codex project index, dashboard preference, and delegation metadata
62
63
  tasks.jsonl one task snapshot per line (schema 10; schema 4-9 migration supported)
63
64
  .taskchef-usage.json optional mode-0600 ccusage snapshot and turn-boundary cache
65
+ .taskchef-dashboard-owner.json optional mode-0600 current dashboard identity and control credential; retained and atomically replaced
66
+ .taskchef-dashboard-handoff.json optional mode-0600 secret-free signed final lease snapshot; retained and atomically overwritten
64
67
  ```
65
68
 
66
69
  Index or inspect Codex projects conversationally:
@@ -238,28 +241,36 @@ $taskchef-dashboard Ensure and open the TaskChef dashboard.
238
241
  ```
239
242
 
240
243
  MCP activation and `$taskchef-dashboard` call the input-free `ensure_dashboard`
241
- MCP tool. It starts at
242
- most one dashboard inside the existing TaskChef MCP process on
243
- `127.0.0.1:3210`, or reuses a listener only when its bounded `/api/health`
244
- identity proves the exact TaskChef/dashboard-server version and the same
245
- canonical workspace. The response says `started` or `reused` and includes the
246
- stable URL, canonical workspace, and versions.
247
-
248
- The in-process dashboard closes on MCP transport close, stdin EOF, SIGINT,
249
- SIGTERM, or detected loss of the MCP process's original parent. Activating a
250
- newer TaskChef MCP can also retire an older compatible MCP-owned dashboard for
251
- the same canonical workspace through an authenticated loopback handoff. These
252
- guards reduce unnecessary orphans but do not claim that Codex supplies a
253
- restart or child-process cleanup guarantee. TaskChef adds no daemon or other
254
- OS-persistent component, and dashboard availability remains best-effort while
255
- Codex is closed.
256
-
257
- Authenticated handoff requires the older listener to use the same dashboard
258
- protocol and to have written TaskChef's private mode-0600 ownership record in
259
- that canonical workspace. A nonce-bound HMAC challenge proves the listener has
260
- the matching secret before TaskChef sends a separately authenticated graceful
261
- shutdown request. The secret is never returned by `/api/health`, sent in a
262
- request, or logged. Standalone, different-workspace, newer, malformed,
244
+ MCP tool. It starts at most one loopback dashboard scoped to the running Codex
245
+ session on `127.0.0.1:3210`, or reuses a listener only when its bounded
246
+ `/api/health` identity proves the exact TaskChef/dashboard-server version,
247
+ canonical workspace, and `session` launcher. The response says `started` or
248
+ `reused` and includes the stable URL, canonical workspace, and versions.
249
+
250
+ The dashboard is launched by MCP but is not hosted by one MCP transport. It
251
+ therefore survives an individual MCP close, stdin EOF, signal, or plugin reload.
252
+ Each MCP securely registers its original Codex parent PID; after every
253
+ registered Codex session PID disappears for a grace period, the dashboard
254
+ closes and exits. Activating an installed newer TaskChef MCP authenticates and
255
+ retires a compatible older `mcp`- or `session`-owned dashboard for the same
256
+ canonical workspace, then starts the installed version. These are best-effort
257
+ local guards, not a claim that Codex supplies a restart guarantee. TaskChef adds
258
+ no daemon or OS-persistent component. See the complete
259
+ [dashboard lifecycle](docs/dashboard-lifecycle.md).
260
+
261
+ Authenticated handoff requires the older listener to have written TaskChef's
262
+ private mode-0600 ownership record in that canonical workspace. A nonce-bound
263
+ HMAC challenge proves the listener has the matching secret before TaskChef
264
+ sends an authenticated two-phase handoff. A session listener prepares by
265
+ fencing ordinary joins, adding the activating Codex PID, and returning a signed
266
+ bounded lease snapshot while remaining live. A separate authenticated commit
267
+ allows a short concurrent-activator grace, returns the signed final immutable
268
+ lease set, and then schedules graceful shutdown after a bounded response-retry
269
+ window. A mode-`0600`, secret-free, signed final-snapshot record permits exact
270
+ lease recovery if every commit response is lost; a prior MCP-owned listener
271
+ receives a separately authenticated graceful shutdown request. The secret is never
272
+ returned by `/api/health`, sent in a request, or logged. Standalone,
273
+ different-workspace, newer, malformed,
263
274
  unverified, and spoofed listeners are left untouched. Versions predating this
264
275
  protocol cannot be taken over safely and may require one final manual cleanup.
265
276
  The ownership record is durable metadata: shutdown retains it, and the next
@@ -330,9 +341,10 @@ pricing modes. ccusage 20.0.20 may omit GPT-5.6 cache-write charges, so TaskChef
330
341
  labels that analyzer limitation instead of presenting the estimate as complete.
331
342
  The header shows the running TaskChef package version reported by the same
332
343
  bounded health identity used for compatible-listener checks.
333
- The canonical port is owned by a dashboard initialized in the TaskChef MCP host
334
- before its tool transport connects. Health identity records an `mcp` launcher,
335
- and MCP recovery reuses only another exact-compatible MCP-launched dashboard;
344
+ The canonical port is owned by a dashboard session process initialized by the
345
+ TaskChef MCP before its tool transport connects. Health identity records a
346
+ `session` launcher, and MCP recovery reuses only another exact-compatible,
347
+ authenticated session dashboard;
336
348
  a foreground `taskchef dashboard` process is intentionally standalone so its
337
349
  child commands cannot silently inherit an agent-shell sandbox.
338
350
  Task and result times are relative through 29 days (with minute detail for the
@@ -419,14 +431,14 @@ does not necessarily reload Codex. Then run `$taskchef-dashboard` (or call
419
431
 
420
432
  - the expected released TaskChef version;
421
433
  - the expected dashboard protocol `serverVersion`;
422
- - the `mcp` dashboard launcher;
434
+ - the `session` dashboard launcher;
423
435
  - the canonical TaskChef workspace path;
424
436
  - the canonical `http://127.0.0.1:3210/` URL.
425
437
 
426
438
  The release-install sequence is therefore: install plugin, activate or reload
427
439
  the new MCP process, ensure the dashboard, then verify TaskChef version,
428
- protocol `serverVersion`, `mcp` launcher, canonical workspace, and URL.
429
- Exact-compatible MCP servers may be reused; standalone and unknown listeners
440
+ protocol `serverVersion`, `session` launcher, canonical workspace, and URL.
441
+ Exact-compatible session servers may be reused; standalone and unknown listeners
430
442
  remain untouched.
431
443
 
432
444
  If autostart reports a **verified older TaskChef** listener, the port occupant
@@ -0,0 +1,168 @@
1
+ # Dashboard lifecycle
2
+
3
+ This document defines how the canonical TaskChef dashboard starts, survives MCP
4
+ reloads, changes version, and stops. The [specification](spec.md) is normative;
5
+ the [README](../README.md) covers user operation, and
6
+ [workflows](workflows.md) maps these guarantees to implementation.
7
+
8
+ ## Ownership model
9
+
10
+ The canonical dashboard is a loopback-only process scoped to a running Codex
11
+ application session. It is launched and maintained by TaskChef MCP activation,
12
+ but it is not hosted by one MCP transport. This distinction lets the dashboard
13
+ survive an individual MCP EOF, signal, transport close, or plugin reload while
14
+ other TaskChef MCP transports in the same Codex session continue using it.
15
+
16
+ TaskChef does not install a daemon, login item, lifecycle hook, or privileged
17
+ service. A foreground `taskchef dashboard` process remains a separate
18
+ `standalone` launcher and is never adopted as the canonical session dashboard.
19
+
20
+ The dashboard was originally moved into the MCP runtime so the experimental
21
+ chat-archive action could inherit the MCP host environment. That action is now
22
+ disabled because Codex does not expose a reliable supported app-callable
23
+ archive interface. The dashboard still benefits from MCP activation,
24
+ workspace resolution, and startup isolation, but none of those requires the
25
+ HTTP listener to share one MCP transport's lifetime. The session process keeps
26
+ those benefits without retaining the obsolete per-transport ownership.
27
+
28
+ ## Start and reuse
29
+
30
+ Unless `dashboard.autostart` is explicitly `false`, MCP activation runs the
31
+ same serialized ensure operation exposed by `ensure_dashboard` before the MCP
32
+ transport connects. An explicit ensure remains available when autostart is
33
+ disabled. Failure is isolated from MCP tool startup and emits only a bounded,
34
+ non-sensitive diagnostic.
35
+
36
+ The canonical session manager requires an explicit nonzero port and normally
37
+ binds `127.0.0.1:3210`; ephemeral port zero remains available only to direct
38
+ foreground/server callers that own the returned listener. Reuse requires an
39
+ exact bounded health identity:
40
+
41
+ - TaskChef dashboard service and health schema;
42
+ - installed TaskChef version;
43
+ - dashboard protocol version;
44
+ - canonical workspace;
45
+ - `session` launcher.
46
+
47
+ The MCP then authenticates the listener with the private ownership credential
48
+ and registers its original Codex parent PID as a session lease. Registration
49
+ success and transferred lease sets carry response HMACs bound to their fresh
50
+ request nonce and complete result, so a different process appearing between
51
+ the challenge and control request cannot be adopted. Concurrent starts
52
+ serialize locally and converge across processes by authenticating the single
53
+ listener that wins the port race.
54
+
55
+ A detached child reports readiness over a private inherited IPC channel only
56
+ after the listener is bound and the new owner record is durably published.
57
+ Startup errors use the same channel. A bounded timeout sends a cooperative
58
+ cancellation message, so slow or failed initialization cannot be mistaken for
59
+ success or silently strand a late or partially constructed listener. Owner
60
+ publication checks cancellation before atomic replacement; while publication
61
+ is in flight, every close path retains the port until publication settles, so
62
+ an older credential writer cannot race and overwrite a succeeding session's
63
+ owner record.
64
+
65
+ ## MCP reload and plugin upgrade
66
+
67
+ Closing one MCP transport does not close the session dashboard. EOF, SIGINT,
68
+ SIGTERM, protocol close, failed transport startup, and detected MCP-parent loss
69
+ still close that MCP process promptly, but the independently hosted dashboard
70
+ remains while a registered Codex session PID is alive.
71
+
72
+ After a plugin upgrade, installing files alone cannot execute new code. When
73
+ the newly installed MCP activates, it compares the live identity with its own
74
+ version. An exact current listener is reused. A verified older TaskChef
75
+ `mcp`- or `session`-launched listener for the same canonical workspace receives
76
+ an authenticated graceful handoff request. A session listener prepares an
77
+ idempotent handoff by fencing new registrations, adding the activating Codex
78
+ PID, and snapshotting its bounded live leases while it remains running. Only
79
+ after the MCP receives and verifies that signed result does it send a separate
80
+ authenticated commit that schedules graceful shutdown. A lost prepare response
81
+ is safely retried; an abandoned preparation expires and reopens registration.
82
+ A commit begins a short bounded finalization grace during which concurrent
83
+ authenticated activators can join. The commit response then returns the final
84
+ immutable lease snapshot with a credential-bound proof. The listener remains
85
+ available for a bounded commit-response retry window before graceful shutdown,
86
+ so a surviving activator can replace an elected peer that exits before launch
87
+ without discarding the older live sessions. The replacement starts with the
88
+ verified final leases. A full lease set refuses a distinct activating PID
89
+ without stopping the old listener. Finalization also reserves one of the 64
90
+ bounded lease slots for a distinct recovery activator; a 64-lease snapshot
91
+ cannot commit retirement and leaves the old listener running. The new MCP then
92
+ starts the current `session` version. A newer listener is never downgraded,
93
+ including during the brief old-to-new listener gap. If different newer versions
94
+ race, a higher contender authenticates and replaces a lower winner until the
95
+ highest active version remains.
96
+
97
+ Before acknowledging commit, the retiring session atomically records that
98
+ signed final snapshot in the mode-`0600` workspace file
99
+ `.taskchef-dashboard-handoff.json`. The record
100
+ contains no control secret. It exists only so an activator that loses every
101
+ commit response can authenticate and recover the exact finalized leases after
102
+ the old listener closes. The single record is retained and atomically
103
+ overwritten by the next finalized handoff; it cannot authenticate against a
104
+ new owner identity and secret. Avoiding post-publication deletion prevents one
105
+ replacement from removing a newer handoff generation. Invalid, permissively
106
+ readable, foreign-workspace, or incorrectly signed records are ignored and
107
+ never authorize takeover.
108
+
109
+ Both private metadata writers sync the completed file, atomically rename it,
110
+ and sync the canonical workspace directory before reporting publication. Final
111
+ lease joins are fenced before the immutable snapshot and durable write begin.
112
+
113
+ Versions predating authenticated ownership cannot be retired safely. Such a
114
+ legacy listener may require one final manual cleanup. This limitation is
115
+ intentional; TaskChef does not weaken listener safety to automate migration.
116
+
117
+ ## Codex session end
118
+
119
+ Each MCP registers the exact PID of the Codex process that launched it. The
120
+ dashboard checks only those registered PIDs with a non-signalling existence
121
+ probe. When none remains alive for the configured grace period, the dashboard
122
+ gracefully closes its HTTP listener and exits. Registering another live Codex
123
+ session during the grace period cancels expiry.
124
+
125
+ This is a best-effort local lifecycle guard, not a claim that Codex documents
126
+ or guarantees restart cleanup. PID existence cannot prove application identity
127
+ after an unlikely PID reuse, and abrupt operating-system termination can always
128
+ interrupt graceful cleanup. A later MCP activation still performs authenticated
129
+ version handoff, which is the recovery boundary for a recognized stale
130
+ TaskChef listener.
131
+
132
+ ## Security boundary
133
+
134
+ TaskChef writes ownership to `.taskchef-dashboard-owner.json` and finalized
135
+ handoff metadata to `.taskchef-dashboard-handoff.json` as private regular
136
+ mode-0600 files in the canonical workspace. The credential never appears in health responses,
137
+ diagnostics, URLs, or logs. A fresh nonce-bound HMAC challenge proves that the
138
+ listener and owner record share the credential. Shutdown and session
139
+ registration use separate action-bound proofs; successful registration and
140
+ handoff responses are also nonce- and result-bound. Nonces are single-use within
141
+ a bounded five-minute replay window. The replay cache has a fixed capacity and
142
+ refuses overflow while entries remain valid.
143
+
144
+ TaskChef sends control requests only after all public identity and private
145
+ ownership fields match. It never discovers or kills a port owner, sends OS
146
+ signals to a listener, uses `kill -9`, searches broadly for processes, or
147
+ requires elevated permission. These listeners remain untouched:
148
+
149
+ - standalone dashboards;
150
+ - unknown or spoofed services;
151
+ - different canonical workspaces;
152
+ - newer TaskChef versions;
153
+ - malformed or mismatched ownership records;
154
+ - listeners that fail the authenticated challenge;
155
+ - uncooperative legacy listeners without the handoff protocol.
156
+
157
+ ## Lifecycle matrix
158
+
159
+ | Event | MCP transport | Canonical dashboard |
160
+ | --- | --- | --- |
161
+ | MCP activation, no listener | Starts | Starts current session version |
162
+ | MCP activation, exact listener | Starts | Authenticated reuse and lease registration |
163
+ | One MCP EOF, signal, or reload | Closes | Remains while a Codex session PID is alive |
164
+ | Plugin upgrade activates newer MCP | Starts current version | Verified older version retires; current version starts |
165
+ | All registered Codex session PIDs disappear | May already be closed | Graceful close after the grace period |
166
+ | `dashboard.autostart: false` | Starts normally | No activation-time ensure; explicit ensure still works |
167
+ | Foreground `taskchef dashboard` | Unrelated | Standalone process follows its foreground CLI lifetime |
168
+ | Unknown or unverified port occupant | Starts normally | Occupant is untouched; ensure reports a bounded conflict |
package/docs/spec.md CHANGED
@@ -57,9 +57,15 @@ is dated research, not contract.
57
57
 
58
58
  ## Workspace contract
59
59
 
60
- TaskChef MUST manage only `AGENTS.md`, `taskchef.json`, `tasks.jsonl`, and the
61
- optional `.taskchef-usage.json` cache
62
- inside the dispatcher workspace. It MUST preserve unrelated paths.
60
+ TaskChef MUST manage only `AGENTS.md`, `taskchef.json`, `tasks.jsonl`, the
61
+ optional `.taskchef-usage.json` cache, and the optional dashboard lifecycle
62
+ records `.taskchef-dashboard-owner.json` and
63
+ `.taskchef-dashboard-handoff.json` inside the dispatcher workspace. It MUST
64
+ preserve unrelated paths. The owner record MUST be a retained mode-`0600`
65
+ current-listener identity and control credential that is atomically replaced by
66
+ a new owner. The handoff record MUST be a retained mode-`0600`, secret-free,
67
+ credential-signed final lease snapshot that is atomically overwritten by the
68
+ next finalized handoff.
63
69
 
64
70
  `taskchef.json` MUST have schema version 2, the following required fields, and
65
71
  an optional exact `dashboard` object:
@@ -191,8 +197,9 @@ port conflicts, and dashboard errors MUST NOT prevent tool registration or MCP
191
197
  availability. They MUST emit only a bounded non-sensitive diagnostic through
192
198
  the MCP process logging channel. MCP initialization MUST NOT open a browser.
193
199
  If transport connection fails after dashboard startup, the MCP server MUST
194
- best-effort close both its owned dashboard and partially attached transport,
195
- then propagate the original connection failure even when cleanup also fails.
200
+ best-effort close its manager and partially attached transport, then propagate
201
+ the original connection failure even when cleanup also fails. Closing that
202
+ individual MCP MUST NOT directly close a valid Codex-session dashboard.
196
203
 
197
204
  At the start of every dispatcher turn, the dispatcher SHOULD call
198
205
  `ensure_dashboard` best-effort. Failure MUST NOT block direct TaskChef answers,
@@ -282,12 +289,11 @@ object. Validation, marker, identity, uniqueness, freshness, or filesystem
282
289
  failures are surfaced as tool errors and MUST NOT partially mutate the log.
283
290
 
284
291
  ### `ensure_dashboard`
285
-
286
- **Caller:** dispatcher. **Mutation:** starts at most one in-process loopback
287
- HTTP server. The first owned start writes a private dashboard ownership record
288
- in the canonical workspace. The record remains after shutdown and the next
289
- owner atomically replaces it before reporting startup success.
290
- Exact-compatible reuse does not write it.
292
+ **Caller:** dispatcher. **Mutation:** starts or reuses the authenticated
293
+ Codex-session-scoped loopback dashboard. The first start writes a private
294
+ dashboard ownership record in the canonical workspace. The record remains
295
+ after shutdown and the next owner atomically replaces it before reporting
296
+ startup success.
291
297
 
292
298
  **Input:** empty object.
293
299
 
@@ -296,7 +302,7 @@ Exact-compatible reuse does not write it.
296
302
  ```text
297
303
  { dashboard: {
298
304
  action: "started" | "reused",
299
- launcher: "mcp",
305
+ launcher: "session",
300
306
  url: "http://127.0.0.1:3210/",
301
307
  workspace: string,
302
308
  taskchefVersion: string,
@@ -304,51 +310,98 @@ Exact-compatible reuse does not write it.
304
310
  } }
305
311
  ```
306
312
 
307
- MCP initialization MUST complete its best-effort dashboard start before exposing
308
- the MCP transport. Calls MUST serialize within one MCP process. The first call
309
- starts an owned dashboard or reuses an exact compatible MCP-launched listener;
310
- later and concurrent calls are idempotent and report reuse after the single start. The stable default MUST
311
- bind only to `127.0.0.1:3210` and MUST NOT accept a model-supplied workspace,
312
- host, or port.
313
-
314
- Before reuse, TaskChef MUST query a bounded loopback identity endpoint and
315
- require the exact fixed service/schema, TaskChef version, dashboard-server
316
- version, canonical workspace, and `mcp` launcher identity. Exact-compatible
317
- reuse MUST remain non-destructive and MUST NOT require ownership metadata. A
318
- manager that reuses another same-version MCP listener MUST monitor that listener
319
- for the remainder of its own lifetime and perform ordinary singleton startup if
320
- the reused owner exits, so overlapping plugin reloads converge on the surviving
321
- MCP process without signaling or terminating either process. A temporary
322
- different or unknown occupant remains untouched and does not disable that
323
- non-destructive availability monitor.
324
-
325
- An older TaskChef version MAY be retired only when all of these facts hold: its
326
- health identity is exact and reports the same canonical workspace, `mcp`
327
- launcher, and dashboard-server version; its semantic version is older than the
328
- requesting TaskChef version; a private regular mode-0600 owner record in that
329
- same workspace exactly matches the listener; and a fresh nonce-bound HMAC
330
- challenge proves control of that record's secret. Only after that proof MAY the
331
- new process send a separately nonce-bound authenticated loopback shutdown
332
- request. Shutdown nonces MUST be single-use. The secret MUST NOT appear in
333
- health responses, requests, diagnostics, or logs. Shutdown MUST retain the
334
- durable owner record so retirement cannot expose a credentialless live-listener
335
- window or delete a replacement's record. An owner accepting handoff MUST retire its in-memory dashboard manager
336
- so later tool calls cannot restart the older listener. Concurrent handoffs MUST
337
- converge on one listener and exact-compatible reuse.
338
-
339
- A standalone, unknown, malformed, different-workspace, newer, incompatible,
340
- unproven, spoofed, or legacy listener without valid ownership metadata MUST
341
- produce a concise actionable conflict and MUST NOT receive a shutdown request,
342
- signal, or process-level termination attempt. TaskChef MUST NOT discover or
343
- kill port owners. A startup or owner-record-write failure MUST leave no owned
344
- listener. The MCP server MUST close its owned dashboard on explicit MCP close,
345
- transport close, stdin EOF, SIGINT, SIGTERM, or detected replacement of its
346
- original parent process. Parent-loss detection is a local best-effort guard,
347
- not a Codex restart guarantee. Signal and parent-loss shutdown MUST bound the
348
- wait for an in-flight transport startup before closing the MCP server, so a
349
- never-settling startup cannot retain the dashboard indefinitely. This keeps dashboard child operations in the MCP
350
- host environment and prevents an agent-shell or foreground CLI dashboard from
351
- being mistaken for the canonical MCP-owned runtime.
313
+ MCP initialization MUST complete its best-effort ensure before exposing the
314
+ MCP transport. Calls MUST serialize within one MCP process. The first call
315
+ starts a dashboard session process or reuses the exact current listener; later
316
+ and concurrent calls are idempotent. The stable default MUST bind only to
317
+ `127.0.0.1:3210` and MUST NOT accept a model-supplied workspace, host, port,
318
+ session PID, or credential.
319
+
320
+ Exact reuse MUST require the fixed service/schema, TaskChef version,
321
+ dashboard-server version, canonical workspace, and `session` launcher identity.
322
+ It MUST additionally prove the private owner credential and use a fresh,
323
+ single-use, action-bound HMAC to register the MCP's original Codex parent PID.
324
+ The registration acknowledgement and every transferred lease set MUST carry a
325
+ separate response HMAC bound to the request nonce and complete accepted result.
326
+ The independent dashboard MUST survive closure of an individual MCP transport.
327
+ The session manager MUST require an explicit nonzero port because a detached
328
+ child cannot safely return an ephemeral bound port without an additional IPC
329
+ ownership channel. Direct foreground server callers MAY continue to bind port
330
+ zero when they retain the returned listener.
331
+
332
+ The dashboard MUST track only explicitly registered PIDs using non-signalling
333
+ existence probes. Once every registered PID is absent for the grace period, it
334
+ MUST gracefully close its HTTP listener and exit. A new authenticated live
335
+ registration during the grace period MUST cancel expiry. This is a local
336
+ best-effort session guard, not a Codex restart guarantee.
337
+
338
+ An older TaskChef version MAY be retired only when its exact health identity
339
+ reports the same canonical workspace and an `mcp` or `session` launcher; a
340
+ private regular mode-0600 owner record exactly matches that listener; and a
341
+ fresh nonce-bound HMAC challenge proves control of the record's secret. Only
342
+ then MAY the new MCP send an action- and nonce-bound authenticated loopback
343
+ handoff. Before retiring a prior `session` listener, an idempotent prepare
344
+ action MUST fence new registrations, register the activating Codex PID,
345
+ validate and return the bounded live PID lease set while the old listener
346
+ remains running. Only a separate authenticated commit after the caller verifies
347
+ that result MAY schedule shutdown. A lost prepare response MUST be retryable,
348
+ and an abandoned preparation MUST expire without shutting down the listener. A
349
+ full, failed, or malformed transfer MUST leave the
350
+ listener running and MUST NOT acknowledge a concurrent registration that will
351
+ be absent from the returned set. A prior `mcp` listener MAY instead receive a
352
+ separately authenticated graceful shutdown request.
353
+ A commit MUST begin a short bounded finalization grace that allows concurrent
354
+ authenticated activators to join. Its response MUST contain a credential-bound
355
+ proof of the final immutable complete lease snapshot. The listener MUST remain
356
+ available for a bounded commit-response retry window before shutdown, so a
357
+ surviving activator can recover if the elected one exits before launch. An
358
+ activator observing the authenticated old-owner listener gap MUST wait for the
359
+ elected replacement and MUST NOT bind an older version into that gap.
360
+ The finalized transferable snapshot MUST reserve one bounded lease slot for a
361
+ distinct recovery activator. If that complete union cannot fit, commit MUST fail
362
+ without stopping the old listener. When different compatible newer versions
363
+ race, a higher version that loses the bind MUST authenticate and replace the
364
+ lower winner rather than accepting it as final.
365
+ Before acknowledging commit, the retiring session MUST atomically persist the
366
+ credential-bound final snapshot in a private mode-`0600` same-workspace record
367
+ that contains no secret. A replacement MAY use that record only after verifying
368
+ its exact workspace, listener identity, handoff identifier when known, bounded
369
+ PID set, and HMAC with the private owner credential. It MUST ignore the record
370
+ once replacement ownership is published, but MUST NOT unlink it after that
371
+ transition because a newer handoff may already have atomically replaced it. The
372
+ single retained record MUST be overwritten only by a newer finalized handoff
373
+ and MUST remain unusable against a different owner identity or credential.
374
+ Owner and handoff publication MUST sync the completed private file, atomically
375
+ rename it, and sync the containing canonical workspace directory before
376
+ reporting success. Finalization MUST fence further handoff joins before taking
377
+ and persisting the immutable snapshot.
378
+ The new MCP MAY then start its current `session` version and MUST NOT downgrade
379
+ a newer listener. Concurrent startup and handoff MUST converge on one
380
+ authenticated listener. Single-use control nonces MUST be retained in a fixed,
381
+ time-bounded replay cache that refuses overflow while entries remain valid.
382
+
383
+ The credential MUST NOT appear in health responses, requests, diagnostics, or
384
+ logs. A standalone, unknown, malformed, different-workspace, newer, unproven,
385
+ spoofed, or legacy listener without valid ownership metadata MUST produce a
386
+ concise actionable conflict and MUST NOT receive a shutdown request, signal,
387
+ or process-level termination attempt. TaskChef MUST NOT discover or kill port
388
+ owners. An invalid workspace, initial task log, or ownership write MUST leave
389
+ no newly owned listener.
390
+
391
+ Detached session startup MUST use a private child readiness acknowledgement
392
+ sent only after listener bind and atomic ownership publication. Startup errors
393
+ MUST propagate through that channel. A bounded readiness timeout MUST
394
+ cooperatively cancel the exact child so late initialization cannot strand an
395
+ unreported listener. Ownership publication MUST check cancellation before its
396
+ atomic replacement, and the listener MUST retain the port until that write
397
+ commits or aborts on every shutdown path so an older writer cannot overwrite a
398
+ successor's credential.
399
+
400
+ MCP EOF, explicit close, protocol close, SIGINT, SIGTERM, transport-start
401
+ failure, and MCP-parent loss MUST still bound MCP shutdown. They MUST close the
402
+ MCP manager and transport without directly closing the independently hosted
403
+ session dashboard. Foreground `taskchef dashboard` remains `standalone`, is
404
+ never adopted by MCP, and follows its foreground process lifetime.
352
405
 
353
406
  The packaged `$taskchef-dashboard` skill MUST call this tool, report `started`
354
407
  or `reused`, and return the canonical clickable URL. It MAY use an available
@@ -358,6 +411,9 @@ back to the link without failing. It MUST NOT inspect task outcomes or dispatch.
358
411
  **Annotations:** `readOnlyHint: false`, `destructiveHint: false`,
359
412
  `openWorldHint: false`.
360
413
 
414
+ The complete operational rationale and limits are documented in
415
+ [Dashboard lifecycle](dashboard-lifecycle.md).
416
+
361
417
  ### `prepare_dispatch`
362
418
 
363
419
  **Caller:** dispatcher. **Mutation:** none.
@@ -643,8 +699,8 @@ identity or infer semantic results.
643
699
 
644
700
  TaskChef MUST NOT install or require daemons, launchd agents, login items,
645
701
  system services, cron jobs, hooks, privileged components, or elevated/system
646
- permissions for dashboard availability. Availability is best-effort while the
647
- owning Codex/plugin MCP process is alive and is not guaranteed while Codex is
702
+ permissions for dashboard availability. Availability is best-effort while a
703
+ registered Codex session process is alive and is not guaranteed while Codex is
648
704
  closed.
649
705
 
650
706
  Releases predating authenticated dashboard handoff are legacy listeners. A
@@ -656,6 +712,6 @@ protocol, compatible prior-version handoff is automatic.
656
712
  Installing or replacing plugin files MUST NOT be described as activating the
657
713
  new MCP code. Release verification MUST install the plugin, activate or reload
658
714
  the new MCP process, ensure the dashboard, and verify the expected TaskChef
659
- version, dashboard protocol `serverVersion`, `mcp` launcher, canonical workspace,
660
- and canonical URL. Exact-compatible MCP-listener reuse remains valid; installation MUST NOT be
715
+ version, dashboard protocol `serverVersion`, `session` launcher, canonical workspace,
716
+ and canonical URL. Exact-compatible session-listener reuse remains valid; installation MUST NOT be
661
717
  claimed to reload Codex automatically.
package/docs/workflows.md CHANGED
@@ -4,7 +4,8 @@ This developer and advanced-agent guide explains how the current implementation
4
4
  moves data through TaskChef. The [specification](spec.md) is normative; the
5
5
  [README](../README.md) owns user operation. The
6
6
  [FirstMate comparison](firstmate-taskchef-comparison.md) is non-normative
7
- research.
7
+ research. The [dashboard lifecycle](dashboard-lifecycle.md) owns the focused
8
+ start, upgrade, shutdown, and security rationale.
8
9
 
9
10
  ## Implementation map
10
11
 
@@ -15,12 +16,14 @@ research.
15
16
  | `skills/taskchef-bootstrap/SKILL.md` | Initialize the workspace and maintain the Codex project index. |
16
17
  | `skills/taskchef-dashboard/SKILL.md` | Ensure or recover the canonical dashboard and return its URL. |
17
18
  | `skills/taskchef-copilot/SKILL.md` | Explain normalized cached briefs and coordinate safe next actions. |
18
- | `src/mcp.js` | Dashboard ensure, four primary lifecycle tools, one deprecated alias, shutdown ownership, and MCP annotations. |
19
+ | `src/mcp.js` | Dashboard ensure, four primary lifecycle tools, one deprecated alias, MCP cleanup, and annotations. |
19
20
  | `src/delegation.js` | UUID marker, concise executor-skill invocation shape, and creation-failure handling. |
20
21
  | `src/workspace.js` | Current schemas, validation, locking, atomic JSONL writes, linking, and result freshness. |
21
22
  | `src/cli.js` | Administration, normalized cached briefs, inspection, diagnostics, and dashboard startup. |
22
23
  | `src/dashboard.js` | Versioned health identity, validated compact snapshots, SSE fan-out, on-demand details, and bounded open actions. |
23
- | `src/dashboard-manager.js` | Concurrent singleton ensure, exact listener reuse, conflicts, and owned shutdown. |
24
+ | `src/dashboard-manager.js` | Concurrent session ensure, authenticated reuse and upgrade handoff, and safe conflicts. |
25
+ | `src/dashboard-session-process.js` | Independent loopback server, private ownership publication, signals, and Codex-session lease. |
26
+ | `src/dashboard-session.js` | Exact registered-PID liveness checks and grace-period expiry. |
24
27
  | `src/usage.js` | Optional bounded ccusage execution, exact primary-thread mapping, normalized aggregation, and the private usage cache. |
25
28
  | `src/usage-tracker.js` | Deferred sampling, cumulative boundaries, historical availability, and per-turn deltas. |
26
29
 
@@ -40,19 +43,25 @@ sequenceDiagram
40
43
  participant D as Dispatcher
41
44
  participant M as TaskChef MCP
42
45
  participant H as Loopback health
43
- participant S as Dashboard server
46
+ participant S as Dashboard session process
44
47
  M->>M: Read dashboard.autostart (absent means true)
45
48
  M->>M: Best-effort ensure before MCP transport connects
46
49
  D->>M: ensure_dashboard()
47
50
  M->>M: Serialize concurrent ensure calls
48
51
  M->>H: GET 127.0.0.1:3210/api/health
49
- alt Exact service, versions, canonical workspace, and MCP launcher
52
+ alt Exact service, versions, canonical workspace, and session launcher
50
53
  H-->>M: Bounded compatible identity
54
+ M->>S: Authenticate owner and register Codex parent PID
51
55
  M-->>D: reused, URL, workspace, versions
52
56
  else No listener
53
57
  H--xM: Connection refused
54
- M->>S: Start in this MCP process on 127.0.0.1:3210
55
- S-->>M: Owned server
58
+ M->>S: Launch session process on 127.0.0.1:3210
59
+ S-->>M: Private owner metadata and bounded identity
60
+ M-->>D: started, URL, workspace, versions
61
+ else Verified older TaskChef listener for this workspace
62
+ M->>S: Authenticated prepare, lease join, and commit
63
+ S-->>M: Signed final leases and bounded retry before shutdown
64
+ M->>S: Launch installed session version
56
65
  M-->>D: started, URL, workspace, versions
57
66
  else Standalone, unknown, stale, or different workspace
58
67
  H-->>M: Missing or incompatible identity
@@ -63,14 +72,15 @@ sequenceDiagram
63
72
  Note over D: Created-thread directive, when any, precedes final dashboard link
64
73
  ```
65
74
 
66
- When the MCP transport or plugin process closes, it closes only the server it
67
- started. A foreground `taskchef dashboard` listener identifies itself as
68
- standalone and is never reused as the canonical MCP dashboard, because its
69
- archive child process may inherit a different host environment. No TaskChef
70
- path terminates an incompatible listener or installs OS persistence.
75
+ When one MCP transport or plugin process closes, the dashboard remains while a
76
+ registered Codex session PID is alive. After every registered PID disappears
77
+ for the grace period, the dashboard closes and exits. A foreground
78
+ `taskchef dashboard` listener identifies itself as standalone and is never
79
+ reused as the canonical session dashboard. No TaskChef path terminates an
80
+ incompatible listener or installs OS persistence.
71
81
 
72
- Autostart and explicit ensures share the same manager promise, so concurrent
73
- initialization and recovery calls produce at most one owned listener. An
82
+ Autostart and explicit ensures share the same manager promise, while
83
+ cross-process port races converge through authenticated reuse. An
74
84
  explicit `dashboard.autostart: false` skips only activation-time ensure. Any
75
85
  failure is reduced to a fixed stderr diagnostic; tool registration and MCP
76
86
  availability continue. Activation never opens a browser.
@@ -82,13 +92,15 @@ The practical release handoff ends in this order:
82
92
  1. Install the released plugin.
83
93
  2. Activate or reload its new TaskChef MCP process.
84
94
  3. Run `$taskchef-dashboard` or call `ensure_dashboard`.
85
- 4. Verify the expected TaskChef version, protocol `serverVersion`, `mcp`
95
+ 4. Verify the expected TaskChef version, protocol `serverVersion`, `session`
86
96
  launcher, canonical workspace, and canonical URL returned by the dashboard identity.
87
97
 
88
98
  Replacing plugin files alone cannot execute autostart because old code remains
89
- in the already-running MCP process. Installation does not necessarily reload
90
- Codex. An exact-compatible MCP dashboard may be reused; a standalone or unknown
91
- listener is never terminated or replaced.
99
+ in an already-running MCP process. Installation does not necessarily reload
100
+ Codex. Activation of the installed MCP authenticates and retires a verified
101
+ older TaskChef listener before starting the installed session version. An
102
+ exact-compatible session dashboard may be reused; a newer, standalone, or
103
+ unknown listener is never terminated or replaced.
92
104
 
93
105
  ## Normal delegation and self-linking
94
106