@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.
- package/dist/console/assets/{index-FtTaDku8.js → index-BZ6HkxGf.js} +1 -1
- package/dist/console/index.html +1 -1
- package/dist/manifest.json +3 -3
- package/docs/README.md +57 -0
- package/docs/adrs/001-hybrid-storage-backend.md +38 -0
- package/docs/adrs/002-four-layer-context-classification.md +38 -0
- package/docs/adrs/003-checkpoint-trigger-strategy.md +35 -0
- package/docs/adrs/004-opt-in-encryption-strategy.md +36 -0
- package/docs/adrs/005-agent-first-workflow-execution-tokens.md +105 -0
- package/docs/adrs/006-append-only-session-run-event-log.md +76 -0
- package/docs/adrs/007-resume-and-checkpoint-only-sessions.md +51 -0
- package/docs/adrs/008-blocked-nodes-architectural-upgrade.md +178 -0
- package/docs/adrs/009-bridge-mode-single-instance-mcp.md +195 -0
- package/docs/adrs/010-release-pipeline.md +89 -0
- package/docs/architecture/README.md +7 -0
- package/docs/architecture/refactor-audit.md +364 -0
- package/docs/authoring-v2.md +527 -0
- package/docs/authoring.md +873 -0
- package/docs/changelog-recent.md +201 -0
- package/docs/configuration.md +505 -0
- package/docs/ctc-mcp-proposal.md +518 -0
- package/docs/design/README.md +22 -0
- package/docs/design/agent-cascade-protocol.md +96 -0
- package/docs/design/autonomous-console-design-candidates.md +253 -0
- package/docs/design/autonomous-console-design-review.md +111 -0
- package/docs/design/autonomous-platform-mvp-discovery.md +525 -0
- package/docs/design/claude-code-source-deep-dive.md +713 -0
- package/docs/design/console-cyberpunk-ui-discovery.md +504 -0
- package/docs/design/console-execution-trace-candidates-final.md +160 -0
- package/docs/design/console-execution-trace-candidates.md +211 -0
- package/docs/design/console-execution-trace-design-candidates-v2.md +113 -0
- package/docs/design/console-execution-trace-design-review.md +74 -0
- package/docs/design/console-execution-trace-discovery.md +394 -0
- package/docs/design/console-execution-trace-final-review.md +77 -0
- package/docs/design/console-execution-trace-review.md +92 -0
- package/docs/design/console-performance-discovery.md +415 -0
- package/docs/design/console-ui-backlog.md +280 -0
- package/docs/design/daemon-architecture-discovery.md +853 -0
- package/docs/design/daemon-design-candidates.md +318 -0
- package/docs/design/daemon-design-review-findings.md +119 -0
- package/docs/design/daemon-engine-design-candidates.md +210 -0
- package/docs/design/daemon-engine-design-review.md +131 -0
- package/docs/design/daemon-execution-engine-discovery.md +280 -0
- package/docs/design/daemon-gap-analysis.md +554 -0
- package/docs/design/daemon-owns-console-plan.md +168 -0
- package/docs/design/daemon-owns-console-review.md +91 -0
- package/docs/design/daemon-owns-console.md +195 -0
- package/docs/design/data-model-erd.md +11 -0
- package/docs/design/design-candidates-consolidate-dev-staleness.md +98 -0
- package/docs/design/design-candidates-walk-cache-depth-limit.md +80 -0
- package/docs/design/design-review-consolidate-dev-staleness.md +54 -0
- package/docs/design/design-review-walk-cache-depth-limit.md +48 -0
- package/docs/design/implementation-plan-consolidate-dev-staleness.md +142 -0
- package/docs/design/implementation-plan-walk-cache-depth-limit.md +141 -0
- package/docs/design/layer3b-ghost-nodes-design-candidates.md +229 -0
- package/docs/design/layer3b-ghost-nodes-design-review.md +93 -0
- package/docs/design/layer3b-ghost-nodes-implementation-plan.md +219 -0
- package/docs/design/list-workflows-latency-fix-plan.md +128 -0
- package/docs/design/list-workflows-latency-fix-review.md +55 -0
- package/docs/design/list-workflows-latency-fix.md +109 -0
- package/docs/design/native-context-management-api.md +11 -0
- package/docs/design/performance-sweep-2026-04.md +96 -0
- package/docs/design/routines-guide.md +219 -0
- package/docs/design/sequence-diagrams.md +11 -0
- package/docs/design/subagent-design-principles.md +220 -0
- package/docs/design/temporal-patterns-design-candidates.md +312 -0
- package/docs/design/temporal-patterns-design-review-findings.md +163 -0
- package/docs/design/test-isolation-from-config-file.md +335 -0
- package/docs/design/v2-core-design-locks.md +2746 -0
- package/docs/design/v2-lock-registry.json +734 -0
- package/docs/design/workflow-authoring-v2.md +1044 -0
- package/docs/design/workflow-docs-spec.md +218 -0
- package/docs/design/workflow-extension-points.md +687 -0
- package/docs/design/workrail-auto-trigger-system.md +359 -0
- package/docs/design/workrail-config-file-discovery.md +513 -0
- package/docs/docker.md +110 -0
- package/docs/generated/v2-lock-closure-plan.md +26 -0
- package/docs/generated/v2-lock-coverage.json +797 -0
- package/docs/generated/v2-lock-coverage.md +177 -0
- package/docs/ideas/backlog.md +3927 -0
- package/docs/ideas/design-candidates-mcp-resilience.md +208 -0
- package/docs/ideas/design-review-findings-mcp-resilience.md +119 -0
- package/docs/ideas/implementation_plan.md +249 -0
- package/docs/ideas/third-party-workflow-setup-design-thinking.md +1948 -0
- package/docs/implementation/02-architecture.md +316 -0
- package/docs/implementation/04-testing-strategy.md +124 -0
- package/docs/implementation/09-simple-workflow-guide.md +835 -0
- package/docs/implementation/13-advanced-validation-guide.md +874 -0
- package/docs/implementation/README.md +21 -0
- package/docs/integrations/claude-code.md +300 -0
- package/docs/integrations/firebender.md +315 -0
- package/docs/migration/v0.1.0.md +147 -0
- package/docs/naming-conventions.md +45 -0
- package/docs/planning/README.md +104 -0
- package/docs/planning/github-ticketing-playbook.md +195 -0
- package/docs/plans/README.md +24 -0
- package/docs/plans/agent-managed-ticketing-design.md +605 -0
- package/docs/plans/agentic-orchestration-roadmap.md +112 -0
- package/docs/plans/assessment-gates-engine-handoff.md +536 -0
- package/docs/plans/content-coherence-and-references.md +151 -0
- package/docs/plans/library-extraction-plan.md +340 -0
- package/docs/plans/mr-review-workflow-redesign.md +1451 -0
- package/docs/plans/native-context-management-epic.md +11 -0
- package/docs/plans/perf-fixes-design-candidates.md +225 -0
- package/docs/plans/perf-fixes-design-review-findings.md +61 -0
- package/docs/plans/perf-fixes-new-issues-candidates.md +264 -0
- package/docs/plans/perf-fixes-new-issues-review.md +110 -0
- package/docs/plans/prompt-fragments.md +53 -0
- package/docs/plans/ui-ux-workflow-design-candidates.md +120 -0
- package/docs/plans/ui-ux-workflow-discovery.md +100 -0
- package/docs/plans/ui-ux-workflow-review.md +48 -0
- package/docs/plans/v2-followup-enhancements.md +587 -0
- package/docs/plans/workflow-categories-candidates.md +105 -0
- package/docs/plans/workflow-categories-discovery.md +110 -0
- package/docs/plans/workflow-categories-review.md +51 -0
- package/docs/plans/workflow-discovery-model-candidates.md +94 -0
- package/docs/plans/workflow-discovery-model-discovery.md +74 -0
- package/docs/plans/workflow-discovery-model-review.md +48 -0
- package/docs/plans/workflow-source-setup-phase-1.md +245 -0
- package/docs/plans/workflow-source-setup-phase-2.md +361 -0
- package/docs/plans/workflow-staleness-detection-candidates.md +104 -0
- package/docs/plans/workflow-staleness-detection-review.md +58 -0
- package/docs/plans/workflow-staleness-detection.md +80 -0
- package/docs/plans/workflow-v2-design.md +69 -0
- package/docs/plans/workflow-v2-roadmap.md +74 -0
- package/docs/plans/workflow-validation-design.md +98 -0
- package/docs/plans/workflow-validation-roadmap.md +108 -0
- package/docs/plans/workrail-platform-vision.md +420 -0
- package/docs/reference/agent-context-cleaner-snippet.md +94 -0
- package/docs/reference/agent-context-guidance.md +140 -0
- package/docs/reference/context-optimization.md +284 -0
- package/docs/reference/example-workflow-repository-template/.github/workflows/validate.yml +125 -0
- package/docs/reference/example-workflow-repository-template/README.md +268 -0
- package/docs/reference/example-workflow-repository-template/workflows/example-workflow.json +80 -0
- package/docs/reference/external-workflow-repositories.md +916 -0
- package/docs/reference/feature-flags-architecture.md +472 -0
- package/docs/reference/feature-flags.md +349 -0
- package/docs/reference/god-tier-workflow-validation.md +272 -0
- package/docs/reference/loop-optimization.md +209 -0
- package/docs/reference/loop-validation.md +176 -0
- package/docs/reference/loops.md +465 -0
- package/docs/reference/mcp-platform-constraints.md +59 -0
- package/docs/reference/recovery.md +88 -0
- package/docs/reference/releases.md +177 -0
- package/docs/reference/troubleshooting.md +105 -0
- package/docs/reference/workflow-execution-contract.md +998 -0
- package/docs/roadmap/README.md +22 -0
- package/docs/roadmap/legacy-planning-status.md +103 -0
- package/docs/roadmap/now-next-later.md +70 -0
- package/docs/roadmap/open-work-inventory.md +389 -0
- package/docs/tickets/README.md +39 -0
- package/docs/tickets/next-up.md +76 -0
- package/docs/workflow-management.md +317 -0
- package/docs/workflow-templates.md +423 -0
- package/docs/workflow-validation.md +184 -0
- package/docs/workflows.md +254 -0
- package/package.json +3 -1
- package/spec/authoring-spec.json +61 -16
- package/workflows/workflow-for-workflows.json +252 -93
- package/workflows/workflow-for-workflows.v2.json +188 -77
|
@@ -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.
|