@exaudeus/workrail 3.27.0 → 3.29.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.
Files changed (160) hide show
  1. package/dist/console/assets/{index-FtTaDku8.js → index-BZ6HkxGf.js} +1 -1
  2. package/dist/console/index.html +1 -1
  3. package/dist/manifest.json +3 -3
  4. package/docs/README.md +57 -0
  5. package/docs/adrs/001-hybrid-storage-backend.md +38 -0
  6. package/docs/adrs/002-four-layer-context-classification.md +38 -0
  7. package/docs/adrs/003-checkpoint-trigger-strategy.md +35 -0
  8. package/docs/adrs/004-opt-in-encryption-strategy.md +36 -0
  9. package/docs/adrs/005-agent-first-workflow-execution-tokens.md +105 -0
  10. package/docs/adrs/006-append-only-session-run-event-log.md +76 -0
  11. package/docs/adrs/007-resume-and-checkpoint-only-sessions.md +51 -0
  12. package/docs/adrs/008-blocked-nodes-architectural-upgrade.md +178 -0
  13. package/docs/adrs/009-bridge-mode-single-instance-mcp.md +195 -0
  14. package/docs/adrs/010-release-pipeline.md +89 -0
  15. package/docs/architecture/README.md +7 -0
  16. package/docs/architecture/refactor-audit.md +364 -0
  17. package/docs/authoring-v2.md +527 -0
  18. package/docs/authoring.md +873 -0
  19. package/docs/changelog-recent.md +201 -0
  20. package/docs/configuration.md +505 -0
  21. package/docs/ctc-mcp-proposal.md +518 -0
  22. package/docs/design/README.md +22 -0
  23. package/docs/design/agent-cascade-protocol.md +96 -0
  24. package/docs/design/autonomous-console-design-candidates.md +253 -0
  25. package/docs/design/autonomous-console-design-review.md +111 -0
  26. package/docs/design/autonomous-platform-mvp-discovery.md +525 -0
  27. package/docs/design/claude-code-source-deep-dive.md +713 -0
  28. package/docs/design/console-cyberpunk-ui-discovery.md +504 -0
  29. package/docs/design/console-execution-trace-candidates-final.md +160 -0
  30. package/docs/design/console-execution-trace-candidates.md +211 -0
  31. package/docs/design/console-execution-trace-design-candidates-v2.md +113 -0
  32. package/docs/design/console-execution-trace-design-review.md +74 -0
  33. package/docs/design/console-execution-trace-discovery.md +394 -0
  34. package/docs/design/console-execution-trace-final-review.md +77 -0
  35. package/docs/design/console-execution-trace-review.md +92 -0
  36. package/docs/design/console-performance-discovery.md +415 -0
  37. package/docs/design/console-ui-backlog.md +280 -0
  38. package/docs/design/daemon-architecture-discovery.md +853 -0
  39. package/docs/design/daemon-design-candidates.md +318 -0
  40. package/docs/design/daemon-design-review-findings.md +119 -0
  41. package/docs/design/daemon-engine-design-candidates.md +210 -0
  42. package/docs/design/daemon-engine-design-review.md +131 -0
  43. package/docs/design/daemon-execution-engine-discovery.md +280 -0
  44. package/docs/design/daemon-gap-analysis.md +554 -0
  45. package/docs/design/daemon-owns-console-plan.md +168 -0
  46. package/docs/design/daemon-owns-console-review.md +91 -0
  47. package/docs/design/daemon-owns-console.md +195 -0
  48. package/docs/design/data-model-erd.md +11 -0
  49. package/docs/design/design-candidates-consolidate-dev-staleness.md +98 -0
  50. package/docs/design/design-candidates-walk-cache-depth-limit.md +80 -0
  51. package/docs/design/design-review-consolidate-dev-staleness.md +54 -0
  52. package/docs/design/design-review-walk-cache-depth-limit.md +48 -0
  53. package/docs/design/implementation-plan-consolidate-dev-staleness.md +142 -0
  54. package/docs/design/implementation-plan-walk-cache-depth-limit.md +141 -0
  55. package/docs/design/layer3b-ghost-nodes-design-candidates.md +229 -0
  56. package/docs/design/layer3b-ghost-nodes-design-review.md +93 -0
  57. package/docs/design/layer3b-ghost-nodes-implementation-plan.md +219 -0
  58. package/docs/design/list-workflows-latency-fix-plan.md +128 -0
  59. package/docs/design/list-workflows-latency-fix-review.md +55 -0
  60. package/docs/design/list-workflows-latency-fix.md +109 -0
  61. package/docs/design/native-context-management-api.md +11 -0
  62. package/docs/design/performance-sweep-2026-04.md +96 -0
  63. package/docs/design/routines-guide.md +219 -0
  64. package/docs/design/sequence-diagrams.md +11 -0
  65. package/docs/design/subagent-design-principles.md +220 -0
  66. package/docs/design/temporal-patterns-design-candidates.md +312 -0
  67. package/docs/design/temporal-patterns-design-review-findings.md +163 -0
  68. package/docs/design/test-isolation-from-config-file.md +335 -0
  69. package/docs/design/v2-core-design-locks.md +2746 -0
  70. package/docs/design/v2-lock-registry.json +734 -0
  71. package/docs/design/workflow-authoring-v2.md +1044 -0
  72. package/docs/design/workflow-docs-spec.md +218 -0
  73. package/docs/design/workflow-extension-points.md +687 -0
  74. package/docs/design/workrail-auto-trigger-system.md +359 -0
  75. package/docs/design/workrail-config-file-discovery.md +513 -0
  76. package/docs/docker.md +110 -0
  77. package/docs/generated/v2-lock-closure-plan.md +26 -0
  78. package/docs/generated/v2-lock-coverage.json +797 -0
  79. package/docs/generated/v2-lock-coverage.md +177 -0
  80. package/docs/ideas/backlog.md +3927 -0
  81. package/docs/ideas/design-candidates-mcp-resilience.md +208 -0
  82. package/docs/ideas/design-review-findings-mcp-resilience.md +119 -0
  83. package/docs/ideas/implementation_plan.md +249 -0
  84. package/docs/ideas/third-party-workflow-setup-design-thinking.md +1948 -0
  85. package/docs/implementation/02-architecture.md +316 -0
  86. package/docs/implementation/04-testing-strategy.md +124 -0
  87. package/docs/implementation/09-simple-workflow-guide.md +835 -0
  88. package/docs/implementation/13-advanced-validation-guide.md +874 -0
  89. package/docs/implementation/README.md +21 -0
  90. package/docs/integrations/claude-code.md +300 -0
  91. package/docs/integrations/firebender.md +315 -0
  92. package/docs/migration/v0.1.0.md +147 -0
  93. package/docs/naming-conventions.md +45 -0
  94. package/docs/planning/README.md +104 -0
  95. package/docs/planning/github-ticketing-playbook.md +195 -0
  96. package/docs/plans/README.md +24 -0
  97. package/docs/plans/agent-managed-ticketing-design.md +605 -0
  98. package/docs/plans/agentic-orchestration-roadmap.md +112 -0
  99. package/docs/plans/assessment-gates-engine-handoff.md +536 -0
  100. package/docs/plans/content-coherence-and-references.md +151 -0
  101. package/docs/plans/library-extraction-plan.md +340 -0
  102. package/docs/plans/mr-review-workflow-redesign.md +1451 -0
  103. package/docs/plans/native-context-management-epic.md +11 -0
  104. package/docs/plans/perf-fixes-design-candidates.md +225 -0
  105. package/docs/plans/perf-fixes-design-review-findings.md +61 -0
  106. package/docs/plans/perf-fixes-new-issues-candidates.md +264 -0
  107. package/docs/plans/perf-fixes-new-issues-review.md +110 -0
  108. package/docs/plans/prompt-fragments.md +53 -0
  109. package/docs/plans/ui-ux-workflow-design-candidates.md +120 -0
  110. package/docs/plans/ui-ux-workflow-discovery.md +100 -0
  111. package/docs/plans/ui-ux-workflow-review.md +48 -0
  112. package/docs/plans/v2-followup-enhancements.md +587 -0
  113. package/docs/plans/workflow-categories-candidates.md +105 -0
  114. package/docs/plans/workflow-categories-discovery.md +110 -0
  115. package/docs/plans/workflow-categories-review.md +51 -0
  116. package/docs/plans/workflow-discovery-model-candidates.md +94 -0
  117. package/docs/plans/workflow-discovery-model-discovery.md +74 -0
  118. package/docs/plans/workflow-discovery-model-review.md +48 -0
  119. package/docs/plans/workflow-source-setup-phase-1.md +245 -0
  120. package/docs/plans/workflow-source-setup-phase-2.md +361 -0
  121. package/docs/plans/workflow-staleness-detection-candidates.md +104 -0
  122. package/docs/plans/workflow-staleness-detection-review.md +58 -0
  123. package/docs/plans/workflow-staleness-detection.md +80 -0
  124. package/docs/plans/workflow-v2-design.md +69 -0
  125. package/docs/plans/workflow-v2-roadmap.md +74 -0
  126. package/docs/plans/workflow-validation-design.md +98 -0
  127. package/docs/plans/workflow-validation-roadmap.md +108 -0
  128. package/docs/plans/workrail-platform-vision.md +420 -0
  129. package/docs/reference/agent-context-cleaner-snippet.md +94 -0
  130. package/docs/reference/agent-context-guidance.md +140 -0
  131. package/docs/reference/context-optimization.md +284 -0
  132. package/docs/reference/example-workflow-repository-template/.github/workflows/validate.yml +125 -0
  133. package/docs/reference/example-workflow-repository-template/README.md +268 -0
  134. package/docs/reference/example-workflow-repository-template/workflows/example-workflow.json +80 -0
  135. package/docs/reference/external-workflow-repositories.md +916 -0
  136. package/docs/reference/feature-flags-architecture.md +472 -0
  137. package/docs/reference/feature-flags.md +349 -0
  138. package/docs/reference/god-tier-workflow-validation.md +272 -0
  139. package/docs/reference/loop-optimization.md +209 -0
  140. package/docs/reference/loop-validation.md +176 -0
  141. package/docs/reference/loops.md +465 -0
  142. package/docs/reference/mcp-platform-constraints.md +59 -0
  143. package/docs/reference/recovery.md +88 -0
  144. package/docs/reference/releases.md +177 -0
  145. package/docs/reference/troubleshooting.md +105 -0
  146. package/docs/reference/workflow-execution-contract.md +998 -0
  147. package/docs/roadmap/README.md +22 -0
  148. package/docs/roadmap/legacy-planning-status.md +103 -0
  149. package/docs/roadmap/now-next-later.md +70 -0
  150. package/docs/roadmap/open-work-inventory.md +389 -0
  151. package/docs/tickets/README.md +39 -0
  152. package/docs/tickets/next-up.md +76 -0
  153. package/docs/workflow-management.md +317 -0
  154. package/docs/workflow-templates.md +423 -0
  155. package/docs/workflow-validation.md +184 -0
  156. package/docs/workflows.md +254 -0
  157. package/package.json +3 -1
  158. package/spec/authoring-spec.json +61 -16
  159. package/workflows/workflow-for-workflows.json +252 -93
  160. package/workflows/workflow-for-workflows.v2.json +188 -77
