@exaudeus/workrail 3.74.1 → 3.74.3
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/dist/application/services/workflow-interpreter.js +22 -0
- package/dist/console-ui/assets/{index-BmDxs-a5.js → index-ByqIsoyt.js} +1 -1
- package/dist/console-ui/index.html +1 -1
- package/dist/daemon/session-scope.d.ts +7 -1
- package/dist/daemon/workflow-runner.d.ts +11 -4
- package/dist/daemon/workflow-runner.js +92 -66
- package/dist/manifest.json +13 -13
- package/dist/v2/durable-core/domain/context-template-resolver.js +34 -9
- package/docs/ideas/backlog.md +227 -27
- package/package.json +1 -1
- package/workflows/routines/tension-driven-design.json +26 -15
- package/workflows/wr.discovery.json +153 -16
package/docs/ideas/backlog.md
CHANGED
|
@@ -65,26 +65,50 @@ No proposed solutions here -- just the problem.]
|
|
|
65
65
|
|
|
66
66
|
### wr.coding-task forEach loop exposes broken agent-facing state (Apr 30, 2026)
|
|
67
67
|
|
|
68
|
-
**Status:
|
|
68
|
+
**Status: done** | Shipped May 1, 2026 (PR #926)
|
|
69
69
|
|
|
70
70
|
**Score: 13** | Cor:3 Cap:1 Eff:2 Lev:2 Con:3 | Blocked: no
|
|
71
71
|
|
|
72
|
-
The `
|
|
72
|
+
**Root cause (diagnosed Apr 30, 2026):** The agent wrote `slices` as an array of plain strings (`["1: slice name", ...]`) instead of objects (`[{name: "...", ...}]`). The engine accepted the array (it was an array), entered the loop, and `{{currentSlice.name}}` silently resolved to `[unset]` on every iteration because strings don't have a `.name` property.
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
**Shipped (PR #926):**
|
|
75
|
+
1. **forEach shape guard** (`workflow-interpreter.ts`): at iteration 0, if the body uses `{{itemVar.field}}` dot-path access but the items array contains primitives, returns `LOOP_MISSING_CONTEXT` with a message naming the actual type and a preview of the bad value. The loop never enters with broken state.
|
|
76
|
+
2. **Diagnostic `[unset]` messages** (`context-template-resolver.ts`): when dot-path navigation fails mid-path due to a type mismatch (e.g. `currentSlice` is a string), the rendered prompt now shows `[unset: currentSlice.name -- 'currentSlice' is string ("1: Auth..."), not object]` instead of just `[unset: currentSlice.name]`.
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
**Remaining open (separate items):** context contract enforcement (systemic fix), `todoList` abstraction, `wr.loop_control` shown in forEach prompts.
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
**GitHub issue:** https://github.com/EtienneBBeaulac/workrail/issues/920
|
|
81
|
+
|
|
82
|
+
---
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
### Context contract: steps must declare required and produced context keys (Apr 30, 2026)
|
|
81
85
|
|
|
82
|
-
**
|
|
86
|
+
**Status: tentative** | Priority: medium
|
|
87
|
+
|
|
88
|
+
**Score: 12** | Cor:3 Cap:2 Eff:1 Lev:3 Con:2 | Blocked: no
|
|
89
|
+
|
|
90
|
+
The engine has no mechanism to enforce context between steps. `Capture:` instructions in step prompts are prose -- the engine accepts `continue_workflow` with empty context on every advance, silently. This is the systemic root of the forEach `[unset]` bug: the agent wrote planning output as notes, not as context, and the engine accepted every advance without complaint. The same failure can happen in any workflow that passes state between steps.
|
|
91
|
+
|
|
92
|
+
**Things to hash out:**
|
|
93
|
+
- What schema format should `contextContract` use -- JSON Schema subset or a simpler workrail-specific type DSL?
|
|
94
|
+
- Should validation be blocking (engine rejects the advance) or advisory (engine warns in the next step prompt)?
|
|
95
|
+
- Does context contract cover loop entry preconditions, or does the separate forEach guard item handle that?
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### `todoList` step type: ergonomic abstraction over forEach (Apr 30, 2026)
|
|
100
|
+
|
|
101
|
+
**Status: idea** | Priority: medium
|
|
102
|
+
|
|
103
|
+
**Score: 10** | Cor:2 Cap:3 Eff:1 Lev:2 Con:2 | Blocked: no
|
|
104
|
+
|
|
105
|
+
Workflow authors using forEach must manually wire a prior step to populate the items array, understand iteration variables, avoid emitting `wr.loop_control` artifacts (which have no effect in forEach), and explain the loop framing to the agent. The forEach shape guard (PR #926) now catches primitive-item arrays loudly at loop entry, but the wiring between "the step that produces items" and "the loop that consumes them" remains implicit and invisible to the engine. The `todoList` abstraction would make this wiring structural.
|
|
83
106
|
|
|
84
107
|
**Things to hash out:**
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
108
|
+
- Should `todoList` compile to a forEach loop at the engine layer, or be a new execution primitive?
|
|
109
|
+
- How does the setup step that produces the items array get authored -- inline prompt, routine reference, or both?
|
|
110
|
+
- What does the agent-facing presentation look like: "Item 3 of 8" with item content injected, or something else?
|
|
111
|
+
- Should `wr.loop_control` artifacts be stripped from the step prompt entirely in a `todoList`, or does the agent still need an explicit completion signal?
|
|
88
112
|
|
|
89
113
|
---
|
|
90
114
|
|
|
@@ -234,6 +258,71 @@ This is exactly what happened with the commit SHA change: setting `agentCommitSh
|
|
|
234
258
|
The autonomous workflow runner (`worktrain daemon`). Completely separate from the MCP server -- calls the engine directly in-process.
|
|
235
259
|
|
|
236
260
|
|
|
261
|
+
### Living work context: shared knowledge document that accumulates across the full pipeline (Apr 30, 2026)
|
|
262
|
+
|
|
263
|
+
**Status: idea** | Priority: high
|
|
264
|
+
|
|
265
|
+
**Score: 13** | Cor:3 Cap:3 Eff:2 Lev:3 Con:2 | Blocked: no
|
|
266
|
+
|
|
267
|
+
When a multi-agent pipeline runs -- discovery → shaping → coding → review → fix → re-review -- no agent has a complete picture of what came before it. The coding agent has the goal. The review agent has the code. The fix agent has the findings. None of them have the accumulated context from the full pipeline: why this approach was chosen over alternatives, what was ruled out, what constraints were discovered, what architectural decisions were made, what edge cases were handled, what the review found and why.
|
|
268
|
+
|
|
269
|
+
Each agent reconstructs intent from incomplete context, which is why review finds things coding missed (review doesn't know what the coding agent was trying to do), why fix sessions address symptoms without understanding causes (no access to the architectural reasoning), and why agents repeat work that earlier agents already did.
|
|
270
|
+
|
|
271
|
+
**The real need:** a **living work context document** that every agent in the pipeline both reads from and contributes to:
|
|
272
|
+
|
|
273
|
+
- **Discovery adds**: why this approach over alternatives, what was ruled out, constraints found
|
|
274
|
+
- **Shaping adds**: the bounded problem, no-gos, acceptance criteria -- the verifiable contract
|
|
275
|
+
- **Architecture/coding adds**: why specific decisions were made, what invariants must hold, what was deliberately deferred and why
|
|
276
|
+
- **Review adds**: what was found, the underlying reason it was missed, what the fix must address
|
|
277
|
+
- **Fix adds**: what was changed and why the fix is correct per the spec
|
|
278
|
+
|
|
279
|
+
The spec from shaping is one layer of this -- the *what to build* contract. But the full context also includes the *why* from discovery, the *how* decisions from coding, and the *what was missed* from review. All of it should be accessible to every downstream agent.
|
|
280
|
+
|
|
281
|
+
This is related to the "session knowledge log" backlog entry (agents appending to `session-knowledge.jsonl`) but is explicitly a **multi-agent shared artifact**, not a single session's private log. The coordinator is responsible for maintaining and passing this document to each spawned agent.
|
|
282
|
+
|
|
283
|
+
**Things to hash out:**
|
|
284
|
+
- What is the right format? A growing markdown document is human-readable but hard to query. Structured JSON is queryable but loses the narrative. A hybrid (structured frontmatter + narrative body) may be best.
|
|
285
|
+
- Where does it live? In the worktree (accessible to the coding agent)? In a well-known workspace path? In the session store (accessible to all agents via `read_artifact`)?
|
|
286
|
+
- Who owns writing to it -- the coordinator (scripts that have no LLM)? Each agent? Both?
|
|
287
|
+
- When a pure coordinator pipeline has no main agent, who synthesizes the discovery findings into the document? The discovery agent writes its own section; the coordinator passes it through. But synthesis across sections (connecting discovery constraints to coding decisions) requires reasoning.
|
|
288
|
+
- How does the review agent know which work context applies to the current PR? It needs discovery without being told explicitly.
|
|
289
|
+
- What's the minimum viable version -- is just passing the shaped spec (`SPEC.md`) to the coding and review agents already a major improvement, even without the full living document?
|
|
290
|
+
- This is distinct from "context injection at dispatch time" (passing a static bundle) -- the living document evolves as the pipeline progresses. Does the coordinator update it after each phase completes?
|
|
291
|
+
- **Is "document" even the right abstraction?** A flat document implies agents read it linearly. But agents need to query it selectively -- the coding agent needs "what constraints affect this decision?", the review agent needs "what did the coding agent say about this module?". A structured knowledge store (typed facts, queryable by agent role and topic) may be more useful than a document. This connects to the knowledge graph backlog entry -- the work-unit knowledge store may be a per-pipeline instance of the same infrastructure. This is worth hashing out before designing the format.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### Move backlog to a dedicated worktrain-meta repo (Apr 30, 2026)
|
|
296
|
+
|
|
297
|
+
**Status: idea** | Priority: high
|
|
298
|
+
|
|
299
|
+
**Score: 11** | Cor:2 Cap:2 Eff:2 Lev:3 Con:3 | Blocked: no
|
|
300
|
+
|
|
301
|
+
The backlog (`docs/ideas/backlog.md`) lives in the code repo, which means every feature branch has its own version of it. Ideas added mid-session on a feature branch are held hostage until that PR merges. If two branches both modify the backlog, git merge conflicts occur. There is no single authoritative place to add an idea that immediately applies everywhere.
|
|
302
|
+
|
|
303
|
+
**Proposed fix:** move the backlog to a dedicated `worktrain-meta` repo (e.g. `~/git/personal/worktrain-meta/`). This is a separate git repo that is never branched for feature work -- you commit and push directly to main whenever an idea is added. Full git history is preserved. No code branch ever touches it. WorkTrain daemon sessions and the `npm run backlog` script are configured with the path to this repo.
|
|
304
|
+
|
|
305
|
+
**Why separate repo over a dedicated branch in this repo:**
|
|
306
|
+
- A dedicated branch in this repo can be accidentally contaminated by a rebase or merge
|
|
307
|
+
- CI runs on every push to a branch here -- wasting resources on docs-only changes
|
|
308
|
+
- The backlog lifecycle (ideas, grooming, scoring) is independent of the code release cycle -- they should be independent repos
|
|
309
|
+
- When native backlog operations (structured data, SQLite) are built later, the backlog is already isolated and the migration doesn't touch the code repo
|
|
310
|
+
|
|
311
|
+
**Migration steps:**
|
|
312
|
+
1. Create `~/git/personal/worktrain-meta/` git repo, push to GitHub as a new repo
|
|
313
|
+
2. Move `docs/ideas/backlog.md` there as the initial commit
|
|
314
|
+
3. Update `scripts/backlog-priority.ts` path
|
|
315
|
+
4. Update AGENTS.md reference to `npm run backlog`
|
|
316
|
+
5. Update daemon-soul.md and any session context that references the backlog path
|
|
317
|
+
6. Add `backlogRepoPath` to `~/.workrail/config.json` so the daemon knows where to find it
|
|
318
|
+
|
|
319
|
+
**Things to hash out:**
|
|
320
|
+
- Should the worktrain-meta repo also hold other cross-cutting artifacts like planning docs, the now-next-later roadmap, open-work-inventory? Or just the backlog?
|
|
321
|
+
- How do subagents spawned in a worktree find the backlog? They need the path configured, not relative to the code workspace.
|
|
322
|
+
- When native structured backlog operations are built, does the storage backend (SQLite) live in worktrain-meta or in `~/.workrail/data/`? The history requirement points toward worktrain-meta (git-tracked), but query performance points toward `~/.workrail/data/` (local database).
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
237
326
|
### Subagent context package: project vision and task goal baked into spawning (Apr 30, 2026)
|
|
238
327
|
|
|
239
328
|
**Status: idea** | Priority: high
|
|
@@ -333,21 +422,7 @@ Five dimensions, each scored 1-3. Score = sum (max 15). Items marked **Blocked**
|
|
|
333
422
|
|
|
334
423
|
### `delivery_failed` unreachable in `getChildSessionResult` -- type promises more than code delivers (Apr 30, 2026)
|
|
335
424
|
|
|
336
|
-
**Status:
|
|
337
|
-
|
|
338
|
-
**Score: 10** | Cor:3 Cap:1 Eff:2 Lev:2 Con:2 | Blocked: no
|
|
339
|
-
|
|
340
|
-
`ChildSessionResult` has `reason: 'delivery_failed'` as a variant of `kind: 'failed'`. However `fetchChildSessionResult` in `coordinator-deps.ts` reads session status through `ConsoleService.getSessionDetail`, which returns statuses like `complete`/`blocked`/`in_progress` -- it never returns a `delivery_failed` status. `delivery_failed` is a `TriggerRouter`-level concept (callbackUrl POST failure) that is not stored as a session status in the event log. Child sessions spawned via `spawnSession`/`spawnAndAwait` have no `callbackUrl` and cannot produce it through this code path.
|
|
341
|
-
|
|
342
|
-
The result: coordinators using `getChildSessionResult` can never observe `reason: 'delivery_failed'`, even though the type says they might. This violates the "make illegal states unrepresentable" principle -- the type union promises a variant the implementation cannot produce on this path.
|
|
343
|
-
|
|
344
|
-
**Architectural fix (not a comment):** surface `delivery_failed` through session status. When `TriggerRouter` records a `delivery_failed` outcome, write a corresponding session event or status that `ConsoleService.getSessionDetail` returns. Then `fetchChildSessionResult` can map it correctly. This closes the gap between what the type promises and what the infrastructure delivers.
|
|
345
|
-
|
|
346
|
-
Alternative: if `spawnSession`/`spawnAndAwait` child sessions genuinely cannot have `delivery_failed` outcomes by design, remove `reason: 'delivery_failed'` from `ChildSessionResult` entirely and document that it only exists in `spawn_agent`'s direct outcome mapping.
|
|
347
|
-
|
|
348
|
-
**Things to hash out:**
|
|
349
|
-
- Should `delivery_failed` be surfaced through ConsoleService (requires touching session status storage), or removed from `ChildSessionResult` since the `spawnSession` path provably cannot produce it?
|
|
350
|
-
- If surfaced: what event or field in the session store carries this status, and how does ConsoleService project it?
|
|
425
|
+
**Status: done** | Fixed in `cd8aaeb8` -- `delivery_failed` removed from `ChildSessionResult` entirely. The `spawnSession`/`spawnAndAwait` path cannot produce it by design; it only exists in `spawn_agent`'s direct outcome mapping.
|
|
351
426
|
|
|
352
427
|
---
|
|
353
428
|
|
|
@@ -367,19 +442,27 @@ Alternative: if `spawnSession`/`spawnAndAwait` child sessions genuinely cannot h
|
|
|
367
442
|
|
|
368
443
|
### Daemon architecture: remaining migrations (Apr 29, 2026)
|
|
369
444
|
|
|
370
|
-
**Status: partial** | A9 shipped Apr 29, 2026.
|
|
445
|
+
**Status: partial** | A9 shipped Apr 29, 2026. FC/IS follow-on shipped Apr 30 -- May 1, 2026.
|
|
371
446
|
|
|
372
447
|
**Score: 8** | Cor:1 Cap:1 Eff:2 Lev:1 Con:3 | Blocked: no
|
|
373
448
|
|
|
374
449
|
Track A (A1-A9) shipped and the `SessionSource` migration is complete. `WorkflowTrigger._preAllocatedStartResponse` is gone.
|
|
375
450
|
|
|
451
|
+
**Shipped Apr 30 -- May 1, 2026 (PR #925):**
|
|
452
|
+
- `TerminalSignal` union replaces `stuckReason` + `timeoutReason`. Illegal state (stuck AND timeout simultaneously) now structurally impossible. Stall overwrite bug fixed. `Readonly<SessionState>` at pure read sites.
|
|
453
|
+
- `SessionScope` capability boundary complete: `onTokenUpdate`, `onIssueReported`, `onSteer`, `getCurrentToken`, `sessionWorkspacePath`, spawn depths all named scope fields. `constructTools` signature is `(ctx, apiKey, schemas, scope)` -- zero direct `state.X` references.
|
|
454
|
+
- Early-exit paths unified through `finalizeSession`. `SteerRegistry`/`AbortRegistry` dead exports removed.
|
|
455
|
+
- Architecture tests enforce `state.terminalSignal` write restriction and `constructTools` state-access restriction in CI.
|
|
456
|
+
- `persistTokens` failure early-exit path covered by new outcome invariants tests.
|
|
457
|
+
|
|
376
458
|
**Remaining items:**
|
|
377
459
|
|
|
378
460
|
- `CriticalEffect<T>` / `ObservabilityEffect` type distinction -- categorize side effects in `runAgentLoop` and finalization as either crash-relevant or observability-only
|
|
379
|
-
- `StateRef` mutation wrapper -- replace direct `state.pendingSteerParts.push()` mutations with an explicit mutation API
|
|
380
461
|
- Zod tool param validation -- replace manual `typeof` checks in tool factories with Zod schema validation (requires `zodToJsonSchema` or maintaining two sources of truth for param schemas)
|
|
381
462
|
- `createCoordinatorDeps` unit tests -- extraction in B3 improved testability; cover `spawnSession`, `awaitSessions`, `getAgentResult` at minimum
|
|
382
463
|
- ~~Wire `AllocatedSession.triggerSource` to the `run_started` event for session attribution~~ -- **done**, PR #899 (Apr 30, 2026)
|
|
464
|
+
- ~~`SessionStateWriter` capability interfaces~~ -- **done** as part of PR #925 (`SessionScope` now owns all mutation callbacks)
|
|
465
|
+
- ~~Architecture test: forbid `state.terminalSignal =` direct writes outside `setTerminalSignal()`~~ -- **done**, PR #925
|
|
383
466
|
|
|
384
467
|
---
|
|
385
468
|
|
|
@@ -444,6 +527,8 @@ Phase 3 (PRs #835, #837): `buildTurnEndSubscriber`, `buildAgentCallbacks`, `buil
|
|
|
444
527
|
|
|
445
528
|
**Total workflow-runner.ts reduction: ~4,955 → ~2,800 lines (44%).**
|
|
446
529
|
|
|
530
|
+
**FC/IS follow-on (PR #925, Apr 30 -- May 1, 2026):** `TerminalSignal` union, `SessionScope` capability boundary completion, early-exit unification through `finalizeSession`, architecture tests. See "Daemon architecture: remaining migrations" entry for full details.
|
|
531
|
+
|
|
447
532
|
**Follow-on:** `wr.refactoring` workflow (see backlog entry above). Remaining items in "Daemon architecture: remaining migrations" entry below.
|
|
448
533
|
|
|
449
534
|
---
|
|
@@ -1249,6 +1334,25 @@ This is already how mid-run resume works. The same mechanism extends naturally t
|
|
|
1249
1334
|
|
|
1250
1335
|
---
|
|
1251
1336
|
|
|
1337
|
+
### Task-scoped rules: step-level rule injection by task type (Apr 30, 2026)
|
|
1338
|
+
|
|
1339
|
+
**Status: idea** | Priority: medium
|
|
1340
|
+
|
|
1341
|
+
**Score: 10** | Cor:2 Cap:3 Eff:2 Lev:2 Con:2 | Blocked: no
|
|
1342
|
+
|
|
1343
|
+
Workspace rules today are injected globally -- every session gets the same rules regardless of what the session is doing. This means PR-opening rules, issue-creation rules, commit message rules, and merge rules are all visible to a discovery session that will never do any of those things. Worse, a PR-opening step in a coding workflow doesn't get the rules injected precisely when it needs them -- they're diluted in the full rules blob. There is no mechanism to say "inject these rules only when the agent is about to open a PR" or "inject these rules only when creating a GitHub issue."
|
|
1344
|
+
|
|
1345
|
+
The idea: a rule declaration mechanism (either in the workflow step definition or in a workspace rules file) that tags rules by task type. At step execution time, the engine injects only the rules tagged for that step's declared task type. Examples: a step with `taskType: 'git.open_pr'` automatically receives PR-opening rules; a step with `taskType: 'github.create_issue'` receives issue-creation rules. Rules not tagged for the current task type are not injected into that step's prompt. This is complementary to the phase-scoped rules preprocessing item -- phase scoping is coarse-grained (coding vs review), task scoping is fine-grained (which specific action within a step).
|
|
1346
|
+
|
|
1347
|
+
**Things to hash out:**
|
|
1348
|
+
- Where are task-scoped rules declared -- in the workflow step definition (`taskType` field), in a workspace rules file with tags, or both?
|
|
1349
|
+
- What is the taxonomy of task types -- is it an open string, a closed enum, or a hierarchical namespace (e.g. `git.*`, `github.*`, `jira.*`)?
|
|
1350
|
+
- Does this interact with the ephemeral per-turn injection idea? Task-scoped rules are a natural candidate for ephemeral injection -- visible when needed, not accumulated in history.
|
|
1351
|
+
- Should task-scoped rules override or augment the global rules? What is the precedence and load order?
|
|
1352
|
+
- Who authors the task-scoped rules -- the workflow author (in the workflow JSON) or the workspace operator (in a workspace rules file)? Both seem valid but have different ownership models.
|
|
1353
|
+
|
|
1354
|
+
---
|
|
1355
|
+
|
|
1252
1356
|
### Rules preprocessing: normalize workspace rules before injection
|
|
1253
1357
|
|
|
1254
1358
|
**Status: idea** | Priority: medium
|
|
@@ -2466,8 +2570,52 @@ A workflow that aggregates activity across git history, GitLab/GitHub MRs and re
|
|
|
2466
2570
|
|
|
2467
2571
|
---
|
|
2468
2572
|
|
|
2573
|
+
### Ephemeral per-turn context injection in the agent loop (Apr 30, 2026)
|
|
2574
|
+
|
|
2575
|
+
**Status: idea** | Priority: medium
|
|
2576
|
+
|
|
2577
|
+
**Score: 10** | Cor:1 Cap:3 Eff:2 Lev:2 Con:2 | Blocked: no
|
|
2578
|
+
|
|
2579
|
+
The agent loop injects content (rules, soul, workspace context) into the system prompt once at session start. This means rules and behavioral constraints consume tokens for the entire session history. For long-running sessions, this is wasteful: every LLM API call re-sends the full system prompt including rules that were injected 50 turns ago. The alternative -- injecting rules on every turn as a fresh user or system message -- keeps them current but pollutes the conversation history with repetitive injections that further inflate context. There is no mechanism to inject content that is "always fresh, never historical" -- present on every loop iteration but not accumulated in the turn-by-turn conversation log.
|
|
2580
|
+
|
|
2581
|
+
The desired behavior: certain content (rules, behavioral constraints, workspace context, soul principles) should be re-injected on every turn as an ephemeral "floating system message" that is visible to the LLM during inference but not stored in the conversation history. The LLM always sees it but it never grows the history.
|
|
2582
|
+
|
|
2583
|
+
**Things to hash out:**
|
|
2584
|
+
- Does the Anthropic API (or other LLM providers) support a distinct ephemeral/volatile content slot that is not part of the messages array? If not, what is the closest approximation?
|
|
2585
|
+
- Is this a system prompt update per turn, or a separate "ephemeral context" message type? The distinction affects how context windows are managed by the provider.
|
|
2586
|
+
- Should ephemeral content be declared in the workflow (as a `volatileContext` field) or injected by the daemon's buildSystemPrompt() at the infrastructure level?
|
|
2587
|
+
- Which content actually benefits from this -- rules/soul only, or also things like "current git status", "last test run output", workspace context that may change mid-session?
|
|
2588
|
+
- Does this interact with the WorkRail engine's `continue_workflow` step injection? Step prompts are already injected per turn via `steer()` -- is this just a generalization of that mechanism?
|
|
2589
|
+
|
|
2590
|
+
---
|
|
2591
|
+
|
|
2469
2592
|
## Platform Vision (longer-term)
|
|
2470
2593
|
|
|
2594
|
+
### Epic-mode: full autonomous delivery of a multi-task feature from discovery to merged PRs (Apr 30, 2026)
|
|
2595
|
+
|
|
2596
|
+
**Status: idea** | Priority: high
|
|
2597
|
+
|
|
2598
|
+
**Score: 10** | Cor:1 Cap:3 Eff:1 Lev:3 Con:1 | Blocked: yes (blocked by: living work context, coordinator pipeline operational end-to-end, spawn_agent depth + parallel worktree support)
|
|
2599
|
+
|
|
2600
|
+
Today WorkTrain handles one ticket at a time. An epic -- a feature that requires 5-10 interdependent changes across multiple files, modules, or services -- requires the operator to manually decompose it into tickets and dispatch each one separately. The decomposition, dependency ordering, and integration are all human work. This is the gap between "WorkTrain handles tickets" and "WorkTrain handles features."
|
|
2601
|
+
|
|
2602
|
+
The idea: a single operator action kicks off an end-to-end autonomous pipeline for an entire epic. A planning phase fully decomposes the epic into a dependency-ordered task graph. Each task is a concrete, independently-implementable unit of work. Dependent tasks wait for their predecessors to land. Independent tasks are dispatched simultaneously to parallel agents in separate worktrees. Each task produces a PR. PRs target each other in a chain (each PR's base branch is the previous task's feature branch, or a shared integration branch). A coordinator monitors progress, re-plans when a task produces unexpected output, and handles failures by re-dispatching or escalating. When all tasks are merged (in dependency order), the epic is done.
|
|
2603
|
+
|
|
2604
|
+
This is the feature that makes WorkTrain feel like it can take on real engineering work, not just isolated bug fixes and small features.
|
|
2605
|
+
|
|
2606
|
+
**Things to hash out:**
|
|
2607
|
+
- What is the planning artifact? The decomposition step needs to produce a typed task graph -- not just a list of tasks, but explicit dependency edges, estimated scope per task, and the integration strategy (shared branch, stacked PRs, merge train). What schema captures this in a way the coordinator can route on deterministically?
|
|
2608
|
+
- How are dependencies enforced? If task B depends on task A, does B's agent start only after A's PR is merged, or does it work against A's branch before merge? The latter is faster but requires the coordinator to handle A's branch being rebased or amended.
|
|
2609
|
+
- How does the coordinator handle a task whose output invalidates the plan? If task A's implementation reveals a constraint that makes task C unnecessary or changes its scope, the coordinator needs to re-plan. What signals task A to the coordinator, and what does re-planning look like? Does it spawn a new planning agent, or does the coordinator apply deterministic rules?
|
|
2610
|
+
- What is the integration strategy for parallel tasks that touch overlapping files? Two agents working in separate worktrees may produce conflicting changes. Is this detected at PR-open time (merge conflicts), at plan time (the planner tries to assign non-overlapping scopes), or both?
|
|
2611
|
+
- What is the failure model? If one task in a 10-task epic fails after 3 tasks have merged, what happens to the already-landed work? The coordinator can't un-merge. Does it escalate to the operator, attempt a compensating task, or leave the partial state as-is?
|
|
2612
|
+
- How does this interact with the living work context design? Each task agent needs context from the planning phase (what the epic is trying to accomplish, what other tasks are doing, what invariants the whole feature must satisfy). This is exactly the cross-session context problem but at epic scale -- the context store needs to accumulate across a task graph, not just a linear pipeline.
|
|
2613
|
+
- What is the operator experience? Does the operator see a dashboard of all tasks in flight, their dependencies, and their status? Can they pause the epic, re-scope a task, or cancel a branch of the task graph mid-execution?
|
|
2614
|
+
|
|
2615
|
+
**Why it's high leverage despite low confidence:** getting this right makes WorkTrain the tool for large-scale autonomous development. Every other item in the backlog improves WorkTrain's reliability or quality for one ticket. This item changes the unit of work from "ticket" to "feature."
|
|
2616
|
+
|
|
2617
|
+
---
|
|
2618
|
+
|
|
2471
2619
|
### Move backlog to a dedicated worktrain-meta repo with version control (Apr 30, 2026)
|
|
2472
2620
|
|
|
2473
2621
|
**Status: idea** | Priority: high
|
|
@@ -4074,3 +4222,55 @@ WorkTrain has no tooling to surface the state of worktrees and branches relative
|
|
|
4074
4222
|
|
|
4075
4223
|
---
|
|
4076
4224
|
|
|
4225
|
+
|
|
4226
|
+
## WorkRail usage report as a mercury-mobile team script (May 4, 2026)
|
|
4227
|
+
|
|
4228
|
+
**Goal:** Make the WorkRail usage report dead simple to run for any mercury-mobile engineer -- one command, zero config beyond a GitLab token.
|
|
4229
|
+
|
|
4230
|
+
### Distribution
|
|
4231
|
+
|
|
4232
|
+
- Lives in mercury-mobile's common-ground team directory (`src/teams/mercury/mercury-mobile/scripts/workrail-report.sh`)
|
|
4233
|
+
- Distributed to every mercury engineer's machine by common-ground via `make sync`
|
|
4234
|
+
- Runnable as `~/.cg/dist/scripts/workrail-report.sh` or wrapped as a skill/alias
|
|
4235
|
+
|
|
4236
|
+
### What it does
|
|
4237
|
+
|
|
4238
|
+
1. Reads `~/.cg/config.toml` for the engineer's team identity
|
|
4239
|
+
2. Reads `~/.cg/repo-list.cache` to resolve repo names to local paths
|
|
4240
|
+
3. Scans `~/.workrail/data/sessions/` for sessions in the report window -- this is the authoritative source of what repos WorkRail was used on
|
|
4241
|
+
4. Fetches GitLab MRs via API for each repo that had sessions
|
|
4242
|
+
5. Builds the HTML report and writes to `~/Downloads/workrail-report-YYYY-MM-DD.html`
|
|
4243
|
+
6. Auto-opens the report
|
|
4244
|
+
|
|
4245
|
+
### Configuration
|
|
4246
|
+
|
|
4247
|
+
- **Token:** checks `GITLAB_TOKEN` env var → `~/.cg/secrets` → prompts once and offers to save. Zero setup if engineer already has `GITLAB_TOKEN` set.
|
|
4248
|
+
- **Date range:** defaults to last 30 days rolling. Override via `WORKRAIL_REPORT_DAYS=60 ./workrail-report.sh` or `--days 90` flag.
|
|
4249
|
+
- **Nothing else** -- team, repos, and GitLab paths are all auto-detected.
|
|
4250
|
+
|
|
4251
|
+
### Report behavior
|
|
4252
|
+
|
|
4253
|
+
- Only shows repos where WorkRail sessions exist in the window -- absence is signal, not a bug
|
|
4254
|
+
- Repos worked in outside WorkRail simply don't appear (the report is a WorkRail usage report, not a total productivity report)
|
|
4255
|
+
- "WorkRail shipped" correlation tab disabled in distributed version -- too expensive to run automatically. Available as a separate manual step for advanced users.
|
|
4256
|
+
|
|
4257
|
+
### Error handling
|
|
4258
|
+
|
|
4259
|
+
- No WorkRail installed → clear message with install instructions
|
|
4260
|
+
- No sessions in window → "No WorkRail activity in the last 30 days" with suggestion to check date range
|
|
4261
|
+
- No GitLab token → prompt with instructions for creating one
|
|
4262
|
+
- Repo not cloned locally → skip with note (LOC stats require local clone, rest of report works without it)
|
|
4263
|
+
|
|
4264
|
+
### Non-goals
|
|
4265
|
+
|
|
4266
|
+
- Not a team-level aggregated report (that's a future feature once `triggerSource` attribution is built)
|
|
4267
|
+
- Not a real-time dashboard
|
|
4268
|
+
- Not responsible for repos where WorkRail wasn't used
|
|
4269
|
+
|
|
4270
|
+
### Depends on
|
|
4271
|
+
|
|
4272
|
+
- The shared report scripts (`01-collect-sessions.py`, `02-collect-commits.py`, `04-build-html.py`) being stable -- ship this only after those are solid
|
|
4273
|
+
- `triggerSource: 'daemon' | 'mcp'` attribution (backlog) for distinguishing autonomous vs manual sessions -- not blocking but would improve the report
|
|
4274
|
+
- Common-ground `make sync` distributing the script reliably
|
|
4275
|
+
|
|
4276
|
+
**Priority:** Medium. The shared scripts work and have been tested. Main remaining work is the shell wrapper, token storage, and integration with common-ground's team config.
|
package/package.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "wr.routine-tension-driven-design",
|
|
3
3
|
"name": "Tension-Driven Design Generation",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"metricsProfile": "none",
|
|
6
|
-
"
|
|
6
|
+
"features": [
|
|
7
|
+
"wr.features.capabilities",
|
|
8
|
+
"wr.features.subagent_guidance"
|
|
9
|
+
],
|
|
10
|
+
"description": "Generates design candidates grounded in real tensions. Supports standalone and parallel-executor modes. In executor mode, anchors to an assigned focus angle from the goal string and ranks candidates without recommending a winner -- the calling agent owns synthesis and selection.",
|
|
7
11
|
"clarificationPrompts": [
|
|
8
|
-
"What problem should this design solve?",
|
|
12
|
+
"What problem should this design solve? (When spawned as an executor, the full fact packet and assigned focus angle should be in the goal string.)",
|
|
9
13
|
"What acceptance criteria, invariants, and constraints must it respect?",
|
|
10
|
-
"
|
|
11
|
-
"What artifact name should I produce?"
|
|
14
|
+
"What artifact name should I produce? (Default: design-candidates.md)"
|
|
12
15
|
],
|
|
13
16
|
"preconditions": [
|
|
14
|
-
"Problem statement is available",
|
|
15
|
-
"Acceptance criteria and non-goals are available",
|
|
17
|
+
"Problem statement is available -- either in the goal string (executor mode) or as context the agent can discover",
|
|
16
18
|
"Relevant files, patterns, or codebase references are available",
|
|
17
19
|
"Agent has read access to the codebase"
|
|
18
20
|
],
|
|
@@ -22,41 +24,50 @@
|
|
|
22
24
|
"PHILOSOPHY: the dev's coding philosophy is a design constraint, not an afterthought review lens. Discover it and use it.",
|
|
23
25
|
"SIMPLICITY BIAS: always consider whether the problem even needs an architectural solution. The simplest change that works is a valid candidate.",
|
|
24
26
|
"REPO PATTERNS: study how the codebase already solves similar problems. The best design often adapts an existing pattern.",
|
|
25
|
-
"HONESTY: for each candidate, state what you gain, what you give up, and how it fails. Optimize for useful comparison, not persuasion."
|
|
27
|
+
"HONESTY: for each candidate, state what you gain, what you give up, and how it fails. Optimize for useful comparison, not persuasion.",
|
|
28
|
+
"EXECUTOR MODE: if goal contains 'FOCUS ANGLE:', you are a parallel executor. Generate candidates anchored to that angle only. Step 4 ranks, does not recommend. Main agent owns synthesis and selection.",
|
|
29
|
+
"OUTPUT FILE: use the filename from 'OUTPUT FILE:' in your goal string, defaulting to design-candidates.md."
|
|
26
30
|
],
|
|
27
31
|
"steps": [
|
|
32
|
+
{
|
|
33
|
+
"id": "step-anchor-and-orient",
|
|
34
|
+
"title": "Step 0: Anchor to Assigned Context and Focus Angle",
|
|
35
|
+
"prompt": "Before doing any research or generation, read your goal string carefully and extract your operating context.\n\nFrom the goal string, extract and record:\n- **FOCUS ANGLE** (marked 'FOCUS ANGLE:' in the goal): your assigned generation angle. If present, ALL candidates must be anchored to this. You are in executor mode.\n- **PROBLEM** (marked 'PROBLEM:' or 'REFRAMED PROBLEM:'): what you are solving\n- **TENSIONS** (marked 'TENSIONS:'): core tensions the main agent already identified -- use these, do not re-investigate\n- **DECISION CRITERIA** (marked 'CRITERIA:'): what the final direction must satisfy\n- **IDEAL END STATE** (marked 'IDEAL END STATE:'): what the best achievable outcome looks like\n- **RISKIEST ASSUMPTION** (marked 'RISKIEST ASSUMPTION:'): the assumption most likely to invalidate the design\n- **PHILOSOPHY SOURCES** (marked 'PHILOSOPHY:'): pointers to rules or repo files encoding the dev's philosophy\n- **OUTPUT FILE** (marked 'OUTPUT FILE:'): the filename to produce (default: design-candidates.md)\n\nIf your goal contains a FOCUS ANGLE:\n- State your angle explicitly at the top of your notes\n- Confirm what it means for generation: which tensions it asks you to prioritize, which assumptions it asks you to stress-test\n- You will NOT recommend a winner in step 4 -- you will rank. Selection belongs to the main agent.\n\nIf your goal contains no FOCUS ANGLE (standalone execution):\n- Note that you are running standalone\n- You will discover missing context in subsequent steps\n\nWorking notes:\n- Assigned focus angle (or 'standalone')\n- All fact packet fields extracted from goal\n- What this angle means for generation\n- Output filename\n- Executor vs standalone confirmation",
|
|
36
|
+
"agentRole": "You are anchoring to your assigned role before doing any work. Read the goal string carefully. Do not skip this step.",
|
|
37
|
+
"requireConfirmation": false
|
|
38
|
+
},
|
|
28
39
|
{
|
|
29
40
|
"id": "step-discover-philosophy",
|
|
30
41
|
"title": "Step 1: Discover the Dev's Philosophy",
|
|
31
|
-
"prompt": "Discover the dev's coding philosophy and preferences before designing anything.\n\
|
|
42
|
+
"prompt": "Discover the dev's coding philosophy and preferences before designing anything.\n\nIf PHILOSOPHY SOURCES were provided in step 0, go read those sources directly (they are file paths or Memory entry names).\n\nIf no philosophy sources were provided, discover from scratch:\n1. Memory MCP (if available): call `mcp_memory_conventions`, `mcp_memory_prefer`, `mcp_memory_recall` to retrieve learned preferences\n2. Active session rules / CLAUDE.md / AGENTS.md: read any rules or philosophy documents in context\n3. Repo patterns: infer preferences from how the codebase works -- error handling, mutability, test style, architecture\n\nNote any philosophy conflicts (stated rules vs actual repo patterns).\n\nWorking notes:\n- Philosophy sources consulted\n- Key principles discovered\n- Conflicts between stated and practiced philosophy\n- Which principles are likely to constrain this design",
|
|
32
43
|
"agentRole": "You are discovering what the dev actually cares about before designing solutions.",
|
|
33
44
|
"requireConfirmation": false
|
|
34
45
|
},
|
|
35
46
|
{
|
|
36
47
|
"id": "step-understand-deeply",
|
|
37
48
|
"title": "Step 2: Understand the Problem Deeply",
|
|
38
|
-
"prompt": "Understand the problem before proposing anything.\n\
|
|
49
|
+
"prompt": "Understand the problem before proposing anything.\n\nIf TENSIONS and a REFRAMED PROBLEM were extracted in step 0, use them as your starting point -- do not re-investigate what the main agent already resolved. Build on that foundation and add what the main agent may have missed from your assigned angle's perspective.\n\nReason through:\n- What are the core tensions in this problem?\n- How does the codebase already solve similar problems? Study the most relevant existing patterns -- analyze the architectural decisions and constraints they protect, not just list files.\n- Where does the problem most likely live? Is the requested location the real seam, or just where the symptom appears?\n- What nearby callers, consumers, sibling paths, or contracts must remain consistent if that boundary changes?\n- What is the simplest naive solution? Why is it insufficient? (If it IS sufficient, note that -- it may be the best candidate.)\n- What makes this problem hard? What would a junior developer miss?\n- Which of the dev's philosophy principles are under pressure from this problem's constraints?\n- If in executor mode: what does the problem look like specifically from your assigned angle? What tensions does your angle ask you to prioritize?\n\nWorking notes:\n- Core tensions (2-4 real tradeoffs, not generic labels)\n- Existing patterns analysis (decisions, invariants they protect)\n- Likely seam / plausible boundaries\n- Nearby impact surface that must stay consistent\n- Naive solution and why it's insufficient (or sufficient)\n- What makes this hard\n- Philosophy principles under pressure\n- How your assigned angle (if in executor mode) shapes your view of the problem",
|
|
39
50
|
"agentRole": "You are reasoning deeply about the problem space before generating any solutions.",
|
|
40
51
|
"requireConfirmation": false
|
|
41
52
|
},
|
|
42
53
|
{
|
|
43
54
|
"id": "step-generate-candidates",
|
|
44
55
|
"title": "Step 3: Generate Candidates from Tensions",
|
|
45
|
-
"prompt": "Generate design candidates that resolve the identified tensions differently.\n\
|
|
56
|
+
"prompt": "Generate design candidates that resolve the identified tensions differently.\n\nIf in executor mode (FOCUS ANGLE was set in step 0):\n- All candidates must be anchored to your assigned angle. Do not generate generic candidates that ignore it.\n- You are NOT required to include the simplest possible change or the standard repo-pattern candidate unless they genuinely arise from your angle. Those are covered by other executors or by the main agent's synthesis.\n- Generate 2-3 candidates that each explore your angle from a different sub-direction -- vary the scope, the boundary, or the tradeoff accepted, but keep all of them anchored to the angle.\n- One candidate should be the most ambitious expression of your angle. One should be the most constrained. Others fill the space between.\n\nIf running standalone:\n- MANDATORY candidates:\n 1. The simplest possible change that satisfies acceptance criteria. If the problem doesn't need an architectural solution, say so.\n 2. Follow the existing repo pattern -- adapt what the codebase already does for similar problems. Don't invent when you can adapt.\n- Additional candidates (1-2 more): each must resolve the identified tensions DIFFERENTLY, not just vary surface details.\n\nFor each candidate, produce:\n- One-sentence summary of the approach\n- Which tensions it resolves and which it accepts\n- Boundary solved at, and why that boundary is the best fit\n- The specific failure mode you'd watch for\n- How it relates to existing repo patterns (follows / adapts / departs)\n- What you gain and what you give up\n- Impact surface beyond the immediate task\n- Scope judgment: too narrow / best-fit / too broad, with concrete evidence\n- Which philosophy principles it honors and which it conflicts with (by name)\n\nRules:\n- Candidates must be genuinely different in shape, not just wording\n- If all candidates converge on the same approach, note it honestly rather than manufacturing fake diversity\n- Broader scope requires concrete evidence\n- Cite specific files or patterns when they materially shape a candidate\n- Specify each candidate at the level of concrete shape, not concept labels: 'typed store' is not a specification; 'append-only per-run JSON file at a deterministic path, written atomically via temp-rename, read by coordinator before each spawn' is",
|
|
46
57
|
"agentRole": "You are generating genuinely diverse design candidates grounded in real tensions.",
|
|
47
58
|
"requireConfirmation": false
|
|
48
59
|
},
|
|
49
60
|
{
|
|
50
61
|
"id": "step-compare-and-recommend",
|
|
51
|
-
"title": "Step 4: Compare
|
|
52
|
-
"prompt": "Compare candidates through tradeoff analysis, not checklists.\n\
|
|
53
|
-
"agentRole": "You are
|
|
62
|
+
"title": "Step 4: Compare Candidates",
|
|
63
|
+
"prompt": "Compare candidates through tradeoff analysis, not checklists.\n\nIf in executor mode (FOCUS ANGLE was set in step 0):\n- Do NOT select a winner or make a final recommendation. The main agent owns selection across the full cross-executor candidate set.\n- Rank your candidates by how well each serves your assigned angle. State which is the strongest expression of the angle, which is the most defensible fallback, and what tradeoff separates them.\n- For each candidate: the strongest argument for it from your angle, and the strongest argument against it that the main agent should weigh.\n- State what a candidate from a DIFFERENT angle would need to offer to beat your strongest candidate from this angle's perspective. This is the cross-angle boundary -- it helps the main agent understand where each angle's value runs out.\n\nIf running standalone:\n- Produce a clear recommendation with rationale tied back to tensions, scope judgment, repo patterns, and philosophy.\n- Self-critique: strongest argument against your pick, narrower option that might still work and why it lost, broader option that might be justified and what evidence would be required, assumption that if wrong would invalidate the design.\n\nWorking notes:\n- Ranking (executor) or recommendation (standalone)\n- Strongest argument for and against each candidate\n- Cross-angle boundary statement (executor mode only)\n- Pivot conditions",
|
|
64
|
+
"agentRole": "You are ranking or recommending honestly. In executor mode you are producing material for the main agent to synthesize -- not closing the decision.",
|
|
54
65
|
"requireConfirmation": false
|
|
55
66
|
},
|
|
56
67
|
{
|
|
57
68
|
"id": "step-deliver",
|
|
58
69
|
"title": "Step 5: Deliver the Design Candidates",
|
|
59
|
-
"prompt": "Create `
|
|
70
|
+
"prompt": "Create the output file. Use the filename from OUTPUT FILE in your goal string, defaulting to `design-candidates.md` if none was specified.\n\nRequired structure:\n- Assigned Focus Angle (executor mode) or 'Standalone' -- state this first so the main agent knows the lens\n- Problem Understanding (tensions, likely seam, what makes it hard)\n- Philosophy Constraints (which principles matter, any conflicts)\n- Impact Surface (what nearby paths, consumers, or contracts must stay consistent)\n- Candidates (each with: summary, tensions resolved/accepted, boundary solved at, why that boundary is the best fit, failure mode, repo-pattern relationship, gains/losses, scope judgment, philosophy fit)\n- Ranking (executor mode: ranked by angle fit, no winner declared) or Recommendation (standalone: winner, rationale, self-critique)\n- Cross-Angle Boundary (executor mode only): what a candidate from a different angle would need to offer to beat the strongest candidate from this angle\n- Open Questions for the Main Agent\n\nThe main agent will interrogate this output -- it is raw investigative material, not a final decision. Optimize for honest, useful analysis over polished presentation.",
|
|
60
71
|
"agentRole": "You are delivering design analysis for the main agent to interrogate and build on.",
|
|
61
72
|
"requireConfirmation": false
|
|
62
73
|
}
|