@exaudeus/workrail 3.28.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-C146q2kN.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 +3 -3
  160. package/workflows/workflow-for-workflows.v2.json +3 -3
@@ -0,0 +1,713 @@
1
+ # Claude Code Source Deep Dive: WorkRail Auto Integration Patterns
2
+
3
+ **Discovery path:** `landscape_first`
4
+ **Date:** 2026-04-14
5
+ **Source:** `https://github.com/Archie818/Claude-Code` (leaked Claude Code source)
6
+ **Files read:** `compact.ts`, `sessionMemoryCompact.ts`, `sessionMemoryUtils.ts`, `sessionMemory.ts`, `prompts.ts`, `hooks.ts`, `types/hooks.ts`, `hooksConfigManager.ts`, `hooksSettings.ts`, `coordinatorMode.ts`, `bridge/sessionRunner.ts`
7
+
8
+ ---
9
+
10
+ ## Context / Ask
11
+
12
+ Deep dive on the leaked Claude Code source to extract concrete integration patterns for WorkRail Auto:
13
+ 1. Full compaction system (three tiers) -- what survives each, how `executePreCompactHooks` works
14
+ 2. Hooks API -- PreToolUse/PostToolUse: how registered, what data received, how they block/modify
15
+ 3. Session memory -- `sessionMemoryUtils.ts`: what it is, how written/read
16
+ 4. Coordinator/subagent model -- how Claude Code coordinates between coordinator and workers
17
+ 5. `sessionRunner.ts` -- programmatic session initiation pattern for WorkRail Auto's daemon
18
+
19
+ ---
20
+
21
+ ## Path Recommendation
22
+
23
+ **`landscape_first`** -- the source is concrete and readable. The dominant need is understanding the existing system deeply before designing WorkRail's integration. No reframing needed; the problem is well-understood.
24
+
25
+ ---
26
+
27
+ ## Landscape Packet
28
+
29
+ ### 1. Compaction System: Three Tiers
30
+
31
+ `src/commands/compact/compact.ts` + `src/services/compact/sessionMemoryCompact.ts` + `src/services/compact/microCompact.ts`
32
+
33
+ Claude Code has three distinct compaction mechanisms, applied in strict priority order:
34
+
35
+ #### Tier 1: Session Memory Compaction (preferred, no custom instructions)
36
+
37
+ ```
38
+ trySessionMemoryCompaction(messages, agentId)
39
+ ```
40
+
41
+ - **What it is:** Replaces the full conversation with a structured summary derived from a durable markdown file (`~/.claude/projects/<project>/session-memory.md`).
42
+ - **How it works:**
43
+ 1. Checks feature gates: `tengu_session_memory` AND `tengu_sm_compact` must both be true. Override: `ENABLE_CLAUDE_CODE_SM_COMPACT=1`.
44
+ 2. Waits for any in-progress memory extraction (15s timeout).
45
+ 3. Reads `lastSummarizedMessageId` -- the message UUID up to which session memory is current.
46
+ 4. Calls `calculateMessagesToKeepIndex()` -- determines which recent messages to preserve verbatim (starting from lastSummarizedIndex + 1, expanding backwards to meet minimums):
47
+ - `minTokens: 10_000` (configurable via GrowthBook `tengu_sm_compact_config`)
48
+ - `minTextBlockMessages: 5`
49
+ - `maxTokens: 40_000` (hard cap)
50
+ 5. Builds `CompactionResult`: boundary marker + summary message (the session memory content formatted as a user message) + messages to keep.
51
+ 6. The summary message includes the full session memory content truncated to `MAX_TOTAL_SESSION_MEMORY_TOKENS = 12_000` tokens.
52
+ - **What survives:** The structured session memory doc + the last N messages (10k-40k tokens). Old conversation history is replaced by the memory doc.
53
+ - **Key invariant:** `adjustIndexToPreserveAPIInvariants()` ensures tool_use/tool_result pairs are never split. Thinking blocks sharing a `message.id` stay together.
54
+ - **If session memory is empty or gate is off:** Returns `null`, falls through to Tier 2.
55
+
56
+ #### Tier 2: Traditional Full Compaction (with optional Reactive path)
57
+
58
+ ```
59
+ compactConversation(messages, context, cacheSafeParams, ..., customInstructions)
60
+ ```
61
+
62
+ - **What it is:** Calls the Claude API to summarize the entire conversation into a single compact summary message.
63
+ - **Pre-step -- microcompaction:**
64
+ ```
65
+ microcompactMessages(messages, context)
66
+ ```
67
+ Strips tool results, large blobs, etc. to reduce tokens before the summarization API call.
68
+ - **Also runs `executePreCompactHooks` in the reactive path** (see Tier 2b below).
69
+ - **What survives:** A single LLM-generated summary message replaces all history. `setLastSummarizedMessageId(undefined)` is called -- resets the session memory boundary.
70
+ - **Reactive path (feature-gated):** `REACTIVE_COMPACT` feature -- runs pre-compact hooks concurrently with cache param building for performance.
71
+
72
+ #### Tier 3: Microcompact (emergency, standalone)
73
+
74
+ ```
75
+ microcompactMessages(messages, context)
76
+ ```
77
+
78
+ - Used as a pre-pass before Tier 2, and also usable standalone.
79
+ - Strips tool result content (keeps the tool call structure but removes large payloads), strips binary content, removes redundant whitespace.
80
+ - Token-based heuristics; does not call the Claude API.
81
+
82
+ #### The `executePreCompactHooks` Integration Point
83
+
84
+ ```typescript
85
+ // src/utils/hooks.ts:3961
86
+ export async function executePreCompactHooks(
87
+ compactData: { trigger: 'manual' | 'auto'; customInstructions: string | null },
88
+ signal?: AbortSignal,
89
+ timeoutMs: number = TOOL_HOOK_EXECUTION_TIMEOUT_MS,
90
+ ): Promise<{ newCustomInstructions?: string; userDisplayMessage?: string }>
91
+ ```
92
+
93
+ - Called in the **Tier 2 reactive path** (`compactViaReactive`), **concurrently** with `getCacheSharingParams`.
94
+ - Input: trigger type (`manual` | `auto`) + custom instructions.
95
+ - Hook scripts receive a JSON `PreCompactHookInput` on stdin.
96
+ - Hook return values:
97
+ - `stdout` with content → appended as **custom compaction instructions** (injected into the summarization prompt)
98
+ - Exit code 2 → **blocks compaction entirely**
99
+ - Other exit codes → stderr shown to user, compaction continues
100
+ - The hook outputs are merged with any user-provided custom instructions via `mergeHookInstructions()`.
101
+ - **NOT called in the Tier 1 (session memory) path** -- session memory compaction runs hooks via `processSessionStartHooks('compact')` instead.
102
+
103
+ **WorkRail Auto integration point:** A `PreCompact` hook script can inject WorkRail's current step state as custom instructions into the summarization prompt. This ensures the LLM-generated summary explicitly mentions the current workflow state.
104
+
105
+ ---
106
+
107
+ ### 2. Hooks API: PreToolUse/PostToolUse
108
+
109
+ #### Registration Format
110
+
111
+ Hooks are stored in Claude settings files (`~/.claude/settings.json`, `.claude/settings.json`, `.claude/settings.local.json`):
112
+
113
+ ```json
114
+ {
115
+ "hooks": {
116
+ "PreToolUse": [
117
+ {
118
+ "matcher": "Bash",
119
+ "hooks": [
120
+ { "type": "command", "command": "~/.workrail/hooks/pre-tool-use.sh" }
121
+ ]
122
+ }
123
+ ],
124
+ "PostToolUse": [
125
+ {
126
+ "matcher": "*",
127
+ "hooks": [
128
+ { "type": "command", "command": "~/.workrail/hooks/post-tool-use.sh" }
129
+ ]
130
+ }
131
+ ],
132
+ "PreCompact": [
133
+ {
134
+ "matcher": "auto",
135
+ "hooks": [
136
+ { "type": "command", "command": "~/.workrail/hooks/pre-compact.sh" }
137
+ ]
138
+ }
139
+ ]
140
+ }
141
+ }
142
+ ```
143
+
144
+ - **`matcher`** matches against `tool_name` for PreToolUse/PostToolUse, `trigger` for PreCompact.
145
+ - `"*"` or empty matcher = match all tools.
146
+ - Hook types: `command` (shell script), `prompt` (sends to model), `agent` (runs subagent), `http` (HTTP endpoint).
147
+
148
+ #### PreToolUse Hook Data
149
+
150
+ The hook script receives on stdin:
151
+
152
+ ```json
153
+ {
154
+ "session_id": "sess_abc123",
155
+ "tool_name": "Bash",
156
+ "tool_input": { "command": "git commit -m 'fix: something'" },
157
+ "tool_use_id": "toolu_01abc",
158
+ "hook_event_name": "PreToolUse"
159
+ }
160
+ ```
161
+
162
+ #### PreToolUse Hook Response Protocol
163
+
164
+ The hook script outputs JSON:
165
+
166
+ ```json
167
+ {
168
+ "continue": true,
169
+ "decision": "approve" | "block",
170
+ "reason": "Why this decision was made",
171
+ "hookSpecificOutput": {
172
+ "hookEventName": "PreToolUse",
173
+ "permissionDecision": "allow" | "deny" | "ask",
174
+ "permissionDecisionReason": "string",
175
+ "updatedInput": { "command": "git commit --no-verify -m 'fix: something'" },
176
+ "additionalContext": "Extra context injected into Claude's next turn"
177
+ }
178
+ }
179
+ ```
180
+
181
+ Key capabilities:
182
+
183
+ | Capability | How |
184
+ |---|---|
185
+ | **Block tool call** | `"decision": "block"` or `"hookSpecificOutput.permissionDecision": "deny"` |
186
+ | **Approve tool call** | `"decision": "approve"` or `"hookSpecificOutput.permissionDecision": "allow"` |
187
+ | **Modify tool input** | `"hookSpecificOutput.updatedInput": { ... }` -- replaces the tool input |
188
+ | **Inject context** | `"hookSpecificOutput.additionalContext": "string"` -- added to Claude's next message |
189
+ | **Stop conversation** | `"continue": false` + `"stopReason": "message"` |
190
+ | **Silent approve** | `exit 0`, empty stdout -- proceed without UI noise |
191
+
192
+ Exit code semantics (exit code overrides JSON when non-zero):
193
+ - `exit 0` -- proceed (stdout visible in transcript mode only)
194
+ - `exit 2` -- **blocking error**: stderr shown to model, tool call blocked
195
+ - Other non-zero -- stderr shown to user, tool proceeds
196
+
197
+ #### PostToolUse Hook Data
198
+
199
+ ```json
200
+ {
201
+ "session_id": "sess_abc123",
202
+ "tool_name": "Write",
203
+ "tool_input": { "file_path": "/src/foo.ts", "content": "..." },
204
+ "tool_response": { "success": true, "output": "..." },
205
+ "tool_use_id": "toolu_01abc",
206
+ "hook_event_name": "PostToolUse"
207
+ }
208
+ ```
209
+
210
+ PostToolUse response can inject `additionalContext` or update MCP tool output (`updatedMCPToolOutput`). Cannot block the tool (already ran).
211
+
212
+ #### PreCompact Hook Data
213
+
214
+ ```json
215
+ {
216
+ "session_id": "sess_abc123",
217
+ "hook_event_name": "PreCompact",
218
+ "trigger": "auto" | "manual",
219
+ "custom_instructions": null
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ### 3. Session Memory: The Durable Store
226
+
227
+ #### Architecture
228
+
229
+ Session memory is a **markdown file** at `~/.claude/projects/<sha256-of-cwd>/session-memory.md` that is maintained by a background forked subagent running after each assistant turn.
230
+
231
+ ```typescript
232
+ // src/services/SessionMemory/sessionMemoryUtils.ts
233
+ // Trigger thresholds:
234
+ DEFAULT_SESSION_MEMORY_CONFIG = {
235
+ minimumMessageTokensToInit: 10000, // First extraction
236
+ minimumTokensBetweenUpdate: 5000, // Subsequent extractions
237
+ toolCallsBetweenUpdates: 3, // Minimum tool calls between extractions
238
+ }
239
+ ```
240
+
241
+ Extraction logic (`shouldExtractMemory()`):
242
+ - Must have `>= 10k` context tokens before first extraction.
243
+ - Subsequent extractions: `>= 5k` token growth AND `>= 3` tool calls since last extraction.
244
+ - OR: token threshold met AND last assistant turn has no tool calls (natural break point).
245
+ - `sequential()` wrapper -- only one extraction runs at a time.
246
+
247
+ #### The Session Memory File Template
248
+
249
+ ```markdown
250
+ # Session Title
251
+ # Current State
252
+ # Task specification
253
+ # Files and Functions
254
+ # Workflow
255
+ # Errors & Corrections
256
+ # Codebase and System Documentation
257
+ # Learnings
258
+ # Key results
259
+ # Worklog
260
+ ```
261
+
262
+ Custom templates are supported at `~/.claude/session-memory/config/template.md`.
263
+
264
+ #### Extraction Process
265
+
266
+ When threshold is met, a **forked subagent** (`runForkedAgent`) is launched with:
267
+ 1. The full current conversation as context.
268
+ 2. A prompt instructing it to edit the session memory file using the `Edit` tool.
269
+ 3. The subagent calls `Edit` tool to update each section with info from the conversation.
270
+
271
+ The forked agent only has access to `Edit` on the memory file (`createMemoryFileCanUseTool(memoryPath)`).
272
+
273
+ #### The `lastSummarizedMessageId` Pointer
274
+
275
+ - Tracks which message was the most recent at the time of the last extraction.
276
+ - Used by Tier 1 compaction to determine the boundary: session memory is "current through this message."
277
+ - Messages after this ID are kept verbatim in the post-compaction result.
278
+ - Set to `undefined` after traditional (Tier 2) compaction -- the pointer is meaningless after a full summarization.
279
+
280
+ #### The `waitForSessionMemoryExtraction()` Barrier
281
+
282
+ - Before Tier 1 compaction runs, it waits up to 15 seconds for any in-progress extraction to finish.
283
+ - Uses a module-level `extractionStartedAt` timestamp.
284
+ - Extraction older than 60 seconds is considered stale and ignored.
285
+
286
+ ---
287
+
288
+ ### 4. Coordinator/Subagent Model
289
+
290
+ `src/coordinator/coordinatorMode.ts`
291
+
292
+ #### Mode Activation
293
+
294
+ ```typescript
295
+ // Enabled via env var
296
+ process.env.CLAUDE_CODE_COORDINATOR_MODE = '1'
297
+
298
+ function isCoordinatorMode(): boolean {
299
+ return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
300
+ }
301
+ ```
302
+
303
+ #### Coordinator Tools
304
+
305
+ In coordinator mode, the coordinator has access to:
306
+ - **`AgentTool`** -- spawn a new worker (full async subagent)
307
+ - **`SendMessageTool`** -- continue an existing worker by agent ID
308
+ - **`TaskStopTool`** -- kill a running worker
309
+
310
+ Workers do NOT have `AgentTool`, `SendMessageTool`, `TeamCreateTool`, `TeamDeleteTool`, `SendMessageTool`, `SyntheticOutputTool` -- only standard tools.
311
+
312
+ #### Worker Communication Protocol
313
+
314
+ Worker results arrive as user-role messages containing `<task-notification>` XML:
315
+
316
+ ```xml
317
+ <task-notification>
318
+ <task-id>agent-a1b2c3</task-id>
319
+ <status>completed|failed|killed</status>
320
+ <summary>Agent "investigate auth bug" completed</summary>
321
+ <result>Found null pointer in src/auth/validate.ts:42...</result>
322
+ <usage>
323
+ <total_tokens>45000</total_tokens>
324
+ <tool_uses>23</tool_uses>
325
+ <duration_ms>45000</duration_ms>
326
+ </usage>
327
+ </task-notification>
328
+ ```
329
+
330
+ The coordinator NEVER acknowledges workers directly -- it only addresses the user. Worker results are internal signals.
331
+
332
+ #### Scratchpad Directory
333
+
334
+ When `tengu_scratch` gate is enabled, workers get a shared scratchpad directory for durable cross-worker knowledge:
335
+ ```
336
+ Content: `Scratchpad directory: /tmp/scratch/sess_abc/`
337
+ Workers can read and write here without permission prompts.
338
+ ```
339
+
340
+ #### Session Mode Resume
341
+
342
+ When resuming a session, `matchSessionMode()` detects whether the previous session was coordinator mode and flips `CLAUDE_CODE_COORDINATOR_MODE` accordingly. This means coordinator mode is durable across session resume.
343
+
344
+ ---
345
+
346
+ ### 5. sessionRunner.ts: Programmatic Session Initiation
347
+
348
+ `src/bridge/sessionRunner.ts`
349
+
350
+ #### Architecture
351
+
352
+ `sessionRunner.ts` implements a `SessionSpawner` that spawns child Claude Code CLI processes and communicates via NDJSON over stdin/stdout. This is the bridge between the server-side SDK and the CLI-based agent.
353
+
354
+ #### Key Interface
355
+
356
+ ```typescript
357
+ type SessionSpawnOpts = {
358
+ sessionId: string
359
+ sdkUrl: string // Session Ingress URL
360
+ accessToken: string
361
+ useCcrV2?: boolean
362
+ workerEpoch?: number
363
+ onFirstUserMessage?: (text: string) => void
364
+ }
365
+
366
+ type SessionHandle = {
367
+ sessionId: string
368
+ done: Promise<SessionDoneStatus> // 'completed' | 'interrupted' | 'failed'
369
+ activities: SessionActivity[]
370
+ currentActivity: SessionActivity | null
371
+ kill(): void
372
+ forceKill(): void
373
+ writeStdin(data: string): void
374
+ updateAccessToken(token: string): void
375
+ }
376
+ ```
377
+
378
+ #### Spawn Arguments
379
+
380
+ The child process is spawned with:
381
+
382
+ ```
383
+ claude --print --sdk-url <URL> --session-id <ID>
384
+ --input-format stream-json
385
+ --output-format stream-json
386
+ --replay-user-messages
387
+ [--verbose] [--debug-file <path>] [--permission-mode <mode>]
388
+ ```
389
+
390
+ Environment:
391
+ - `CLAUDE_CODE_SESSION_ACCESS_TOKEN` -- per-session auth token
392
+ - `CLAUDE_CODE_ENVIRONMENT_KIND=bridge` -- signals bridge mode
393
+ - `CLAUDE_CODE_POST_FOR_SESSION_INGRESS_V2=1` -- transport flag
394
+ - `CLAUDE_CODE_FORCE_SANDBOX=1` -- sandbox mode (optional)
395
+
396
+ #### NDJSON Activity Detection
397
+
398
+ The runner parses stdout NDJSON line by line:
399
+ - `type: 'assistant'` with `content: [{type: 'tool_use', ...}]` → `tool_start` activity
400
+ - `type: 'assistant'` with `content: [{type: 'text', ...}]` → `text` activity
401
+ - `type: 'result'`, `subtype: 'success'` → session completed
402
+ - `type: 'control_request'`, `request.subtype: 'can_use_tool'` → forwarded to server for permission approval
403
+ - `type: 'user'` (not synthetic, not replay) → `onFirstUserMessage` callback
404
+
405
+ #### Token Refresh
406
+
407
+ Access tokens can be rotated mid-session:
408
+ ```typescript
409
+ handle.updateAccessToken(newToken)
410
+ // Sends via stdin:
411
+ // { "type": "update_environment_variables", "variables": { "CLAUDE_CODE_SESSION_ACCESS_TOKEN": newToken } }
412
+ ```
413
+
414
+ ---
415
+
416
+ ## Problem Frame Packet
417
+
418
+ **WorkRail Auto needs to:**
419
+
420
+ 1. **Survive compaction** -- WorkRail session state must persist through context window resets.
421
+ 2. **Observe tool calls** -- Record what the agent actually did (not just what it claimed) for evidence collection.
422
+ 3. **Gate tool execution** -- Block or modify tool calls based on workflow state (e.g., require `record_evidence` before proceeding).
423
+ 4. **Inject state into summaries** -- Ensure compaction summaries mention the current workflow step and continue token.
424
+ 5. **Spawn sessions programmatically** -- WorkRail daemon needs to initiate Claude Code sessions without a human in the loop.
425
+
426
+ **Primary tensions:**
427
+
428
+ - WorkRail doesn't want to be coupled to Claude Code internals -- but the integration points (hooks, session memory) are the stable public surface.
429
+ - Hook scripts are shell-based by default, but `http` type hooks exist -- WorkRail daemon can receive hook events over HTTP without shell scripting.
430
+
431
+ **Assumptions to validate:**
432
+
433
+ - Session memory template can be customized (verified -- `~/.claude/session-memory/config/template.md`)
434
+ - PreCompact hooks fire for auto-compact (verified -- `trigger: 'auto'` matcher supported)
435
+ - Hooks can inject context into Claude's next turn (verified -- `additionalContext` field)
436
+ - HTTP hooks exist (verified -- `type: 'http'` in HookCommand)
437
+
438
+ ---
439
+
440
+ ## Candidate Integration Patterns
441
+
442
+ ### Pattern A: PreCompact Hook (State Injection)
443
+
444
+ **Goal:** Ensure WorkRail's continue token and current step survive compaction.
445
+
446
+ **Implementation:**
447
+ ```bash
448
+ # ~/.workrail/hooks/pre-compact.sh
449
+ # Registered in .claude/settings.json under PreCompact[trigger=auto]
450
+ SESSION_DATA=$(workrail daemon-state read)
451
+ echo "WORKRAIL_STATE: $SESSION_DATA"
452
+ ```
453
+
454
+ The hook outputs WorkRail state as custom instructions. These become part of the compaction prompt, so the summary explicitly mentions the current step + token.
455
+
456
+ **Limits:** Only fires in Tier 2 (traditional compaction). Tier 1 (session memory compaction) uses `processSessionStartHooks('compact')` instead -- a SessionStart hook with `source=compact` fires instead. Both paths need coverage.
457
+
458
+ **Alternative:** Write WorkRail state directly into the session memory file as a new section (`# WorkRail State`) so it's part of the Tier 1 summary automatically. The `postSamplingHook` pattern allows this.
459
+
460
+ ### Pattern B: Session Memory Section Injection
461
+
462
+ **Goal:** Persist WorkRail step notes across all three compaction tiers via the session memory file.
463
+
464
+ **Implementation:**
465
+ 1. Add a `# WorkRail Workflow` section to the session memory template:
466
+ ```
467
+ ~/.claude/session-memory/config/template.md
468
+ ```
469
+ ```markdown
470
+ # WorkRail Workflow
471
+ _Current workflow ID, step ID, continue token, and step notes for recovery after context reset_
472
+ ```
473
+ 2. After each `continue_workflow` call, WorkRail daemon writes the current step state to the session memory file directly (not waiting for the extraction agent).
474
+ 3. On the next auto-extraction, the extraction agent sees the WorkRail section and preserves it.
475
+
476
+ **Why this is the right tier:** Session memory survives ALL three compaction tiers (Tier 1 is literally built on it; Tier 2 summarization receives session memory content as input). This is the most durable integration point.
477
+
478
+ **Concrete write:** WorkRail daemon uses the session memory path (`~/.claude/projects/<hash>/session-memory.md`) and writes directly to the `# WorkRail Workflow` section.
479
+
480
+ ### Pattern C: PreToolUse Hook (Evidence Collection)
481
+
482
+ **Goal:** Observe every tool call and record evidence for WorkRail's `requiredEvidence` gate.
483
+
484
+ **Implementation:**
485
+ ```bash
486
+ # ~/.workrail/hooks/pre-tool-use.sh
487
+ # Matcher: * (all tools)
488
+ INPUT=$(cat) # JSON on stdin
489
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name')
490
+ SESSION=$(echo "$INPUT" | jq -r '.session_id')
491
+
492
+ # Record the evidence
493
+ workrail record-evidence --session "$SESSION" --tool "$TOOL" --input "$INPUT"
494
+
495
+ # Exit 0 = silent approve
496
+ exit 0
497
+ ```
498
+
499
+ Or using HTTP hook type (more daemon-friendly):
500
+ ```json
501
+ {
502
+ "hooks": {
503
+ "PreToolUse": [
504
+ {
505
+ "matcher": "*",
506
+ "hooks": [
507
+ { "type": "http", "url": "http://localhost:3100/hooks/pre-tool-use" }
508
+ ]
509
+ }
510
+ ]
511
+ }
512
+ }
513
+ ```
514
+
515
+ WorkRail daemon's HTTP server receives the hook, records the tool call as evidence, and returns `{"continue": true}` (or `{"decision": "block", "reason": "..."}` to gate).
516
+
517
+ **For WorkRail's `requiredEvidence` gate:** The PreToolUse hook running before `continue_workflow` can verify that required tool calls happened. Or inverted: PostToolUse hook records each tool call → WorkRail's evidence store → `continue_workflow` checks evidence store before advancing.
518
+
519
+ ### Pattern D: sessionRunner Pattern (Daemon Session Initiation)
520
+
521
+ **Goal:** WorkRail daemon spawns and manages Claude Code sessions programmatically.
522
+
523
+ **What sessionRunner actually does:** It spawns a Claude Code CLI subprocess in bridge mode, communicating via NDJSON on stdin/stdout. This is the **pro.anthropic.com** cloud bridge pattern -- it requires a session access token from Anthropic's backend.
524
+
525
+ **What WorkRail Auto actually needs:** Direct Anthropic API calls (not the Claude Code CLI subprocess). The right reference is **pi-mono's `Agent` class** -- `@mariozechner/pi-agent-core` -- which calls the Anthropic API directly without spawning a subprocess.
526
+
527
+ **The sessionRunner pattern still teaches us:**
528
+ - Activity events (`tool_start`, `text`, `result`, `error`) are the right abstraction for live session monitoring.
529
+ - Token rotation via stdin is the right pattern for long-running daemon sessions.
530
+ - NDJSON over stdin/stdout is more reliable than HTTP for subprocess communication.
531
+ - `SessionDoneStatus = 'completed' | 'interrupted' | 'failed'` is the right terminal state model.
532
+
533
+ **WorkRail daemon equivalent:**
534
+ ```typescript
535
+ // WorkRail's daemon session (using pi-mono, not sessionRunner)
536
+ type DaemonSessionHandle = {
537
+ sessionId: string;
538
+ workflowRunId: string;
539
+ done: Promise<'completed' | 'interrupted' | 'failed'>;
540
+ abort(): void;
541
+ activities: ActivityEvent[];
542
+ }
543
+ ```
544
+
545
+ ---
546
+
547
+ ## Challenge Notes
548
+
549
+ ### Challenge: PreCompact vs. PostSampling Hooks for State Injection
550
+
551
+ PreCompact hooks only fire in Tier 2. Session memory compaction (Tier 1) skips them. WorkRail state written only via PreCompact is lost when Tier 1 runs.
552
+
553
+ **Resolution:** Inject WorkRail state via TWO mechanisms:
554
+ 1. Write directly to the `# WorkRail Workflow` section of session memory after each step (ensures Tier 1 has it).
555
+ 2. Register a PreCompact hook that re-states the current continue token as custom instructions (belt-and-suspenders for Tier 2).
556
+
557
+ WorkRail's own durable session store is the ground truth regardless -- but injecting into both channels maximizes the chance of context survival.
558
+
559
+ ### Challenge: HTTP Hooks vs. Shell Hooks
560
+
561
+ HTTP hooks don't get stdin data the same way shell hooks do -- they receive an HTTP POST with the hook input as a JSON body. WorkRail daemon needs to run an HTTP server to receive these. Shell hooks are simpler but require a shell script that calls WorkRail's CLI.
562
+
563
+ **Resolution for MVP:** Shell script that calls `workrail record-evidence --json "$(cat)"`. The daemon listens on a Unix socket. Post-MVP: HTTP hook type, WorkRail daemon runs a small HTTP server.
564
+
565
+ ### Challenge: Feature Gates Block Session Memory
566
+
567
+ `tengu_session_memory` and `tengu_sm_compact` GrowthBook gates must be enabled. External users have no control over these.
568
+
569
+ **Env var override exists:** `ENABLE_CLAUDE_CODE_SM_COMPACT=1` bypasses the gates.
570
+
571
+ **Resolution:** WorkRail daemon sets `ENABLE_CLAUDE_CODE_SM_COMPACT=1` when spawning sessions. In the long run, write WorkRail state directly to the session memory file -- this works regardless of whether SM compaction is enabled.
572
+
573
+ ---
574
+
575
+ ## Decision Log
576
+
577
+ ### Selected Direction: Session Memory File as Primary Durability Layer
578
+
579
+ **Why it won:**
580
+ - Session memory survives ALL three compaction tiers (it's the source for Tier 1, input to Tier 2 summarization, unaffected by Tier 3).
581
+ - Direct file writes don't depend on hooks firing or feature gates.
582
+ - The template is user-customizable.
583
+ - Writing to a local file is trivially simple for the daemon.
584
+
585
+ **Strongest alternative: PreCompact hook injection**
586
+ - Why it lost: Only covers Tier 2 compaction. Requires hook registration setup. Feature-gate dependency.
587
+ - When it wins: Belt-and-suspenders complement to session memory writing.
588
+
589
+ **Accepted tradeoffs:**
590
+ - Direct session memory writes could conflict with the extraction subagent (last-write-wins). Mitigation: use section-append pattern; don't overwrite other sections.
591
+ - Session memory path is per-session (hash of cwd). WorkRail daemon must know the correct path for each Claude Code session it manages.
592
+
593
+ ### HTTP Hooks for Evidence Collection
594
+
595
+ **Selected:** PostToolUse HTTP hook → WorkRail daemon HTTP server.
596
+
597
+ **Why:** Zero subprocess overhead, clean JSON, easy to observe/debug. The daemon already needs to run a server for the REST control plane.
598
+
599
+ **Implementation sketch:**
600
+ ```json
601
+ {
602
+ "hooks": {
603
+ "PostToolUse": [
604
+ {
605
+ "matcher": "*",
606
+ "hooks": [{ "type": "http", "url": "http://localhost:3456/hooks/post-tool-use" }]
607
+ }
608
+ ]
609
+ }
610
+ }
611
+ ```
612
+
613
+ WorkRail daemon handler:
614
+ ```typescript
615
+ app.post('/hooks/post-tool-use', (req, res) => {
616
+ const { tool_name, tool_input, tool_response, session_id } = req.body;
617
+ evidenceStore.record(session_id, { tool_name, tool_input, tool_response });
618
+ res.json({ continue: true });
619
+ });
620
+ ```
621
+
622
+ ---
623
+
624
+ ## Final Summary
625
+
626
+ ### Compaction System
627
+
628
+ Three tiers, strict priority:
629
+
630
+ 1. **Tier 1 (Session Memory Compaction)** -- replaces conversation with session memory markdown + recent messages (10k-40k tokens kept). Gates: `tengu_session_memory` AND `tengu_sm_compact` (override: `ENABLE_CLAUDE_CODE_SM_COMPACT=1`). Does NOT run PreCompact hooks.
631
+ 2. **Tier 2 (Traditional Compaction)** -- API call summarizes full history. Runs PreCompact hooks (reactive path only). Runs microcompact as pre-pass.
632
+ 3. **Tier 3 (Microcompact)** -- strips tool results, large blobs. Pre-pass for Tier 2.
633
+
634
+ WorkRail state should be injected at Tier 1 (write to session memory file) not Tier 2 (PreCompact hook) for maximum durability.
635
+
636
+ ### Hooks API
637
+
638
+ - Registered in `settings.json` under `hooks.{EventName}[{matcher, hooks:[]}]`.
639
+ - PreToolUse: receives `{session_id, tool_name, tool_input, tool_use_id}`. Can block (`decision: "block"`), approve, modify input (`updatedInput`), inject context (`additionalContext`).
640
+ - PostToolUse: receives same + `tool_response`. Can inject context, update MCP output. Cannot block.
641
+ - PreCompact: receives `{trigger: 'manual'|'auto', custom_instructions}`. stdout becomes compaction instructions. Exit 2 blocks compaction.
642
+ - HTTP hook type (`type: "http"`) sends JSON POST to WorkRail daemon's HTTP server. Clean integration path.
643
+ - Shell hook type (`type: "command"`) sends JSON on stdin. Must exit 0/2/other for semantic behavior.
644
+
645
+ ### Session Memory
646
+
647
+ - Markdown file: `~/.claude/projects/<sha256-cwd>/session-memory.md`.
648
+ - Template: 10 sections (Session Title, Current State, Task Spec, Files, Workflow, Errors, Docs, Learnings, Key Results, Worklog).
649
+ - Updated by background forked subagent after each turn (when thresholds met: `>=10k` context tokens to init, `>=5k` token growth + `>=3` tool calls between updates).
650
+ - `lastSummarizedMessageId` tracks the compaction boundary.
651
+ - `waitForSessionMemoryExtraction()` ensures compaction waits for in-flight extraction (15s timeout).
652
+ - Custom template: `~/.claude/session-memory/config/template.md`.
653
+
654
+ **WorkRail injection:** Write a `# WorkRail Workflow` section directly to the session memory file after each step advance. The extraction agent will preserve it in subsequent updates.
655
+
656
+ ### Coordinator/Subagent Model
657
+
658
+ - `CLAUDE_CODE_COORDINATOR_MODE=1` env var activates coordinator mode.
659
+ - Coordinator has `AgentTool` (spawn), `SendMessageTool` (continue), `TaskStopTool` (kill).
660
+ - Workers receive only standard tools (no coordinator tools).
661
+ - Worker results arrive as `<task-notification>` XML in user-role messages.
662
+ - Optional shared scratchpad dir (gate-dependent) for cross-worker durable state.
663
+ - Session mode is durable across resume (stored in session, restored via `matchSessionMode()`).
664
+
665
+ **WorkRail relevance:** The `AgentTool` dispatch + `<task-notification>` result collection pattern is the right subagent model for WorkRail's coordinator-spawning-subworkflow feature. WorkRail daemon's coordinator session holds the main workflow state; subworkflow sessions each run as workers dispatched via `AgentTool`.
666
+
667
+ ### sessionRunner Pattern
668
+
669
+ - **What it does:** Spawns Claude Code CLI subprocess (`--print --sdk-url --session-id --input-format stream-json`), reads NDJSON activity events (tool_start, text, result, error, control_request).
670
+ - **What WorkRail daemon needs instead:** Direct Anthropic API calls via pi-mono's `Agent` class, NOT CLI subprocess spawning.
671
+ - **Key patterns to adopt:**
672
+ - `SessionActivity[]` ring buffer (max 10) for live status display.
673
+ - `SessionDoneStatus: 'completed' | 'interrupted' | 'failed'` terminal state enum.
674
+ - Token rotation mid-session via structured message on stdin.
675
+ - Activity-based event stream as the observable side-channel.
676
+
677
+ ### Concrete WorkRail Auto Build Actions
678
+
679
+ 1. **Session memory integration (highest value, implement now):**
680
+ - Add `# WorkRail Workflow` section to session memory template.
681
+ - Daemon writes current step state to section after each `continue_workflow`.
682
+ - Path resolution: `~/.claude/projects/<sha256(cwd)>/session-memory.md`.
683
+
684
+ 2. **PostToolUse HTTP hook (evidence collection):**
685
+ - Register in `.claude/settings.json`: `PostToolUse` → `http` → `http://localhost:3456/hooks/post-tool-use`.
686
+ - WorkRail daemon handler records evidence per session.
687
+ - `continue_workflow` checks evidence store for `requiredEvidence` gate.
688
+
689
+ 3. **PreCompact belt-and-suspenders:**
690
+ - Register `PreCompact` shell hook that writes current continue token to stdout.
691
+ - If session memory fails, the continue token survives in the Tier 2 summary.
692
+
693
+ 4. **Coordinator mode for subworkflows:**
694
+ - Set `CLAUDE_CODE_COORDINATOR_MODE=1` for coordinator sessions.
695
+ - Subworkflow sessions are spawned as workers via `AgentTool`.
696
+ - Results collected via `<task-notification>` pattern.
697
+ - DO NOT use this for daemon-initiated sessions -- daemon uses pi-mono's `Agent` directly.
698
+
699
+ ### Confidence Band
700
+
701
+ **High confidence** on the compaction tier architecture, hook registration format, session memory file structure and path, coordinator mode activation, and hook JSON protocol -- all read directly from source.
702
+
703
+ **Medium confidence** on the end-to-end flow for Tier 1 compaction triggering (feature gates required, tested by env var override) and on the `processSessionStartHooks('compact')` path in Tier 1.
704
+
705
+ **Gap:** Did not read `src/services/compact/compact.ts` (the service, not the command) in full -- specifically the `buildPostCompactMessages` and `annotateBoundaryWithPreservedSegment` functions. These are internal to the compaction result assembly and likely don't affect WorkRail's integration points.
706
+
707
+ ### Next Actions
708
+
709
+ 1. Implement `# WorkRail Workflow` section in session memory template (1 file edit, no new code).
710
+ 2. Implement daemon HTTP hook endpoint (`POST /hooks/post-tool-use`) -- 30 lines.
711
+ 3. Write `setup-hooks.sh` script that configures `.claude/settings.json` with WorkRail hooks.
712
+ 4. Test with `ENABLE_CLAUDE_CODE_SM_COMPACT=1` env var to force Tier 1 compaction.
713
+ 5. Validate that the `# WorkRail Workflow` section survives a manual `/compact` command.