@@ -0,0 +1,340 @@
1
+ # WorkRail Library Extraction Plan
2
+
3
+ ## Goal
4
+
5
+ Expose WorkRail's v2 workflow engine as an in-process library callable without MCP, transport, or tool abstractions. The first consumer is etienne-clone (MR review bot), but the API should be generic enough for any system that embeds workflow execution.
6
+
7
+ ## Non-goals
8
+
9
+ - No workflow redesign
10
+ - No context injection / prompt templating
11
+ - No parallel steps
12
+ - No new workflow schema features
13
+ - No removal of the existing MCP surface (it stays, built on top of the same engine)
14
+
15
+ ## Current architecture
16
+
17
+ ```
18
+ MCP client (agent)
19
+ |
20
+ v
21
+ MCP JSON-RPC transport (stdio / HTTP)
22
+ |
23
+ v
24
+ Tool registry (tool-registry.ts) — routes tool calls
25
+ |
26
+ v
27
+ MCP handler layer (v2-execution/index.ts)
28
+ - handleV2StartWorkflow(input, ctx: ToolContext) → ToolResult
29
+ - handleV2ContinueWorkflow(input, ctx: ToolContext) → ToolResult
30
+ - handleV2CheckpointWorkflow(input, ctx: ToolContext) → ToolResult
31
+ - handleV2ResumeSession(input, ctx: ToolContext) → ToolResult
32
+ |
33
+ v
34
+ Execution functions (pure logic, returns ResultAsync)
35
+ - executeStartWorkflow(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
36
+ - executeContinueWorkflow(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
37
+ - executeCheckpoint(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
38
+ |
39
+ v
40
+ Engine internals (prompt-renderer, blocking-decision, durable-core, tokens, etc.)
41
+ ```
42
+
43
+ ### Key observation
44
+
45
+ The execution functions (`executeStartWorkflow`, etc.) are already decoupled from MCP. They take typed inputs and a `V2ToolContext`, return `ResultAsync`. The MCP handler layer is a thin adapter that:
46
+ 1. Calls `requireV2Context(ctx)` to narrow the type
47
+ 2. Calls the execution function
48
+ 3. Maps the result to `ToolResult` (success/error)
49
+
50
+ The library extraction targets the execution function layer, bypassing the MCP handler and tool registry entirely.
51
+
52
+ ## What a library consumer calls today (via MCP)
53
+
54
+ ```
55
+ bot → HTTP → MCP JSON-RPC → tool handler → executeStartWorkflow(input, V2ToolContext)
56
+ ```
57
+
58
+ ## What a library consumer would call
59
+
60
+ ```
61
+ bot → engine.startWorkflow(workflowId) → typed result
62
+ ```
63
+
64
+ No HTTP. No JSON-RPC. No tool routing. No ToolResult wrapping.
65
+
66
+ ## Integration points verified
67
+
68
+ ### Inputs to execution functions
69
+
70
+ | Function | Input type | Fields |
71
+ |----------|-----------|--------|
72
+ | `executeStartWorkflow` | `V2StartWorkflowInput` | `workflowId: string`, `workspacePath?: string` |
73
+ | `executeContinueWorkflow` | `V2ContinueWorkflowInput` | `stateToken`, `ackToken?`, `intent`, `context?`, `output?` |
74
+ | `handleV2CheckpointWorkflow` | `V2CheckpointWorkflowInput` | `checkpointToken: string` |
75
+ | `handleV2ResumeSession` | `V2ResumeSessionInput` | `query?`, `gitBranch?`, `gitHeadSha?`, `workspacePath?` |
76
+
77
+ ### Dependencies (V2ToolContext)
78
+
79
+ `V2ToolContext` = `ToolContext` narrowed to guarantee `v2: V2Dependencies` is non-null.
80
+
81
+ **ToolContext fields:**
82
+ - `workflowService: WorkflowService` — used by `executeStartWorkflow` to load workflows
83
+ - `featureFlags: IFeatureFlagProvider` — checked at boundary (not in execution functions)
84
+ - `sessionManager` / `httpServer` — not used by v2 execution functions
85
+ - `v2: V2Dependencies` — the core engine dependency bag
86
+
87
+ **V2Dependencies fields (all required for execution):**
88
+ - `gate: ExecutionSessionGateV2` — session locking
89
+ - `sessionStore` — append-only event log (read + write)
90
+ - `snapshotStore` — execution snapshots
91
+ - `pinnedStore` — content-addressed workflow snapshots
92
+ - `sha256` / `crypto` — hashing
93
+ - `idFactory` — ID generation (session, run, node, event IDs)
94
+ - `tokenCodecPorts` — token encode/decode/sign/verify (grouped: keyring, hmac, base64url, base32, bech32m)
95
+ - `validationPipelineDeps` — Phase 1a validation (schema, structural, compilation, normalization)
96
+
97
+ **V2Dependencies fields (optional, used by resume/workspace):**
98
+ - `resolvedRootUris?` — MCP client roots (not needed for library)
99
+ - `workspaceResolver?` — workspace identity (git branch/SHA detection)
100
+ - `dataDir?` / `directoryListing?` — session enumeration for resume
101
+ - `sessionSummaryProvider?` — resume session ranking
102
+
103
+ ### DI construction graph
104
+
105
+ The V2Dependencies bag is constructed in `server.ts:createToolContext()` using the DI container. The container registers ~20 services across 3 levels:
106
+
107
+ **Level 1 (primitives, no deps):**
108
+ - `LocalDataDirV2(process.env)` — resolves `~/.workrail/v2`
109
+ - `NodeFileSystemV2()` — fs read/write
110
+ - `NodeSha256V2()`, `NodeCryptoV2()`, `NodeHmacSha256V2()` — crypto
111
+ - `NodeBase64UrlV2()`, `Base32AdapterV2()`, `Bech32mAdapterV2()` — encoding
112
+ - `NodeRandomEntropyV2()`, `NodeTimeClockV2()` — randomness, time
113
+ - `IdFactoryV2(entropy)` — ID minting
114
+
115
+ **Level 2 (stores, depend on Level 1):**
116
+ - `LocalKeyringV2(dataDir, fs, base64url, entropy)` — HMAC key management
117
+ - `LocalSessionEventLogStoreV2(dataDir, fs, sha256)` — session event log
118
+ - `LocalSnapshotStoreV2(dataDir, fs, crypto)` — execution snapshots
119
+ - `LocalPinnedWorkflowStoreV2(dataDir, fs)` — pinned workflow definitions
120
+ - `LocalSessionLockV2(dataDir, fs, clock)` — session locking
121
+
122
+ **Level 3 (orchestration):**
123
+ - `ExecutionSessionGateV2(lock, store)` — health-checked session access
124
+
125
+ **WorkflowService deps (separate from V2):**
126
+ - `WorkflowService` depends on storage (Primary), `ValidationEngine`, `WorkflowCompiler`, `WorkflowInterpreter`
127
+ - Storage is a 3-layer chain: `EnhancedMultiSourceWorkflowStorage` → `SchemaValidatingWorkflowStorage` → `CachingWorkflowStorage`
128
+
129
+ **Validation pipeline deps (subset used by start_workflow):**
130
+ - `schemaValidate` — AJV schema validator
131
+ - `structuralValidate` — `ValidationEngine.validateWorkflowStructureOnly()`
132
+ - `compiler` — `WorkflowCompiler` instance
133
+ - `normalizeToExecutable` — `normalizeV1WorkflowToPinnedSnapshot` function
134
+
135
+ ### Token codec construction
136
+
137
+ Tokens require a loaded keyring. The keyring is loaded once at startup (`keyringPort.loadOrCreate()`), then the `unsafeTokenCodecPorts()` factory groups all encoding ports:
138
+
139
+ ```typescript
140
+ const tokenCodecPorts = unsafeTokenCodecPorts({
141
+ keyring: keyringResult.value, // loaded HMAC keys
142
+ hmac, // NodeHmacSha256V2
143
+ base64url, // NodeBase64UrlV2
144
+ base32, // Base32AdapterV2
145
+ bech32m, // Bech32mAdapterV2
146
+ });
147
+ ```
148
+
149
+ ## agentRole enhancement
150
+
151
+ `agentRole` is defined on `WorkflowStepDefinition` and available in `prompt-renderer.ts` via `getStepById()`. Currently not returned in the response.
152
+
153
+ ### Changes needed
154
+
155
+ 1. `StepMetadata` in `prompt-renderer.ts` (line 319): add `readonly agentRole?: string`
156
+ 2. `renderPendingPrompt()` (line 451, 457, 481, 489): include `agentRole: step.agentRole` in return value
157
+ 3. `V2PendingStepSchema` in `output-schemas.ts` (line 102): add `agentRole: z.string().optional()`
158
+ 4. Response construction — 5 sites that build `pending` from `meta`:
159
+ - `start.ts:448` — `const pending = { stepId: meta.stepId, title: meta.title, prompt: meta.prompt }`
160
+ - `continue-rehydrate.ts:185` — same pattern
161
+ - `replay.ts:91, 213, 253` — same pattern (3 sites)
162
+ 5. Contract tests — update schema expectations for `agentRole` optional field
163
+
164
+ This is a ~15 line change across 4 files + contract tests. Note: `continue-advance.ts` delegates to `replay.ts`, so it doesn't need direct changes.
165
+
166
+ ## etienne-clone compatibility (verified)
167
+
168
+ etienne-clone already has a `WorkRailClient` interface in `src/clients/workrail.ts` that matches almost exactly what the library API should expose:
169
+
170
+ ```typescript
171
+ // etienne-clone's existing interface (clients/workrail.ts)
172
+ interface WorkRailClient {
173
+ readonly startWorkflow: (workflowId: string) => Promise<Result<WorkflowStepResponse, WorkRailError>>;
174
+ readonly continueWorkflow: (stateToken, ackToken, output) => Promise<Result<WorkflowStepResponse, WorkRailError>>;
175
+ readonly listWorkflows: () => Promise<Result<WorkflowListResponse, WorkRailError>>;
176
+ }
177
+ ```
178
+
179
+ The library API should match this shape so etienne-clone can swap `createWorkRailClient(config)` (HTTP) for `createWorkRailEngine(config)` (in-process) with minimal changes. The main difference: `WorkRailError` becomes `EngineError` (no `connection_failed`, `timeout`, `session_expired` — those are transport errors).
180
+
181
+ The `PendingStep` type in etienne-clone is `{ stepId, title, prompt }` — once `agentRole` ships, the bot can use it as the LLM's system prompt per step, rather than using a static system prompt for the whole review.
182
+
183
+ ## Library API design
184
+
185
+ ### Entry point
186
+
187
+ ```typescript
188
+ // src/engine/index.ts (new file, library entry point)
189
+ export { createWorkRailEngine } from './engine-factory.js';
190
+ export type { WorkRailEngine, EngineConfig } from './types.js';
191
+ ```
192
+
193
+ ### Config
194
+
195
+ ```typescript
196
+ interface EngineConfig {
197
+ // Where to store durable state (sessions, snapshots, keyring)
198
+ // Default: ~/.workrail/v2
199
+ readonly dataDir?: string;
200
+
201
+ // Workflow sources (bundled, filesystem, git, etc.)
202
+ // Default: bundled workflows only
203
+ readonly workflowSources?: readonly WorkflowSource[];
204
+ }
205
+ ```
206
+
207
+ ### Engine interface
208
+
209
+ ```typescript
210
+ interface WorkRailEngine {
211
+ // Start a workflow, get the first step
212
+ readonly startWorkflow: (workflowId: string) => Promise<EngineResult<StepResponse>>;
213
+
214
+ // Advance to next step (ackToken present) or rehydrate (ackToken absent)
215
+ readonly continueWorkflow: (
216
+ stateToken: string,
217
+ ackToken: string | null,
218
+ output?: { notesMarkdown?: string; artifacts?: unknown[] },
219
+ ) => Promise<EngineResult<StepResponse>>;
220
+
221
+ // Checkpoint without advancing
222
+ readonly checkpointWorkflow: (checkpointToken: string) => Promise<EngineResult<CheckpointResponse>>;
223
+
224
+ // List available workflows
225
+ readonly listWorkflows: () => Promise<EngineResult<WorkflowListResponse>>;
226
+ }
227
+ ```
228
+
229
+ ### Response types
230
+
231
+ ```typescript
232
+ // Branded token types — compile-time safety against token misuse
233
+ type StateToken = string & { readonly [StateTokenBrand]: never };
234
+ type AckToken = string & { readonly [AckTokenBrand]: never };
235
+ type CheckpointToken = string & { readonly [CheckpointTokenBrand]: never };
236
+
237
+ // Discriminated union: ok | blocked (illegal states unrepresentable)
238
+ type StepResponse = StepResponseOk | StepResponseBlocked;
239
+
240
+ interface StepResponseOk extends StepResponseBase {
241
+ readonly kind: 'ok';
242
+ readonly pending: PendingStep | null;
243
+ }
244
+
245
+ interface StepResponseBlocked extends StepResponseBase {
246
+ readonly kind: 'blocked';
247
+ readonly pending: PendingStep | null;
248
+ readonly blockers: readonly Blocker[];
249
+ readonly retryable: boolean;
250
+ readonly retryAckToken: AckToken | null;
251
+ }
252
+
253
+ // Typed error variants with domain-specific payloads (errors as data)
254
+ type EngineError =
255
+ | { readonly kind: 'workflow_not_found'; readonly workflowId: string }
256
+ | { readonly kind: 'workflow_has_no_steps'; readonly workflowId: string }
257
+ | { readonly kind: 'workflow_compile_failed'; readonly message: string }
258
+ | { readonly kind: 'validation_failed'; readonly message: string }
259
+ | { readonly kind: 'token_invalid'; readonly message: string }
260
+ | { readonly kind: 'token_signing_failed'; readonly message: string }
261
+ | { readonly kind: 'session_error'; readonly message: string }
262
+ | { readonly kind: 'storage_error'; readonly message: string }
263
+ | { readonly kind: 'prompt_render_failed'; readonly message: string }
264
+ | { readonly kind: 'precondition_failed'; readonly message: string }
265
+ | { readonly kind: 'internal_error'; readonly message: string };
266
+
267
+ type EngineResult<T> =
268
+ | { readonly ok: true; readonly value: T }
269
+ | { readonly ok: false; readonly error: EngineError };
270
+ ```
271
+
272
+ ### Factory implementation strategy — DECIDED
273
+
274
+ **Chosen: DI container with library runtime mode.** The services used by execution functions use `@singleton()` and `@inject()` decorators from `tsyringe`, which require `reflect-metadata` and the global container. Manual wiring is not viable without decoupling the services from decorators first.
275
+
276
+ The factory calls `initializeContainer({ runtimeMode: { kind: 'library' } })` which:
277
+ - Skips signal handlers and process lifecycle management
278
+ - Uses `ThrowingProcessTerminator` (same as test mode)
279
+ - Registers all storage, services, and v2 primitives identically to production
280
+ - Does NOT start HTTP server, MCP transport, or session tools
281
+
282
+ Long-term: DI-free service wrappers remain the ideal (no global state, no reflect-metadata) but require a larger refactor that shouldn't block library v1.
283
+
284
+ ## Implementation slices
285
+
286
+ ### Slice 1: agentRole in step responses (smallest, immediate value) — DONE
287
+
288
+ **Files changed:**
289
+ - `src/v2/durable-core/domain/prompt-renderer.ts` — added `agentRole` to `StepMetadata`, threaded through all 4 return sites
290
+ - `src/mcp/output-schemas.ts` — added `agentRole` to `V2PendingStepSchema`, extracted `toPendingStep()` helper
291
+ - `src/mcp/handlers/v2-execution/start.ts` — uses `toPendingStep(meta)` instead of inline construction
292
+ - `src/mcp/handlers/v2-execution/continue-rehydrate.ts` — same
293
+ - `src/mcp/handlers/v2-execution/replay.ts` — same (3 sites)
294
+ - Note: `continue-advance.ts` delegates to `replay.ts`, no direct changes needed
295
+
296
+ **Risk:** Low. Additive, backward-compatible (optional field). All 62 contract tests pass.
297
+
298
+ ### Slice 2+3: Engine types + factory — DONE
299
+
300
+ **New files:**
301
+ - `src/engine/types.ts` — branded tokens, discriminated union `StepResponse`, typed `EngineError` variants, `WorkRailEngine` interface with `close()`
302
+ - `src/engine/engine-factory.ts` — `createWorkRailEngine(config)` returns `EngineResult<WorkRailEngine>`, uses DI container in `library` runtime mode
303
+ - `src/engine/index.ts` — public exports
304
+
305
+ **Also changed:**
306
+ - `src/runtime/runtime-mode.ts` — added `library` variant
307
+ - `src/di/container.ts` — `library` mode uses no signal handlers, ThrowingProcessTerminator
308
+ - `src/mcp/handlers/v2-execution/index.ts` — exported `executeContinueWorkflow`
309
+ - `src/mcp/handlers/v2-checkpoint.ts` — exported `executeCheckpoint` and `CheckpointError`
310
+
311
+ ### Slice 4: Package export — DONE
312
+
313
+ - `package.json` — added `exports` field with `./engine` sub-path for `@exaudeus/workrail/engine`
314
+
315
+ ### Slice 5: Integration test — DONE
316
+
317
+ - `tests/integration/engine-library.test.ts` — 7 tests: factory init, list, start, rehydrate, advance, typed error (not found), typed error (invalid token)
318
+
319
+ ## What the factory does NOT include
320
+
321
+ - MCP transport or tool registry
322
+ - Feature flag checking (v2 is always on)
323
+ - Session tools (create/update/read session)
324
+ - HTTP server or dashboard
325
+ - Signal handling or process lifecycle
326
+ - `resolvedRootUris` (MCP-specific)
327
+ - `workspaceResolver` (can be added later if needed)
328
+
329
+ ## Testing strategy
330
+
331
+ 1. **Existing tests pass** — the agentRole change must not break any existing tests
332
+ 2. **Engine integration test** — start + advance + complete a workflow via library API
333
+ 3. **Output parity** — verify that `engine.startWorkflow(id)` returns equivalent data to `executeStartWorkflow(input, ctx)` (minus MCP wrapping)
334
+ 4. **Keyring lifecycle** — verify the engine creates/loads keyring correctly on first run and subsequent runs
335
+
336
+ ## Design decisions (resolved)
337
+
338
+ 1. **Engine has `close()` method** — required for resource lifecycle. Currently a no-op since keyring is in-memory and locks are per-operation, but the contract exists for future resource management.
339
+ 2. **Custom storage adapters** — deferred. The port interfaces exist but the factory doesn't expose them yet. Add when a consumer needs in-memory stores for testing.
340
+ 3. **`nextCall` excluded from library responses** — it's an MCP agent concept (`{ tool: 'continue_workflow', params: {...} }`). Library consumers call engine methods directly; they don't need tool call templates.