taskchef 5.11.2 → 6.0.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 +1 -1
- package/BACKLOG.md +6 -15
- package/README.md +30 -40
- package/SPEC.md +92 -369
- package/assets/e2e-benchmark-example.json +37 -33
- package/docs/delegation-design.md +75 -176
- package/index.js +3 -11
- package/package.json +1 -2
- package/scripts/e2e-benchmark.js +101 -412
- package/skills/taskchef-bootstrap/SKILL.md +2 -3
- package/skills/taskchef-delegate/SKILL.md +60 -138
- package/skills/taskchef-report/SKILL.md +12 -8
- package/src/cli.js +2 -1
- package/src/dashboard/actions.js +17 -0
- package/src/dashboard/app.js +15 -12
- package/src/dashboard/index.html +1 -1
- package/src/dashboard/styles.css +4 -0
- package/src/dashboard.js +1 -0
- package/src/delegation.js +24 -201
- package/src/mcp.js +10 -10
- package/src/workspace.js +128 -61
- package/hooks/hooks.json +0 -18
- package/hooks/taskchef-initial-prompt.js +0 -17
- package/src/hook.js +0 -96
package/SPEC.md
CHANGED
|
@@ -2,383 +2,106 @@
|
|
|
2
2
|
|
|
3
3
|
## Purpose
|
|
4
4
|
|
|
5
|
-
TaskChef
|
|
6
|
-
|
|
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.
|
|
5
|
+
TaskChef routes work from a data-only dispatcher workspace to visible Codex
|
|
6
|
+
project tasks, stores exact child links, and caches explicit semantic results.
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
latest useful semantic result, not a second lifecycle or event database.
|
|
8
|
+
## Workspace
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
The canonical workspace contains only:
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
dispatcher workspace.
|
|
19
|
-
2. TaskChef separates only outcomes that can proceed independently.
|
|
20
|
-
3. It selects each target using configured project metadata and validates the
|
|
21
|
-
selected local path.
|
|
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 bounded recent-task checks accept exactly
|
|
26
|
-
one child whose structured initial input contains the exact marker.
|
|
27
|
-
6. It returns without waiting for executor work to complete.
|
|
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.
|
|
12
|
+
- `AGENTS.md`: managed dispatcher instructions plus user instructions.
|
|
13
|
+
- `taskchef.json`: schema-versioned configured projects.
|
|
14
|
+
- `tasks.jsonl`: append-on-create, atomic-rewrite-on-update task snapshots.
|
|
31
15
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
the subject is TaskChef or another configured project. The task may still use
|
|
35
|
-
TaskChef when the initial assignment explicitly requests delegation of separate
|
|
36
|
-
work or when the user later explicitly requests a new delegation.
|
|
16
|
+
All workspace writes use one lock and atomic replacement. Task IDs and non-null
|
|
17
|
+
thread IDs are globally unique.
|
|
37
18
|
|
|
38
|
-
|
|
19
|
+
## Task schema
|
|
39
20
|
|
|
40
|
-
|
|
21
|
+
New records use schema version 4 and contain:
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
└── tasks.jsonl
|
|
47
|
-
```
|
|
23
|
+
- immutable `id`, project snapshot, title, instruction, and `createdAt`;
|
|
24
|
+
- nullable `threadId` until executor self-linking succeeds;
|
|
25
|
+
- `status`, nullable bounded `summary`, nullable `turnId`, `updatedAt`, and
|
|
26
|
+
`updatedBy`.
|
|
48
27
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`workspace init` is idempotent. It creates an empty configuration and task
|
|
55
|
-
log when missing, refreshes managed instructions, and removes legacy TaskChef
|
|
56
|
-
skill symlinks.
|
|
57
|
-
|
|
58
|
-
Every command resolves one workspace in this precedence order:
|
|
59
|
-
|
|
60
|
-
1. explicit `--workspace <path>`
|
|
61
|
-
2. `TASKCHEF_WORKSPACE`
|
|
62
|
-
3. `~/.agents/taskchef`
|
|
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
|
|
68
|
-
the resolved absolute path and its source. Bootstrap compares this canonical
|
|
69
|
-
path with native Codex projects, and when absent invokes the validated
|
|
70
|
-
`codex app <path>` command before verifying the native list again. It never
|
|
71
|
-
uses `codex add` or a hard-coded application bundle path.
|
|
72
|
-
|
|
73
|
-
`doctor` validates configuration, project paths, the JSONL log, managed
|
|
74
|
-
instructions, and the absence of legacy TaskChef skill links without modifying
|
|
75
|
-
the workspace.
|
|
76
|
-
|
|
77
|
-
Neither the workspace nor any directory containing it can be configured as a
|
|
78
|
-
delegation project. All project configuration and task-history mutations share
|
|
79
|
-
one cross-process workspace lock. Writers reread and validate state while
|
|
80
|
-
holding that lock and publish complete files by atomic replacement.
|
|
81
|
-
|
|
82
|
-
## Project configuration
|
|
83
|
-
|
|
84
|
-
`taskchef.json` is the user-facing routing configuration:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"schemaVersion": 2,
|
|
89
|
-
"projects": [
|
|
90
|
-
{
|
|
91
|
-
"name": "payments-api",
|
|
92
|
-
"path": "/workspace/payments-api",
|
|
93
|
-
"isGitRepository": true,
|
|
94
|
-
"githubRepos": [
|
|
95
|
-
"https://github.com/example/payments-api",
|
|
96
|
-
"https://github.com/example/payments-sdk"
|
|
97
|
-
],
|
|
98
|
-
"description": "Owns payment authorization, capture, refunds, and provider integrations."
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"name": "local-data-tools",
|
|
102
|
-
"path": "/workspace/local-data-tools",
|
|
103
|
-
"isGitRepository": false,
|
|
104
|
-
"githubRepos": []
|
|
105
|
-
}
|
|
106
|
-
]
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
- `schemaVersion` identifies the configuration format.
|
|
111
|
-
- `projects` lists the local routing targets.
|
|
112
|
-
- `name` is the unique human-readable project identity.
|
|
113
|
-
- `path` is the normalized, canonical local directory. A Git project must use
|
|
114
|
-
its repository root.
|
|
115
|
-
- `isGitRepository` identifies Git and non-Git projects.
|
|
116
|
-
- `githubRepos` is a deduplicated list of canonical GitHub repository URLs. Use
|
|
117
|
-
`[]` when the project advertises no repositories. A managed `*-workspace`
|
|
118
|
-
project lists each child or sub-repository that should route to it.
|
|
119
|
-
- `description` is optional routing context.
|
|
120
|
-
|
|
121
|
-
TaskChef classifies work against `name`, every URL in `githubRepos`, and
|
|
122
|
-
`description`. The path identifies the checkout but is not a routing hint. For
|
|
123
|
-
a GitHub issue or pull-request URL, TaskChef compares canonical,
|
|
124
|
-
case-insensitive owner/repository identities across every configured list. It
|
|
125
|
-
ignores the issue or PR suffix, `http` versus `https`, optional `www`, trailing
|
|
126
|
-
slashes, and trailing `.git`. It routes only when one configured project
|
|
127
|
-
matches; ambiguous and unmatched URLs are never guessed.
|
|
128
|
-
|
|
129
|
-
`project add` and `project import` detect Git status, exact Git roots, and
|
|
130
|
-
canonical GitHub origins. `--github-repo` is repeatable. Import merges by
|
|
131
|
-
canonical path, preserves an existing name or description when omitted, and
|
|
132
|
-
unions existing and imported repository lists without duplicates. `--replace`
|
|
133
|
-
replaces the configured set. Removing or replacing a project does not alter
|
|
134
|
-
historical task entries.
|
|
135
|
-
|
|
136
|
-
Schema version 2 replaces the string-or-null `githubRepo` field with the
|
|
137
|
-
list-valued `githubRepos` field. Schema-version-1 configurations remain
|
|
138
|
-
compatible: reads normalize a legacy string to one canonical list item and
|
|
139
|
-
legacy `null` to `[]`; `workspace init` persists the migration atomically, and
|
|
140
|
-
any later configuration write emits version 2.
|
|
141
|
-
|
|
142
|
-
The configuration does not store dispatcher identity, execution modes,
|
|
143
|
-
schedules, task state, host information, or the workspace path.
|
|
144
|
-
|
|
145
|
-
## Task entry
|
|
146
|
-
|
|
147
|
-
`tasks.jsonl` contains one compact JSON object per line, in append order:
|
|
148
|
-
|
|
149
|
-
```json
|
|
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"}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
- `schemaVersion` identifies the task entry format.
|
|
154
|
-
- `id` is a unique TaskChef task identifier.
|
|
155
|
-
- `project` is the complete configured project snapshot used for routing.
|
|
156
|
-
- `title` is a short task name.
|
|
157
|
-
- `instruction` is the complete executor instruction, including its first-line
|
|
158
|
-
`<!-- taskchef_id=<full UUID> -->` correlation marker, executor-ownership
|
|
159
|
-
paragraph, and assignment body.
|
|
160
|
-
- `threadId` identifies the created Codex task, or is `null` when creation was
|
|
161
|
-
accepted but its initial identity has not yet been linked.
|
|
162
|
-
- `createdAt` is the dispatch time as an ISO 8601 timestamp.
|
|
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
|
|
173
|
-
unique; any number of unresolved entries may have `threadId: null`. The file is
|
|
174
|
-
empty or newline terminated, with no blank lines. TaskChef rejects a malformed
|
|
175
|
-
log instead of skipping bad entries. Writers replace the complete validated
|
|
176
|
-
file atomically under a workspace lock, so an interrupted write leaves either
|
|
177
|
-
the old history or the complete new history.
|
|
178
|
-
|
|
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.
|
|
185
|
-
|
|
186
|
-
The project snapshot preserves the route even if the project is renamed,
|
|
187
|
-
moved, or removed later. Entries never contain transcripts, hidden reasoning,
|
|
188
|
-
`hostId`, or an event history.
|
|
189
|
-
|
|
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
|
|
193
|
-
old heading-style marker also remain readable. New nullable records, candidate
|
|
194
|
-
matching, and resolution require the exact HTML-comment marker; TaskChef never
|
|
195
|
-
uses an old marker to correlate a thread. Direct records that already have a
|
|
196
|
-
durable thread ID remain marker-independent because they do not use recovery.
|
|
197
|
-
TaskChef does not eagerly rewrite legacy history solely for these compatibility
|
|
198
|
-
cases.
|
|
28
|
+
New unresolved records require the exact first-line HTML marker followed by a
|
|
29
|
+
blank line. Schema 1-3 records and historical `updatedBy: hook` values remain
|
|
30
|
+
readable without eager migration, and task read/list APIs expose their persisted
|
|
31
|
+
schema version so reporting can distinguish legacy recovery from schema 4
|
|
32
|
+
executor link-pending state.
|
|
199
33
|
|
|
200
34
|
## Dispatch workflow
|
|
201
35
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
shows the durable success shape, while these transition rules define the
|
|
275
|
-
shorter failure and longer provisional shapes.
|
|
276
|
-
The writer derives `taskchefVersion` from the running package instead of
|
|
277
|
-
trusting template input. Raw executor output and transcripts are never stored;
|
|
278
|
-
`outputVerified` records only whether the requested output was verified.
|
|
279
|
-
|
|
280
|
-
The writer rejects missing required stages, duplicate or unknown stages,
|
|
281
|
-
invalid timestamps, contradictory workflow outcomes, overlapping stages,
|
|
282
|
-
unknown fields, and overwriting an existing run. Later stages are omitted when
|
|
283
|
-
preparation or creation fails, and provisional resolution is omitted when task
|
|
284
|
-
recording fails. Fallback snapshot observations include the complete recent
|
|
285
|
-
task count plus the filtered candidate and exact-match counts, from which
|
|
286
|
-
candidate-filter effectiveness is checked. Each snapshot records
|
|
287
|
-
`resolveWriteOutcome` as `not-attempted`, `succeeded`, or `failed`, so a unique
|
|
288
|
-
match followed by an atomic write failure remains an honest unresolved result.
|
|
289
|
-
A compact valid starting document is committed as
|
|
290
|
-
`assets/e2e-benchmark-example.json`. Filenames use
|
|
291
|
-
`<startedAt-with-colons-replaced>-taskchef-delegate-e2e.json`. Its cleanup
|
|
292
|
-
operation removes only files matching the full generated filename grammar in
|
|
293
|
-
the selected results directory.
|
|
294
|
-
|
|
295
|
-
`task record` rejects an interactive TTY before reading because its protocol is
|
|
296
|
-
exactly one JSON value followed by EOF. Workspace-lock contention is retried for
|
|
297
|
-
up to seven seconds, while permanent permission failures such as `EPERM` or
|
|
298
|
-
`EACCES` fail immediately so the caller can request the required permission
|
|
299
|
-
without paying the contention retry budget.
|
|
300
|
-
|
|
301
|
-
A failed executor creation normally leaves its pre-created entry with `failed`.
|
|
302
|
-
The exported orchestration helper attaches `taskChefTaskId` and
|
|
303
|
-
`taskChefResultReporting` (`recorded`, `failed`, or `unavailable`) to a thrown
|
|
304
|
-
creation error so callers can recover the entry if failure reporting itself was
|
|
305
|
-
not available. A failed pre-creation record stops before executor creation, so
|
|
306
|
-
there is no untracked executor.
|
|
307
|
-
|
|
308
|
-
## Task history and live reports
|
|
309
|
-
|
|
310
|
-
The CLI reads persisted history without contacting Codex:
|
|
311
|
-
|
|
312
|
-
- `task show <id-or-8-character-prefix>` returns one entry. By default it emits
|
|
313
|
-
labeled human-readable lines for title, project, status, summary, creation and
|
|
314
|
-
update metadata, task/thread/turn IDs, and instruction. A null ID renders as `-`.
|
|
315
|
-
Carriage returns and newlines in labeled values render as `\\r` and `\\n`.
|
|
316
|
-
The instruction starts on the line after `Instruction:` and retains its stored
|
|
317
|
-
line breaks and indentation. `--json` returns the unchanged complete task
|
|
318
|
-
object. The short form is the exact ID text printed by the default
|
|
319
|
-
human-readable `task list` output and succeeds only when it identifies
|
|
320
|
-
exactly one recorded task. Missing, ambiguous, malformed, shorter, and
|
|
321
|
-
wrong-case prefixes fail without selecting a task.
|
|
322
|
-
- `task list` returns entries newest-first by creation time, optionally filtered
|
|
323
|
-
by historical project name or exact path. `--ascending` returns oldest-first.
|
|
324
|
-
Human rows include status, update time, task ID, and thread ID, abbreviating UUID-shaped IDs
|
|
325
|
-
to their first eight-character section unless `--full-id` is passed. Null
|
|
326
|
-
thread IDs display as `-`. ID formatting does not alter JSON values, and the
|
|
327
|
-
selected order applies to both human rows and the JSON `tasks` array.
|
|
328
|
-
- `task summary` returns the total and per-project counts.
|
|
329
|
-
- `task resolve <id> --thread-id <thread-id>` atomically fills one nullable
|
|
330
|
-
thread ID after Codex verifies the exact structured marker match.
|
|
331
|
-
|
|
332
|
-
When the user requests an overview, `$taskchef-report` includes working,
|
|
333
|
-
needs-input, unresolved, legacy, and terminal tasks updated during the last
|
|
334
|
-
seven days. It omits older terminal entries unless explicitly requested or a
|
|
335
|
-
single recent-thread metadata snapshot shows that they are active or awaiting
|
|
336
|
-
approval. That one snapshot is a broad contradiction check: active or awaiting-
|
|
337
|
-
approval metadata overrides a cached result immediately, without one detailed
|
|
338
|
-
read per task. An inactive state does not prove semantic completion; in a broad
|
|
339
|
-
overview it permits an `updatedBy: mcp` result to stand by default.
|
|
340
|
-
Dispatcher- or hook-written `working` snapshots have no semantic callback and
|
|
341
|
-
trigger a live read when selected; an inactive task without an MCP callback has
|
|
342
|
-
an unknown outcome. An MCP-written `failed` snapshot with null thread/turn IDs
|
|
343
|
-
is a fresh executor-creation failure and requires no live lookup. For a focused
|
|
344
|
-
task, title, or project report, any newer matched metadata timestamp triggers at
|
|
345
|
-
most one targeted read per selected inactive task. This distinguishes normal
|
|
346
|
-
same-turn finalization from a quick newer turn by comparing structured turn IDs
|
|
347
|
-
and native turn state. Missing callbacks, uncertain or contradictory identity
|
|
348
|
-
or metadata, and explicitly fully-live requests also trigger one targeted read.
|
|
349
|
-
Reads are batched in groups of eight. Broad overviews do not fan out reads over
|
|
350
|
-
idle terminal tasks solely because their timestamps are newer. Reporting never
|
|
351
|
-
persists inferred live state and does not poll, wait, or schedule work.
|
|
352
|
-
|
|
353
|
-
## Boundaries
|
|
354
|
-
|
|
355
|
-
TaskChef does not include:
|
|
356
|
-
|
|
357
|
-
- lifecycle event history or hook-inferred completion
|
|
358
|
-
- lifecycle event types beyond `UserPromptSubmit`
|
|
359
|
-
- indefinite polling, daemons, heartbeats, dispatcher wakeups, or schedules
|
|
360
|
-
- arbitrary Codex task discovery
|
|
361
|
-
- remote hosts or `hostId` storage
|
|
362
|
-
- transcript or hidden-reasoning collection
|
|
363
|
-
- one-active-task-per-project restrictions
|
|
364
|
-
- batch cancellation or replay
|
|
365
|
-
- bundled development runtimes in dispatcher workspaces.
|
|
366
|
-
|
|
367
|
-
## Acceptance test
|
|
368
|
-
|
|
369
|
-
1. Bootstrap creates `AGENTS.md`, `taskchef.json`, and `tasks.jsonl`, then
|
|
370
|
-
remains idempotent.
|
|
371
|
-
2. Project metadata routes an unambiguous request to the correct local project.
|
|
372
|
-
3. A delegation records `working` before creating a visible Codex task.
|
|
373
|
-
4. A durable creation resolves immediately; a provisional creation is linked
|
|
374
|
-
only after bounded discovery verifies one exact structured-marker match.
|
|
375
|
-
5. The dispatcher returns without waiting for execution.
|
|
376
|
-
6. Several independent assignments can create several entries, including
|
|
377
|
-
multiple entries for the same project.
|
|
378
|
-
7. Task history commands return deterministic entries and project counts.
|
|
379
|
-
8. MCP callbacks replace the latest needs-input, completed, or failed snapshot.
|
|
380
|
-
9. A report skips old terminal tasks by default, checks live metadata once,
|
|
381
|
-
overrides active or approval-waiting tasks directly, and reads only anomalous
|
|
382
|
-
candidates without writing inferred state.
|
|
383
|
-
10. Malformed JSONL, duplicate IDs, duplicate thread IDs, and symlinked managed
|
|
384
|
-
files fail safely.
|
|
36
|
+
1. `prepare_dispatch` validates the workspace and returns one fresh lowercase
|
|
37
|
+
UUID, exact marker, timestamp, and routing targets.
|
|
38
|
+
2. The marked instruction contains the executor ownership paragraph, mandatory
|
|
39
|
+
first-action `link_task` paragraph, result callback paragraph, and task body.
|
|
40
|
+
3. `record_task` writes schema 4 with `threadId: null` before creation.
|
|
41
|
+
4. Native task creation runs once.
|
|
42
|
+
5. The dispatcher returns immediately, including for a provisional worktree
|
|
43
|
+
client ID. It does not list or read tasks, search markers, wait, poll, or
|
|
44
|
+
link the record.
|
|
45
|
+
6. Creation failure writes a terminal `failed` result with null identities and
|
|
46
|
+
a concise bounded summary.
|
|
47
|
+
|
|
48
|
+
## Executor self-linking
|
|
49
|
+
|
|
50
|
+
The executor obtains its own durable native thread ID and calls
|
|
51
|
+
`link_task(taskId, threadId)` before substantive work. The operation:
|
|
52
|
+
|
|
53
|
+
- accepts only schema 4 records;
|
|
54
|
+
- rejects unknown task IDs, malformed/provisional IDs, exact-marker mismatch,
|
|
55
|
+
thread reuse, and conflicting retries;
|
|
56
|
+
- atomically changes only `null` to one durable ID under the workspace lock;
|
|
57
|
+
- is idempotent for the same task and ID;
|
|
58
|
+
- leaves rejected, unavailable, interrupted, or cancelled links visibly
|
|
59
|
+
pending and retryable.
|
|
60
|
+
|
|
61
|
+
The executor must never use a parent/delegator ID, inherited session identity,
|
|
62
|
+
title match, or provisional client ID. This is a cooperative local assertion,
|
|
63
|
+
not transport-authenticated caller identity.
|
|
64
|
+
|
|
65
|
+
## Semantic results
|
|
66
|
+
|
|
67
|
+
`report_result` accepts `completed`, `needs_input`, or `failed` with a concise
|
|
68
|
+
summary. Linked tasks require an exact stored thread-ID match and a non-null
|
|
69
|
+
current turn ID. Self-linked schema 4 journeys require canonical, time-ordered
|
|
70
|
+
Codex UUID turn IDs; each changed semantic result must use an ID newer than the
|
|
71
|
+
stored turn, while an identical same-turn retry is idempotent. Creation failure
|
|
72
|
+
is the sole null-identity result. Follow-up turns must self-read the exact
|
|
73
|
+
thread and submit the new turn ID. Atomic writes preserve one JSONL line per
|
|
74
|
+
task.
|
|
75
|
+
|
|
76
|
+
## Legacy resolver
|
|
77
|
+
|
|
78
|
+
The CLI-only `taskchef task resolve` command accepts unresolved schema 1-3
|
|
79
|
+
records after an operator establishes one exact marker match. It rejects schema
|
|
80
|
+
4 records. There is no public `resolve_task` MCP tool.
|
|
81
|
+
|
|
82
|
+
## Dashboard and reports
|
|
83
|
+
|
|
84
|
+
The existing file watcher observes `link_task` and result rewrites in real
|
|
85
|
+
time. "Open task in Codex" uses only the self-linked child ID. Reports treat
|
|
86
|
+
`updatedBy: mcp` terminal or needs-input snapshots as semantic cache and may
|
|
87
|
+
compare them with one native metadata snapshot. Reporting never mutates task
|
|
88
|
+
history or infers completion from hooks.
|
|
89
|
+
|
|
90
|
+
## Packaging
|
|
91
|
+
|
|
92
|
+
The plugin ships its skills, MCP server, CLI, dashboard, and source modules. It
|
|
93
|
+
contains no hooks configuration, hook executable, hook runtime, or hook trust
|
|
94
|
+
requirement.
|
|
95
|
+
|
|
96
|
+
## Acceptance
|
|
97
|
+
|
|
98
|
+
- Record-before-create and exact-marker guarantees remain mandatory.
|
|
99
|
+
- Creation returns without post-create waiting, polling, task search, or reads.
|
|
100
|
+
- A provisional-path executor self-links its exact durable child ID before
|
|
101
|
+
substantive work.
|
|
102
|
+
- Parent/delegator and provisional IDs cannot be accidentally substituted.
|
|
103
|
+
- Link and result retries are idempotent; conflicts cannot corrupt JSONL.
|
|
104
|
+
- Link failures remain visible and retryable; creation failures are terminal.
|
|
105
|
+
- Current-turn freshness is retained across needs-input, follow-up, and final
|
|
106
|
+
completion.
|
|
107
|
+
- The plugin installs and runs without hook configuration or approval.
|
|
@@ -1,46 +1,50 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
3
|
-
"benchmark": "taskchef-
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"benchmark": "taskchef-executor-self-link-e2e",
|
|
4
|
+
"taskchefVersion": "0.0.0",
|
|
4
5
|
"runId": "replace-with-run-id",
|
|
5
|
-
"startedAt": "2026-08-
|
|
6
|
-
"completedAt": "2026-08-
|
|
6
|
+
"startedAt": "2026-08-24T10:00:00.000Z",
|
|
7
|
+
"completedAt": "2026-08-24T10:01:00.000Z",
|
|
7
8
|
"workload": {
|
|
8
9
|
"project": "example-project",
|
|
9
|
-
"title": "
|
|
10
|
-
"prompt": "
|
|
10
|
+
"title": "Provisional self-link example",
|
|
11
|
+
"prompt": "Pause for approval, then complete the requested work."
|
|
11
12
|
},
|
|
12
13
|
"task": {
|
|
13
14
|
"taskId": "00000000-0000-4000-8000-000000000000",
|
|
14
15
|
"threadId": "00000000-0000-7000-8000-000000000000",
|
|
15
|
-
"clientThreadId":
|
|
16
|
+
"clientThreadId": "local:replace-with-provisional-id",
|
|
16
17
|
"recorded": true,
|
|
17
|
-
"
|
|
18
|
-
|
|
18
|
+
"linked": true
|
|
19
|
+
},
|
|
20
|
+
"turns": {
|
|
21
|
+
"needsInput": "00000000-0001-7000-8000-000000000000",
|
|
22
|
+
"completion": "00000000-0002-7000-8000-000000000000"
|
|
23
|
+
},
|
|
24
|
+
"events": {
|
|
25
|
+
"preparedAt": "2026-08-24T10:00:00.000Z",
|
|
26
|
+
"recordedAt": "2026-08-24T10:00:01.000Z",
|
|
27
|
+
"createdAt": "2026-08-24T10:00:02.000Z",
|
|
28
|
+
"linkedAt": "2026-08-24T10:00:05.000Z",
|
|
29
|
+
"needsInputAt": "2026-08-24T10:00:20.000Z",
|
|
30
|
+
"followedUpAt": "2026-08-24T10:00:40.000Z",
|
|
31
|
+
"completedAt": "2026-08-24T10:01:00.000Z"
|
|
19
32
|
},
|
|
20
|
-
"stages": [
|
|
21
|
-
{
|
|
22
|
-
"name": "prepare-and-list-projects",
|
|
23
|
-
"startedAt": "2026-08-13T06:30:00.000Z",
|
|
24
|
-
"completedAt": "2026-08-13T06:30:00.200Z",
|
|
25
|
-
"outcome": "success"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"name": "create-thread",
|
|
29
|
-
"startedAt": "2026-08-13T06:30:01.000Z",
|
|
30
|
-
"completedAt": "2026-08-13T06:30:01.100Z",
|
|
31
|
-
"outcome": "durable"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"name": "record-task",
|
|
35
|
-
"startedAt": "2026-08-13T06:30:02.000Z",
|
|
36
|
-
"completedAt": "2026-08-13T06:30:04.000Z",
|
|
37
|
-
"outcome": "recorded"
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
33
|
"validation": {
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
34
|
+
"exactMarkerCorrelated": true,
|
|
35
|
+
"noDispatcherPostCreateReads": true,
|
|
36
|
+
"childIdentityVerified": true,
|
|
37
|
+
"parentIdentityRejected": true,
|
|
38
|
+
"linkRetryVerified": true,
|
|
39
|
+
"needsInputVerified": true,
|
|
40
|
+
"followUpTurnFresh": true,
|
|
41
|
+
"dashboardDeepLinkVerified": true,
|
|
42
|
+
"outputVerified": true
|
|
43
|
+
},
|
|
44
|
+
"summary": {
|
|
45
|
+
"totalWallMs": 60000,
|
|
46
|
+
"provisionalPath": true,
|
|
47
|
+
"linked": true,
|
|
48
|
+
"freshFollowUp": true
|
|
45
49
|
}
|
|
46
50
|
}
|