throughline 0.4.11 → 0.5.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/CHANGELOG.md +89 -0
- package/README.md +9 -2
- package/docs/RAG/INDEX.md +160 -0
- package/docs/RAG/_raw/01-hooks/hooks-reference-extract.md +250 -0
- package/docs/RAG/_raw/02-messages-api/messages-api-extract.md +126 -0
- package/docs/RAG/_raw/03-settings/sessions-extract.md +64 -0
- package/docs/RAG/_raw/04-skills/initialUserMessage-investigation.md +101 -0
- package/docs/THROUGHLINE_CLEAR_AUTO_HANDOFF_PLAN.md +7 -4
- package/docs/THROUGHLINE_TRANSCRIPT_INJECTION_PLAN.md +446 -0
- package/package.json +1 -1
- package/src/hook-entrypoints.test.mjs +288 -0
- package/src/prompt-submit.mjs +131 -4
- package/src/resume-context.mjs +79 -6
- package/src/resume-context.test.mjs +161 -9
- package/src/session-start.mjs +95 -13
- package/src/spike-transcript-writer.mjs +196 -0
- package/src/spike-transcript-writer.test.mjs +298 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Claude Code Sessions — Extract
|
|
2
|
+
|
|
3
|
+
Source: <https://code.claude.com/docs/en/sessions> (fetched 2026-05-24)
|
|
4
|
+
|
|
5
|
+
## Session storage
|
|
6
|
+
|
|
7
|
+
- JSONL at `~/.claude/projects/<project>/<session-id>.jsonl`
|
|
8
|
+
- `<project>` derived from working directory path
|
|
9
|
+
- Each line is a JSON object (message / tool use / metadata)
|
|
10
|
+
- Override storage location: `CLAUDE_CONFIG_DIR` env var
|
|
11
|
+
- Default retention: 30 days, configurable via `cleanupPeriodDays`
|
|
12
|
+
- Disable transcript writes: `CLAUDE_CODE_SKIP_PROMPT_HISTORY` (env), or `--no-session-persistence` (CLI flag)
|
|
13
|
+
|
|
14
|
+
## Resume / continue
|
|
15
|
+
|
|
16
|
+
| Command | Behavior |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `claude --continue` | Resumes most recent session in current directory |
|
|
19
|
+
| `claude --resume` | Opens session picker |
|
|
20
|
+
| `claude --resume <name>` | Resumes named session directly |
|
|
21
|
+
| `claude --from-pr <number>` | Resumes session linked to PR |
|
|
22
|
+
| `/resume` (inside session) | Switches to a different conversation |
|
|
23
|
+
|
|
24
|
+
## /clear behavior (KEY)
|
|
25
|
+
|
|
26
|
+
> `/clear`: start fresh with an empty context. **The previous conversation is saved and resumable**.
|
|
27
|
+
|
|
28
|
+
- /clear empties CC's in-memory context buffer
|
|
29
|
+
- Previous conversation remains in JSONL, retrievable via `--continue` / `--resume`
|
|
30
|
+
- This implies CC has BOTH an in-memory state AND the persisted JSONL — and after /clear, the in-memory state is reset but the file is preserved
|
|
31
|
+
|
|
32
|
+
## /compact behavior
|
|
33
|
+
|
|
34
|
+
> `/compact [instructions]`: replace history with a summary, optionally focused on what you specify
|
|
35
|
+
|
|
36
|
+
- Summarizes existing context in-place
|
|
37
|
+
- Optionally focused via instructions
|
|
38
|
+
- Triggers `PreCompact` / `PostCompact` hooks (mid-session events)
|
|
39
|
+
|
|
40
|
+
## /context
|
|
41
|
+
|
|
42
|
+
> `/context`: show what is currently consuming context
|
|
43
|
+
|
|
44
|
+
## Branch / fork
|
|
45
|
+
|
|
46
|
+
> `/branch [name]` or `--fork-session` with `--continue` / `--resume`:
|
|
47
|
+
> Creates a copy of the conversation so far and switches into it, leaving the original intact.
|
|
48
|
+
|
|
49
|
+
- Permission grants don't carry over to new branch
|
|
50
|
+
- Resuming the same session in two terminals interleaves messages into one transcript
|
|
51
|
+
|
|
52
|
+
## Naming
|
|
53
|
+
|
|
54
|
+
- `claude -n <name>` (at startup)
|
|
55
|
+
- `/rename <name>` (mid-session)
|
|
56
|
+
- `Ctrl+R` in session picker
|
|
57
|
+
- Auto-naming on plan accept
|
|
58
|
+
|
|
59
|
+
## Implications for Throughline
|
|
60
|
+
|
|
61
|
+
1. **/clear preserves JSONL**. CC's in-memory state is the canonical source for the new session's messages[], NOT the JSONL.
|
|
62
|
+
2. **/compact preserves session continuity** — same session_id, just summarized. This is the documented "memory preservation" path.
|
|
63
|
+
3. **`--continue` / `--resume` are the official "restore from JSONL" mechanisms** but they pull the WHOLE prior conversation (no Throughline-style L1/L2/L3 selective compression).
|
|
64
|
+
4. **There's no documented hook to influence in-memory state after /clear**, only context attachments (system reminders).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# `initialUserMessage` Field — Investigation Results
|
|
2
|
+
|
|
3
|
+
## Sources
|
|
4
|
+
|
|
5
|
+
- Official hooks reference: <https://code.claude.com/docs/en/hooks> (mentions field in SessionStart hookSpecificOutput shape)
|
|
6
|
+
- First-party hook-dev SKILL: <https://github.com/anthropics/claude-code/blob/main/plugins/plugin-dev/skills/hook-development/SKILL.md> (does NOT mention)
|
|
7
|
+
- Open-source CC implementation `Gitlawb/openclaude`:
|
|
8
|
+
- `src/utils/hooks.ts` — schema definition
|
|
9
|
+
- `src/utils/sessionStart.ts` — storage + retrieval mechanism
|
|
10
|
+
- `src/cli/print.ts` — consumer (the critical one)
|
|
11
|
+
- `src/main.tsx` — initialMessages array construction
|
|
12
|
+
|
|
13
|
+
## The schema (confirmed)
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// From openclaude src/utils/hooks.ts and src/types/hooks.ts
|
|
17
|
+
interface HookResult {
|
|
18
|
+
additionalContext?: string
|
|
19
|
+
initialUserMessage?: string
|
|
20
|
+
watchPaths?: string[]
|
|
21
|
+
updatedInput?: Record<string, unknown>
|
|
22
|
+
// ...
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// SessionStart hook output processing
|
|
26
|
+
case 'SessionStart':
|
|
27
|
+
result.additionalContext = json.hookSpecificOutput.additionalContext
|
|
28
|
+
result.initialUserMessage = json.hookSpecificOutput.initialUserMessage
|
|
29
|
+
if ('watchPaths' in json.hookSpecificOutput && json.hookSpecificOutput.watchPaths) {
|
|
30
|
+
result.watchPaths = json.hookSpecificOutput.watchPaths
|
|
31
|
+
}
|
|
32
|
+
break
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## The CRITICAL constraint (from openclaude source comment)
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// src/cli/print.ts:
|
|
39
|
+
// SessionStart hooks can emit initialUserMessage — the first user turn for
|
|
40
|
+
// headless orchestrator sessions where stdin is empty.
|
|
41
|
+
takeInitialUserMessage,
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**`initialUserMessage` is for HEADLESS MODE ONLY.** It's invoked when `claude -p` is launched and stdin doesn't provide a prompt — the hook can supply the "first user turn" as a substitute.
|
|
45
|
+
|
|
46
|
+
## Storage / consumption mechanism
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// src/utils/sessionStart.ts
|
|
50
|
+
// Set by processSessionStartHooks when a hook emits initialUserMessage;
|
|
51
|
+
// consumed once by takeInitialUserMessage. This side channel avoids changing
|
|
52
|
+
// the return type of processSessionStartHooks.
|
|
53
|
+
let pendingInitialUserMessage: string | undefined = undefined
|
|
54
|
+
|
|
55
|
+
if (hookResult.initialUserMessage) {
|
|
56
|
+
pendingInitialUserMessage = hookResult.initialUserMessage
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function takeInitialUserMessage(): string | undefined {
|
|
60
|
+
const v = pendingInitialUserMessage
|
|
61
|
+
pendingInitialUserMessage = undefined
|
|
62
|
+
return v
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// src/cli/print.ts
|
|
68
|
+
const hookInitialUserMessage = takeInitialUserMessage()
|
|
69
|
+
if (hookInitialUserMessage) {
|
|
70
|
+
structuredIO.prependUserMessage(hookInitialUserMessage)
|
|
71
|
+
}
|
|
72
|
+
// then runHeadlessStreaming() processes the queue
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## What this means for Throughline
|
|
76
|
+
|
|
77
|
+
`initialUserMessage` does NOT solve the `/clear` continuation problem because:
|
|
78
|
+
|
|
79
|
+
1. `/clear` is an INTERACTIVE mode operation
|
|
80
|
+
2. Interactive mode always has a user typing the next prompt — there's no "missing first user message" slot to fill
|
|
81
|
+
3. `initialUserMessage` is consumed by `print.ts` (print mode = `claude -p`), not by the interactive REPL
|
|
82
|
+
|
|
83
|
+
**Conclusion**: `initialUserMessage` is the wrong tool for our problem. It can't be used to make `/clear` continuation feel native.
|
|
84
|
+
|
|
85
|
+
## What IS the right tool? (As of this research)
|
|
86
|
+
|
|
87
|
+
For interactive `/clear`-then-prompt continuity, the available hook surfaces are:
|
|
88
|
+
|
|
89
|
+
- `additionalContext` → system reminder ("briefing" framing, what we have now)
|
|
90
|
+
- `stdout` (SessionStart/UserPromptSubmit/UserPromptExpansion) → system reminder (same as above)
|
|
91
|
+
- `PreCompact`/`PostCompact` hooks → fire on /compact, not /clear (different code path)
|
|
92
|
+
- `decision: block` for UserPromptSubmit → can block prompts, doesn't help inject memory
|
|
93
|
+
- Modifying transcript JSONL externally → ignored by CC's in-memory parent chain (proven dead via Phase 0 experiments)
|
|
94
|
+
|
|
95
|
+
**The current Claude Code hook system does NOT provide a documented mechanism to inject true conversation history (messages[]) into an interactive session after /clear.**
|
|
96
|
+
|
|
97
|
+
The only paths that would solve this are:
|
|
98
|
+
|
|
99
|
+
1. **Use /compact instead of /clear** — preserves session continuity in-place; PreCompact hook can influence the summary
|
|
100
|
+
2. **Agent SDK rewrite (E)** — bypass Claude Code's REPL, build a custom runtime that controls messages[] directly
|
|
101
|
+
3. **API-level proxy** — intercept the Claude Code → Anthropic API call and rewrite messages[]
|
|
@@ -95,13 +95,14 @@ on SessionStart(source, session_id, project_path):
|
|
|
95
95
|
|
|
96
96
|
`consumeBaton` が先発なので「両方同時成立」は構造上発生しない (= baton ありなら baton 経路、無ければ source 判定)。typed `/clear` も UserPromptSubmit hook で baton を書くため、通常はほぼ常に baton path が走る。auto path は VSCode 拡張のメニュー由来 `/clear` のように UserPromptSubmit に届かない経路のためのフォールバック。
|
|
97
97
|
|
|
98
|
-
### 2.2 注入内容: L1 + L2 + L3 refs
|
|
98
|
+
### 2.2 注入内容: 現在地アンカー + L1 + L2 + L3 refs (baton/auto どちらの経路でも同一)
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
含める (順序):
|
|
101
101
|
- ヘッダ + Reading Contract framing (= Codex 側 `renderCodexRolloutMemoryPreview` の写像)
|
|
102
|
+
- **現在地アンカー** (v0.4.12+): 最新 user turn と最新 assistant turn の本文をヘッダ直下に再掲 (各 600 字で truncate)
|
|
102
103
|
- **L1 summaries** (古い turn の一行要約)
|
|
103
104
|
- **L2 bodies** (直近 20 turn の verbatim)
|
|
104
|
-
- **L3 references** (= `throughline detail <時刻>`
|
|
105
|
+
- **L3 references** (= `throughline detail <時刻>` の取り出しコマンド一覧、各 L1/L2 行末尾の inline suffix として集約)
|
|
105
106
|
- Continuation Instruction (= 「これは過去ログではなく現在進行中の作業」と明示)
|
|
106
107
|
|
|
107
108
|
含めない (= 削除):
|
|
@@ -109,7 +110,9 @@ on SessionStart(source, session_id, project_path):
|
|
|
109
110
|
- 中断直前の thinking (extended thinking セクション)
|
|
110
111
|
- 既存の Claude 向け footer の冗長な使い方説明
|
|
111
112
|
|
|
112
|
-
理由:
|
|
113
|
+
理由:
|
|
114
|
+
- L2 末尾アンカーだけだと、L2 が長いセッションで注意が前半 (= L2 内の最古ターン) に固着し、古い計画ターンを「現在の作業」と誤認するケースがあった (実観測あり)。最新ターンをヘッダ直下にも再掲して、最初に目に入る位置で文脈を固定する。
|
|
115
|
+
- L2 全文があれば最後の assistant turn 自体に「次に何をしようとしていたか」が含まれている。memo / thinking は redundant。
|
|
113
116
|
|
|
114
117
|
### 2.3 `/tl` の役割: **残すが簡素化**
|
|
115
118
|
|