taskchef 5.12.0 → 6.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.
package/SPEC.md CHANGED
@@ -2,383 +2,106 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- TaskChef is an interactive Codex dispatcher. It routes independent assignments
6
- to real Codex tasks in configured local projects, records each submitted
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
- Codex tasks remain authoritative for current activity. TaskChef stores only the
11
- latest useful semantic result, not a second lifecycle or event database.
8
+ ## Workspace
12
9
 
13
- ## Core behavior
10
+ The canonical workspace contains only:
14
11
 
15
- 1. The user submits a request in the dispatcher workspace or explicitly invokes
16
- the delegation skill from another Codex project. Work merely concerning the
17
- TaskChef source code does not implicitly invoke delegation outside the
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
- A task created by TaskChef owns its delegated initial assignment. It executes
33
- that assignment in the current task and does not re-dispatch it merely because
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
- Several active executors may target the same project.
19
+ ## Task schema
39
20
 
40
- ## Workspace layout
21
+ New records use schema version 4 and contain:
41
22
 
42
- ```text
43
- ~/.agents/taskchef/
44
- ├── AGENTS.md
45
- ├── taskchef.json
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
- `AGENTS.md` contains a marked block that routes setup and administration to
50
- `$taskchef-bootstrap`, actionable work to `$taskchef-delegate`, and explicit
51
- live report requests to `$taskchef-report`. Bootstrap preserves unrelated
52
- instructions and refreshes only the managed block.
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
- For each assignment, `$taskchef-delegate`:
203
-
204
- 1. calls the structured `prepare_dispatch` tool and native Codex project
205
- discovery concurrently; the preparation tool resolves the canonical
206
- workspace, loads and
207
- validates configured projects, and generates the full UUID, preparation
208
- timestamp, and exact marker in one process; it never takes a pre-creation
209
- thread snapshot
210
- 2. selects one unambiguous configured target and matches its exact path against
211
- the already-loaded native projects
212
- 3. prefixes the instruction with the prepared exact
213
- `<!-- taskchef_id=<UUID> -->` marker as the first line, followed by a blank
214
- line, the executor-ownership sentence, result-callback sentence, and
215
- assignment body
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
- checks at 10 and 30 seconds and resolves only one recent task whose
221
- structured initial input contains the exact marker
222
- 7. records executor-creation failure as a `failed` semantic result on the
223
- already-existing entry
224
- 8. returns after the bounded identity check without waiting for executor work.
225
-
226
- Recording first closes the creation/hook race. On the exact marked prompt, the
227
- hook waits for the separately verified canonical identity, then writes only the
228
- initial turn plus `working`. It never persists the hook `session_id`, because a
229
- subagent hook can receive its parent's session ID. On later prompts whose
230
- session ID matches a recorded executor,
231
- the same `UserPromptSubmit` hook reads the task history and supplies the current
232
- turn ID as callback context without writing. No permission, tool, stop,
233
- notification, or session hook writes task lifecycle state. A provisional
234
- `local:` ID is diagnostic only and can never be persisted as `threadId`.
235
-
236
- The plugin bundles a local stdio MCP server with focused `prepare_dispatch`,
237
- `record_task`, `resolve_task`, and `report_result` tools. It accepts no workspace path from the
238
- model and resolves only an absolute (or `~/`-prefixed) `TASKCHEF_WORKSPACE` or the canonical
239
- `~/.agents/taskchef` default. The write tools reuse the public workspace APIs,
240
- so structured calls cannot bypass exact-field validation, locking, atomic
241
- replacement, unique IDs, or one-way nullable resolution. They are closed-world
242
- local mutations and never create Codex tasks. Desktop thread tools remain
243
- available only to the Codex skill; the standalone CLI remains available for
244
- bootstrap, manual inspection, and recovery.
245
-
246
- ### Legacy end-to-end benchmark results
247
-
248
- Schema-v1 benchmark fixtures below validate historical bounded-resolver
249
- artifacts only. New benchmarks must measure record-before-create, initial-hook
250
- identity, and result callbacks without using the removed snapshot resolver.
251
-
252
- An explicitly requested live benchmark writes one ignored, timestamped JSON
253
- artifact through `scripts/e2e-benchmark.js`. Schema version 1 contains:
254
-
255
- - benchmark name, TaskChef version, run ID, and wall-clock start/end
256
- - project, title, and exact unmarked workload prompt
257
- - TaskChef task ID, nullable durable/client IDs, recording state, resolution,
258
- and attempt count
259
- - ISO start/end, derived duration, and outcome for preparation/project listing,
260
- task creation, recording, and optional provisional resolution
261
- - boolean record, marker, executor-output, and candidate-filter-effectiveness
262
- validation results
263
- - derived total wall time, measured stage time, orchestration overhead,
264
- resolution state, and attempt count
265
-
266
- Stage outcomes are `success|failed` for preparation,
267
- `durable|provisional|failed` for creation, `recorded|failed` for recording, and
268
- `native|discovered|unresolved|failed` for provisional resolution. `failed`
269
- distinguishes a terminal resolver error from a completed no-match checkpoint,
270
- which must proceed to the second fallback attempt. Task resolution is
271
- `immediate|native|discovered|unresolved`. Preparation failure has only the
272
- preparation stage and a null task ID; creation failure stops after creation;
273
- recording failure stops before provisional resolution. The committed example
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": 1,
3
- "benchmark": "taskchef-delegate-e2e",
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-13T06:30:00.000Z",
6
- "completedAt": "2026-08-13T06:30:05.000Z",
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": "Example workload",
10
- "prompt": "Return the requested example output."
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": null,
16
+ "clientThreadId": "local:replace-with-provisional-id",
16
17
  "recorded": true,
17
- "resolution": "immediate",
18
- "resolutionAttempts": 0
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
- "recordVerified": true,
42
- "markerVerified": true,
43
- "outputVerified": false,
44
- "candidateFilterEffective": false
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
  }
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
2
+ <rect x="2" y="2" width="44" height="44" rx="11" fill="#F59E0B"/>
3
+ <path d="M15 37V27.5C11.9 26.3 10 23.6 10 20.5C10 16.4 13.4 13 17.5 13C19 10 21.2 8.5 24 8.5C26.8 8.5 29 10 30.5 13C34.6 13 38 16.4 38 20.5C38 23.6 36.1 26.3 33 27.5V37H15Z" fill="#FFFBEB"/>
4
+ <path d="M19 24L22 27L28.5 20.5" stroke="#78350F" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M24 28V32M24 32H19M24 32H29" stroke="#78350F" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <circle cx="19" cy="32" r="2" fill="#78350F"/>
7
+ <circle cx="29" cy="32" r="2" fill="#78350F"/>
8
+ <path d="M15 37H33" stroke="#78350F" stroke-width="3" stroke-linecap="round"/>
9
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
2
+ <rect x="2" y="2" width="44" height="44" rx="11" fill="#D97706"/>
3
+ <path d="M15 37V27.5C11.9 26.3 10 23.6 10 20.5C10 16.4 13.4 13 17.5 13C19 10 21.2 8.5 24 8.5C26.8 8.5 29 10 30.5 13C34.6 13 38 16.4 38 20.5C38 23.6 36.1 26.3 33 27.5V37H15Z" fill="#FFF7ED"/>
4
+ <path d="M19 24L22 27L28.5 20.5" stroke="#7C2D12" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
5
+ <path d="M24 28V32M24 32H19M24 32H29" stroke="#7C2D12" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
6
+ <circle cx="19" cy="32" r="2" fill="#7C2D12"/>
7
+ <circle cx="29" cy="32" r="2" fill="#7C2D12"/>
8
+ <path d="M15 37H33" stroke="#7C2D12" stroke-width="3" stroke-linecap="round"/>
9
+ </svg>