taskchef 5.7.2 → 5.9.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.
- package/.codex-plugin/plugin.json +2 -2
- package/BACKLOG.md +4 -4
- package/README.md +125 -45
- package/SPEC.md +106 -89
- package/docs/delegation-design.md +158 -254
- package/hooks/hooks.json +18 -0
- package/hooks/taskchef-initial-prompt.js +17 -0
- package/index.js +13 -1
- package/package.json +3 -2
- package/skills/taskchef-bootstrap/SKILL.md +6 -3
- package/skills/taskchef-delegate/SKILL.md +49 -91
- package/skills/taskchef-report/SKILL.md +60 -27
- package/src/cli.js +52 -2
- package/src/dashboard/app.js +255 -0
- package/src/dashboard/index.html +86 -0
- package/src/dashboard/state.js +40 -0
- package/src/dashboard/styles.css +147 -0
- package/src/dashboard.js +597 -0
- package/src/delegation.js +109 -359
- package/src/hook.js +60 -0
- package/src/mcp.js +35 -2
- package/src/workspace-path.js +5 -1
- package/src/workspace.js +239 -23
package/SPEC.md
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
TaskChef is an interactive Codex dispatcher. It routes independent assignments
|
|
6
6
|
to real Codex tasks in configured local projects, records each submitted
|
|
7
|
-
delegation in a task history, and returns immediately. New tasks append;
|
|
8
|
-
|
|
7
|
+
delegation in a task history, and returns immediately. New tasks append; locked
|
|
8
|
+
atomic updates may later resolve identity and replace the latest semantic result.
|
|
9
9
|
|
|
10
|
-
Codex tasks remain authoritative for
|
|
11
|
-
not
|
|
10
|
+
Codex tasks remain authoritative for current activity. TaskChef stores only the
|
|
11
|
+
latest useful semantic result, not a second lifecycle or event database.
|
|
12
12
|
|
|
13
13
|
## Core behavior
|
|
14
14
|
|
|
@@ -19,14 +19,15 @@ not maintain a second lifecycle database.
|
|
|
19
19
|
2. TaskChef separates only outcomes that can proceed independently.
|
|
20
20
|
3. It selects each target using configured project metadata and validates the
|
|
21
21
|
selected local path.
|
|
22
|
-
4. It
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
4. It embeds a generated TaskChef UUID marker, executor-ownership sentence, and
|
|
23
|
+
result-callback instruction, then records the task with `threadId: null`.
|
|
24
|
+
5. It creates an independently openable Codex task. A durable returned ID is
|
|
25
|
+
resolved immediately; otherwise the initial-prompt hook links the root
|
|
26
|
+
session ID without polling.
|
|
27
27
|
6. It returns without waiting for executor work to complete.
|
|
28
|
-
7.
|
|
29
|
-
|
|
28
|
+
7. Executors report `completed`, `needs_input`, or `failed` through MCP. Reports
|
|
29
|
+
filter old terminal entries, use one live metadata snapshot, and read only
|
|
30
|
+
tasks whose cached result may be stale.
|
|
30
31
|
|
|
31
32
|
A task created by TaskChef owns its delegated initial assignment. It executes
|
|
32
33
|
that assignment in the current task and does not re-dispatch it merely because
|
|
@@ -60,7 +61,10 @@ Every command resolves one workspace in this precedence order:
|
|
|
60
61
|
2. `TASKCHEF_WORKSPACE`
|
|
61
62
|
3. `~/.agents/taskchef`
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
`TASKCHEF_WORKSPACE` must be absolute or start with `~/`; this prevents the
|
|
65
|
+
hook, MCP server, and CLI from resolving one relative override against
|
|
66
|
+
different process directories. The current directory is never an implicit
|
|
67
|
+
workspace. `workspace path` exposes
|
|
64
68
|
the resolved absolute path and its source. Bootstrap compares this canonical
|
|
65
69
|
path with native Codex projects, and when absent invokes the validated
|
|
66
70
|
`codex app <path>` command before verifying the native list again. It never
|
|
@@ -136,14 +140,14 @@ legacy `null` to `[]`; `workspace init` persists the migration atomically, and
|
|
|
136
140
|
any later configuration write emits version 2.
|
|
137
141
|
|
|
138
142
|
The configuration does not store dispatcher identity, execution modes,
|
|
139
|
-
schedules, task
|
|
143
|
+
schedules, task state, host information, or the workspace path.
|
|
140
144
|
|
|
141
145
|
## Task entry
|
|
142
146
|
|
|
143
147
|
`tasks.jsonl` contains one compact JSON object per line, in append order:
|
|
144
148
|
|
|
145
149
|
```json
|
|
146
|
-
{"schemaVersion":
|
|
150
|
+
{"schemaVersion":3,"id":"c0f010ff-84f2-4838-a69d-0ff1f5d721d7","project":{"name":"payments-api","path":"/workspace/payments-api","isGitRepository":true,"githubRepos":["https://github.com/example/payments-api","https://github.com/example/payments-sdk"],"description":"Owns payment authorization, capture, refunds, and provider integrations."},"title":"Add payment retry logs","instruction":"<!-- taskchef_id=c0f010ff-84f2-4838-a69d-0ff1f5d721d7 -->\n\nThis task owns the delegated assignment. Execute it in this task; do not re-dispatch it merely because it concerns TaskChef or a configured project. Explicit requests to delegate separate work remain valid.\n\nBefore ending, call the TaskChef report_result MCP tool with completed, needs_input, or failed and a concise summary. Use needs_input only for a semantic decision or information the user must provide; a native approval prompt is live Codex state, not a TaskChef result. Do not include secrets, transcripts, or raw command output.\n\nAdd structured logs for failed payment retries and test them.","threadId":"019f9d46-f42c-7482-9707-3c107bf241ee","createdAt":"2026-08-08T10:00:00.000Z","status":"completed","summary":"Added structured retry logs and regression coverage.","turnId":"019f9d47-result-turn","updatedAt":"2026-08-08T10:08:00.000Z","updatedBy":"mcp"}
|
|
147
151
|
```
|
|
148
152
|
|
|
149
153
|
- `schemaVersion` identifies the task entry format.
|
|
@@ -154,28 +158,38 @@ schedules, task status, results, host information, or the workspace path.
|
|
|
154
158
|
`<!-- taskchef_id=<full UUID> -->` correlation marker, executor-ownership
|
|
155
159
|
paragraph, and assignment body.
|
|
156
160
|
- `threadId` identifies the created Codex task, or is `null` when creation was
|
|
157
|
-
accepted but
|
|
161
|
+
accepted but its initial identity has not yet been linked.
|
|
158
162
|
- `createdAt` is the dispatch time as an ISO 8601 timestamp.
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
- `status` is `working`, `needs_input`, `completed`, or `failed`; legacy
|
|
164
|
+
entries normalize it to `null`.
|
|
165
|
+
- `summary` is a nullable, bounded latest-result summary.
|
|
166
|
+
- `turnId` identifies the initial hook turn or latest reported result turn. An
|
|
167
|
+
MCP result for a linked executor requires it; null is allowed only for a
|
|
168
|
+
failed creation before any durable thread exists.
|
|
169
|
+
- `updatedAt` is the server-side update time.
|
|
170
|
+
- `updatedBy` is `dispatcher`, `hook`, or `mcp`.
|
|
171
|
+
|
|
172
|
+
Schema-version-3 entries have exactly these fields. IDs and non-null thread IDs must be
|
|
161
173
|
unique; any number of unresolved entries may have `threadId: null`. The file is
|
|
162
174
|
empty or newline terminated, with no blank lines. TaskChef rejects a malformed
|
|
163
175
|
log instead of skipping bad entries. Writers replace the complete validated
|
|
164
176
|
file atomically under a workspace lock, so an interrupted write leaves either
|
|
165
177
|
the old history or the complete new history.
|
|
166
178
|
|
|
167
|
-
Task creation appends entries.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
Task creation appends entries. Identity resolution and result callbacks acquire
|
|
180
|
+
the same cross-process lock, reread and validate the complete log, patch one
|
|
181
|
+
matching entry, and atomically replace the file. Resolution is idempotent and
|
|
182
|
+
one-way from null to one unique durable thread ID. Result callbacks must match
|
|
183
|
+
the recorded task/thread and replace only the latest result snapshot; they do
|
|
184
|
+
not append events.
|
|
171
185
|
|
|
172
186
|
The project snapshot preserves the route even if the project is renamed,
|
|
173
|
-
moved, or removed later. Entries never contain
|
|
174
|
-
|
|
187
|
+
moved, or removed later. Entries never contain transcripts, hidden reasoning,
|
|
188
|
+
`hostId`, or an event history.
|
|
175
189
|
|
|
176
|
-
New task entries use schema version
|
|
177
|
-
|
|
178
|
-
|
|
190
|
+
New task entries use schema version 3. Version 1 and 2 entries remain readable
|
|
191
|
+
and normalize to version 3 in API and CLI output with nullable result fields.
|
|
192
|
+
Historical task entries with the
|
|
179
193
|
old heading-style marker also remain readable. New nullable records, candidate
|
|
180
194
|
matching, and resolution require the exact HTML-comment marker; TaskChef never
|
|
181
195
|
uses an old marker to correlate a thread. Direct records that already have a
|
|
@@ -197,49 +211,29 @@ For each assignment, `$taskchef-delegate`:
|
|
|
197
211
|
the already-loaded native projects
|
|
198
212
|
3. prefixes the instruction with the prepared exact
|
|
199
213
|
`<!-- taskchef_id=<UUID> -->` marker as the first line, followed by a blank
|
|
200
|
-
line, the executor-ownership sentence,
|
|
214
|
+
line, the executor-ownership sentence, result-callback sentence, and
|
|
201
215
|
assignment body
|
|
202
|
-
4.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
serial reads
|
|
220
|
-
8. atomically fills the nullable thread ID with `resolve_task` after an exact
|
|
221
|
-
match
|
|
222
|
-
9. returns after recording or after reporting that bounded resolution was
|
|
223
|
-
unresolved, without waiting for executor work completion.
|
|
224
|
-
|
|
225
|
-
The exact random marker remains the sole correlation proof. Creation-time
|
|
226
|
-
filtering allows five seconds of clock skew. Candidate reads use exactly one
|
|
227
|
-
programmatic batch per snapshot and inspect only
|
|
228
|
-
structured `codexDelegation.input`, never untrusted title, summary, preview, or
|
|
229
|
-
plain-text marker echoes. Zero exact matches remain unresolved; multiple exact
|
|
230
|
-
matches are ambiguous. Snapshot, candidate-read, or task-resolution errors
|
|
231
|
-
leave the already-recorded nullable entry intact. The workflow is bounded by
|
|
232
|
-
two snapshots rather than an absolute wall-clock cutoff:
|
|
233
|
-
mandatory recording or tool latency can shift both attempts later, but cannot
|
|
234
|
-
erase an attempt or reduce the minimum 20-second interval between their start
|
|
235
|
-
times.
|
|
236
|
-
A `clientThreadId`, `pendingWorktreeId`, or ID in the documented provisional
|
|
237
|
-
`local:` namespace remains diagnostic context and is rejected from every path
|
|
238
|
-
that could persist the canonical `threadId` field.
|
|
216
|
+
4. appends a `working` task entry with `threadId: null` through `record_task`
|
|
217
|
+
before executor creation
|
|
218
|
+
5. creates a real Codex task at the exact configured path
|
|
219
|
+
6. calls `resolve_task` when creation returns a durable thread ID; otherwise it
|
|
220
|
+
returns immediately and the initial `UserPromptSubmit` hook resolves the root
|
|
221
|
+
session ID against the exact marker
|
|
222
|
+
7. records executor-creation failure as a `failed` semantic result on the
|
|
223
|
+
already-existing entry
|
|
224
|
+
8. never lists, reads, waits for, or polls threads during delegation.
|
|
225
|
+
|
|
226
|
+
Recording first closes the creation/hook race. On the exact marked prompt, the
|
|
227
|
+
hook receives the root session ID and initial turn ID and writes only identity
|
|
228
|
+
plus `working`. On later prompts whose session ID matches a recorded executor,
|
|
229
|
+
the same `UserPromptSubmit` hook reads the task history and supplies the current
|
|
230
|
+
turn ID as callback context without writing. No permission, tool, stop,
|
|
231
|
+
notification, or session hook writes task lifecycle state. A provisional
|
|
232
|
+
`local:` ID is diagnostic only and can never be persisted as `threadId`.
|
|
239
233
|
|
|
240
234
|
The plugin bundles a local stdio MCP server with focused `prepare_dispatch`,
|
|
241
|
-
`record_task`, and `
|
|
242
|
-
model and resolves only `TASKCHEF_WORKSPACE` or the canonical
|
|
235
|
+
`record_task`, `resolve_task`, and `report_result` tools. It accepts no workspace path from the
|
|
236
|
+
model and resolves only an absolute (or `~/`-prefixed) `TASKCHEF_WORKSPACE` or the canonical
|
|
243
237
|
`~/.agents/taskchef` default. The write tools reuse the public workspace APIs,
|
|
244
238
|
so structured calls cannot bypass exact-field validation, locking, atomic
|
|
245
239
|
replacement, unique IDs, or one-way nullable resolution. They are closed-world
|
|
@@ -247,7 +241,11 @@ local mutations and never create Codex tasks. Desktop thread tools remain
|
|
|
247
241
|
available only to the Codex skill; the standalone CLI remains available for
|
|
248
242
|
bootstrap, manual inspection, and recovery.
|
|
249
243
|
|
|
250
|
-
###
|
|
244
|
+
### Legacy end-to-end benchmark results
|
|
245
|
+
|
|
246
|
+
Schema-v1 benchmark fixtures below validate historical bounded-resolver
|
|
247
|
+
artifacts only. New benchmarks must measure record-before-create, initial-hook
|
|
248
|
+
identity, and result callbacks without using the removed snapshot resolver.
|
|
251
249
|
|
|
252
250
|
An explicitly requested live benchmark writes one ignored, timestamped JSON
|
|
253
251
|
artifact through `scripts/e2e-benchmark.js`. Schema version 1 contains:
|
|
@@ -298,17 +296,20 @@ up to seven seconds, while permanent permission failures such as `EPERM` or
|
|
|
298
296
|
`EACCES` fail immediately so the caller can request the required permission
|
|
299
297
|
without paying the contention retry budget.
|
|
300
298
|
|
|
301
|
-
A failed executor creation
|
|
302
|
-
|
|
303
|
-
|
|
299
|
+
A failed executor creation normally leaves its pre-created entry with `failed`.
|
|
300
|
+
The exported orchestration helper attaches `taskChefTaskId` and
|
|
301
|
+
`taskChefResultReporting` (`recorded`, `failed`, or `unavailable`) to a thrown
|
|
302
|
+
creation error so callers can recover the entry if failure reporting itself was
|
|
303
|
+
not available. A failed pre-creation record stops before executor creation, so
|
|
304
|
+
there is no untracked executor.
|
|
304
305
|
|
|
305
306
|
## Task history and live reports
|
|
306
307
|
|
|
307
308
|
The CLI reads persisted history without contacting Codex:
|
|
308
309
|
|
|
309
310
|
- `task show <id-or-8-character-prefix>` returns one entry. By default it emits
|
|
310
|
-
labeled human-readable lines for title, project
|
|
311
|
-
|
|
311
|
+
labeled human-readable lines for title, project, status, summary, creation and
|
|
312
|
+
update metadata, task/thread/turn IDs, and instruction. A null ID renders as `-`.
|
|
312
313
|
Carriage returns and newlines in labeled values render as `\\r` and `\\n`.
|
|
313
314
|
The instruction starts on the line after `Instruction:` and retains its stored
|
|
314
315
|
line breaks and indentation. `--json` returns the unchanged complete task
|
|
@@ -318,7 +319,7 @@ The CLI reads persisted history without contacting Codex:
|
|
|
318
319
|
wrong-case prefixes fail without selecting a task.
|
|
319
320
|
- `task list` returns entries newest-first by creation time, optionally filtered
|
|
320
321
|
by historical project name or exact path. `--ascending` returns oldest-first.
|
|
321
|
-
Human rows include task and thread ID
|
|
322
|
+
Human rows include status, update time, task ID, and thread ID, abbreviating UUID-shaped IDs
|
|
322
323
|
to their first eight-character section unless `--full-id` is passed. Null
|
|
323
324
|
thread IDs display as `-`. ID formatting does not alter JSON values, and the
|
|
324
325
|
selected order applies to both human rows and the JSON `tasks` array.
|
|
@@ -326,20 +327,35 @@ The CLI reads persisted history without contacting Codex:
|
|
|
326
327
|
- `task resolve <id> --thread-id <thread-id>` atomically fills one nullable
|
|
327
328
|
thread ID after Codex verifies the exact structured marker match.
|
|
328
329
|
|
|
329
|
-
When the user requests
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
330
|
+
When the user requests an overview, `$taskchef-report` includes working,
|
|
331
|
+
needs-input, unresolved, legacy, and terminal tasks updated during the last
|
|
332
|
+
seven days. It omits older terminal entries unless explicitly requested or a
|
|
333
|
+
single recent-thread metadata snapshot shows that they are active or awaiting
|
|
334
|
+
approval. That one snapshot is a broad contradiction check: active or awaiting-
|
|
335
|
+
approval metadata overrides a cached result immediately, without one detailed
|
|
336
|
+
read per task. An inactive state does not prove semantic completion; in a broad
|
|
337
|
+
overview it permits an `updatedBy: mcp` result to stand by default.
|
|
338
|
+
Dispatcher- or hook-written `working` snapshots have no semantic callback and
|
|
339
|
+
trigger a live read when selected; an inactive task without an MCP callback has
|
|
340
|
+
an unknown outcome. An MCP-written `failed` snapshot with null thread/turn IDs
|
|
341
|
+
is a fresh executor-creation failure and requires no live lookup. For a focused
|
|
342
|
+
task, title, or project report, any newer matched metadata timestamp triggers at
|
|
343
|
+
most one targeted read per selected inactive task. This distinguishes normal
|
|
344
|
+
same-turn finalization from a quick newer turn by comparing structured turn IDs
|
|
345
|
+
and native turn state. Missing callbacks, uncertain or contradictory identity
|
|
346
|
+
or metadata, and explicitly fully-live requests also trigger one targeted read.
|
|
347
|
+
Reads are batched in groups of eight. Broad overviews do not fan out reads over
|
|
348
|
+
idle terminal tasks solely because their timestamps are newer. Reporting never
|
|
349
|
+
persists inferred live state and does not poll, wait, or schedule work.
|
|
335
350
|
|
|
336
351
|
## Boundaries
|
|
337
352
|
|
|
338
353
|
TaskChef does not include:
|
|
339
354
|
|
|
340
|
-
- lifecycle
|
|
341
|
-
-
|
|
342
|
-
-
|
|
355
|
+
- lifecycle event history or hook-inferred completion
|
|
356
|
+
- lifecycle event types beyond `UserPromptSubmit`
|
|
357
|
+
- indefinite polling, daemons, heartbeats, dispatcher wakeups, or schedules
|
|
358
|
+
- arbitrary Codex task discovery
|
|
343
359
|
- remote hosts or `hostId` storage
|
|
344
360
|
- transcript or hidden-reasoning collection
|
|
345
361
|
- one-active-task-per-project restrictions
|
|
@@ -351,15 +367,16 @@ TaskChef does not include:
|
|
|
351
367
|
1. Bootstrap creates `AGENTS.md`, `taskchef.json`, and `tasks.jsonl`, then
|
|
352
368
|
remains idempotent.
|
|
353
369
|
2. Project metadata routes an unambiguous request to the correct local project.
|
|
354
|
-
3. A
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
thread ID; zero or multiple matches record `threadId: null` for later
|
|
358
|
-
recovery.
|
|
370
|
+
3. A delegation records `working` before creating a visible Codex task.
|
|
371
|
+
4. A durable creation resolves immediately; a provisional creation is linked
|
|
372
|
+
by the initial exact-marker hook without polling.
|
|
359
373
|
5. The dispatcher returns without waiting for execution.
|
|
360
374
|
6. Several independent assignments can create several entries, including
|
|
361
375
|
multiple entries for the same project.
|
|
362
376
|
7. Task history commands return deterministic entries and project counts.
|
|
363
|
-
8.
|
|
364
|
-
9.
|
|
377
|
+
8. MCP callbacks replace the latest needs-input, completed, or failed snapshot.
|
|
378
|
+
9. A report skips old terminal tasks by default, checks live metadata once,
|
|
379
|
+
overrides active or approval-waiting tasks directly, and reads only anomalous
|
|
380
|
+
candidates without writing inferred state.
|
|
381
|
+
10. Malformed JSONL, duplicate IDs, duplicate thread IDs, and symlinked managed
|
|
365
382
|
files fail safely.
|