@brandry/claude-jsonl-compressor 1.0.0-rc.1
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 +27 -0
- package/LICENSE +674 -0
- package/NOTICE +8 -0
- package/README.md +593 -0
- package/SKILL.md +340 -0
- package/agents/openai.yaml +7 -0
- package/bin/claude-jsonl-compressor.cjs +4 -0
- package/bin/claude-jsonl-repair-read-pages.cjs +4 -0
- package/bin/run-python.cjs +77 -0
- package/config/importance_words.json +863 -0
- package/config/topic_patterns.json +608 -0
- package/package.json +60 -0
- package/references/claude-jsonl-compression-format.md +500 -0
- package/scripts/claude_session_tools.py +215 -0
- package/scripts/compress_claude_jsonl.py +7652 -0
- package/scripts/repair_claude_jsonl.py +605 -0
- package/templates/summary_template_en.md +78 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# Claude Code JSONL Compression Format Notes
|
|
2
|
+
|
|
3
|
+
This document describes the empirical format handled by
|
|
4
|
+
`@brandry/claude-jsonl-compressor` package `1.0.0-rc.1` and engine `v10`.
|
|
5
|
+
|
|
6
|
+
Claude Code transcript JSONL is an observed internal format, not a published
|
|
7
|
+
stable storage API. The rules below are deliberately strict where ambiguity
|
|
8
|
+
could restore a rewound branch, break resume topology, or make a tool exchange
|
|
9
|
+
incoherent.
|
|
10
|
+
|
|
11
|
+
## Version Domains
|
|
12
|
+
|
|
13
|
+
The project keeps four independent version domains:
|
|
14
|
+
|
|
15
|
+
| Domain | Current value | Meaning |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| Package | `1.0.0-rc.1` | GitHub/npm release version |
|
|
18
|
+
| Compression engine | `v10` | Topology, partition, and rewrite behavior |
|
|
19
|
+
| Model-pack schema | `v11` | Evidence-pack and model-summary binding protocol |
|
|
20
|
+
| Report schema | `1` | Compression and repair report fields |
|
|
21
|
+
|
|
22
|
+
A change to one domain does not imply the other domains changed.
|
|
23
|
+
|
|
24
|
+
## Three Physical and Logical Layers
|
|
25
|
+
|
|
26
|
+
A transcript can contain records that play very different roles:
|
|
27
|
+
|
|
28
|
+
1. **Active API-message chain.** `user` and `assistant` records connected from
|
|
29
|
+
the selected resume leaf through `parentUuid`. This is the history that the
|
|
30
|
+
compressor may summarize or preserve verbatim.
|
|
31
|
+
2. **Control and side records.** `last-prompt`, titles, modes, attachments,
|
|
32
|
+
hooks, and `file-history-snapshot` records may exist physically in the file
|
|
33
|
+
without becoming ordinary API messages. They require explicit projection or
|
|
34
|
+
attribution rules.
|
|
35
|
+
3. **Inactive or unattributed records.** Rewound branches and records that
|
|
36
|
+
cannot be structurally attributed to the active branch remain useful only
|
|
37
|
+
for diagnostics. Engine v10 excludes their content from every Claude-readable
|
|
38
|
+
output layer and from every model-summary evidence channel.
|
|
39
|
+
|
|
40
|
+
Physical line order alone is therefore not a definition of current context.
|
|
41
|
+
|
|
42
|
+
## Common Observed Record Types
|
|
43
|
+
|
|
44
|
+
| `type` | Observed purpose |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `user` | User content or user-side `tool_result` blocks |
|
|
47
|
+
| `assistant` | Assistant text, thinking, `tool_use`, model metadata, and usage |
|
|
48
|
+
| `system` | Claude Code events, including `subtype: compact_boundary` |
|
|
49
|
+
| `attachment` | Hook, image, file, or environment attachment metadata |
|
|
50
|
+
| `last-prompt` | UI/session pointer containing the current `leafUuid` |
|
|
51
|
+
| `file-history-snapshot` | File checkpoint metadata, commonly without UUID links |
|
|
52
|
+
| `mode` / `permission-mode` | Session mode state |
|
|
53
|
+
| `ai-title` / `custom-title` | Conversation title metadata |
|
|
54
|
+
| `queue-operation` | Queued-input or editing metadata |
|
|
55
|
+
| `agent-name` | Agent label metadata |
|
|
56
|
+
|
|
57
|
+
Open-schema handling is required: unknown fields are preserved on retained
|
|
58
|
+
records unless the operation explicitly projects a control record.
|
|
59
|
+
|
|
60
|
+
## UUID, Parent, Session, and Resume Relationships
|
|
61
|
+
|
|
62
|
+
### UUID chain
|
|
63
|
+
|
|
64
|
+
Message-like records commonly carry:
|
|
65
|
+
|
|
66
|
+
- `uuid`: record identity;
|
|
67
|
+
- `parentUuid`: preceding record on that branch, or `null` at a root;
|
|
68
|
+
- `sessionId`: session identity.
|
|
69
|
+
|
|
70
|
+
Engine v10 treats duplicate UUIDs anywhere in the input as blocking because a
|
|
71
|
+
UUID index would be ambiguous. A non-null `parentUuid` must be a non-empty
|
|
72
|
+
string; any other value is malformed. A missing parent, malformed parent or loop
|
|
73
|
+
on the selected active chain is blocking. Physical inversion is blocking except
|
|
74
|
+
for same-session `attachment -> attachment` edges on an otherwise complete,
|
|
75
|
+
acyclic chain; accepted attachments are emitted in logical parent order.
|
|
76
|
+
Equivalent non-UUID-ambiguity damage wholly inside an excluded branch does not
|
|
77
|
+
revive that branch.
|
|
78
|
+
|
|
79
|
+
Mixed `sessionId` ancestry is not rejected merely because two IDs occur. A
|
|
80
|
+
lineage is accepted only when its contiguous session runs never return to an
|
|
81
|
+
earlier ID and the final run matches both the selected leaf and authoritative
|
|
82
|
+
pointer. Planning forces every earlier run into `summaryIndexes` and preserves
|
|
83
|
+
only the final run as recent raw records. A tool relationship that would move
|
|
84
|
+
the cut across the lineage transition stops compression. This covers observed
|
|
85
|
+
historical branch/resume files without admitting A-B-A or arbitrary cross-session
|
|
86
|
+
raw chains.
|
|
87
|
+
|
|
88
|
+
### Authoritative `last-prompt`
|
|
89
|
+
|
|
90
|
+
Automatic active-chain mode uses the physically last record whose
|
|
91
|
+
`type` is `last-prompt`. Its `leafUuid` is authoritative. The engine does not
|
|
92
|
+
skip a malformed latest pointer to search for an older usable pointer because
|
|
93
|
+
that could resurrect a state the user already left.
|
|
94
|
+
|
|
95
|
+
Strict topology statuses include:
|
|
96
|
+
|
|
97
|
+
- `absent`
|
|
98
|
+
- `malformed`
|
|
99
|
+
- `malformed-parent`
|
|
100
|
+
- `duplicate-uuid`
|
|
101
|
+
- `dangling`
|
|
102
|
+
- `loop`
|
|
103
|
+
- `non-monotonic`
|
|
104
|
+
- `session-mismatch`
|
|
105
|
+
- `extension-limit`
|
|
106
|
+
- `extension-branch`
|
|
107
|
+
- `extension-unsafe`
|
|
108
|
+
- `valid`
|
|
109
|
+
|
|
110
|
+
`--resume-leaf UUID` is an explicit recovery override. It is reported as
|
|
111
|
+
`active-chain-manual-override`, distinct from default strict `active-chain`.
|
|
112
|
+
`--preserve-physical-tail` is a separate legacy compatibility
|
|
113
|
+
mode and does not provide active-branch exclusion guarantees.
|
|
114
|
+
|
|
115
|
+
Strict failures are zero-write outcomes. The CLI does not prompt or retry in a
|
|
116
|
+
different mode. A hosting agent may ask for a new, explicit user confirmation
|
|
117
|
+
when one diagnosed recovery control applies, but the initial compression request
|
|
118
|
+
is not confirmation. Manually spliced or otherwise ambiguous files normally
|
|
119
|
+
require physical-tail compatibility and therefore forfeit branch/rewind
|
|
120
|
+
isolation.
|
|
121
|
+
|
|
122
|
+
### Records after `last-prompt`
|
|
123
|
+
|
|
124
|
+
The default `--max-post-last-prompt-extension 0` excludes all UUID records
|
|
125
|
+
physically after the authoritative pointer. A nonzero value is explicit and
|
|
126
|
+
accepts only a direct, physically later, same-session linear closure consisting
|
|
127
|
+
of tool-result-only user records that close every pending tool ID. Ordinary
|
|
128
|
+
conversation, system/hook records, unrelated results and partial closure are
|
|
129
|
+
rejected as unsafe.
|
|
130
|
+
|
|
131
|
+
## Six-Way Source Partition
|
|
132
|
+
|
|
133
|
+
After strict topology succeeds, every source line belongs to exactly one set:
|
|
134
|
+
|
|
135
|
+
| Set | Meaning | May reach Claude-readable output? |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| `summaryIndexes` | Older active-chain records selected for semantic summary | Yes, only through the new summary |
|
|
138
|
+
| `rawKeepIndexes` | Recent active-chain records kept byte-semantically as JSON objects | Yes, as recent raw history |
|
|
139
|
+
| `sideKeepIndexes` | Explicitly attributed side/checkpoint records | Yes, as non-chain side records |
|
|
140
|
+
| `controlProjectionIndexes` | Control metadata used to construct the final projected state | Yes, only through controlled projection |
|
|
141
|
+
| `excludedBranchIndexes` | UUID records outside the selected active branch | No |
|
|
142
|
+
| `excludedUnattributedIndexes` | Records with no accepted structural attribution | No |
|
|
143
|
+
|
|
144
|
+
The sets are mutually exclusive and cover every source index. The legacy
|
|
145
|
+
internal/report name `omittedIndexes` is only a compatibility alias for
|
|
146
|
+
`summaryIndexes`; it no longer means every physically discarded record.
|
|
147
|
+
|
|
148
|
+
Before a model pack or candidate is written, the engine copies only the
|
|
149
|
+
authoritative logical active chain, projects its selected leaf into one pointer,
|
|
150
|
+
and runs the shared transcript validator on that source view. Malformed old tool
|
|
151
|
+
exchanges, duplicate tool IDs, or compact metadata on the active chain therefore
|
|
152
|
+
cannot be hidden by summarization. Damage confined to an excluded inactive
|
|
153
|
+
branch remains excluded and does not block or enter the summary.
|
|
154
|
+
|
|
155
|
+
Inactive and unattributed record bodies are absent from:
|
|
156
|
+
|
|
157
|
+
- the model evidence pack;
|
|
158
|
+
- model-authored summary validation input;
|
|
159
|
+
- deterministic fallback summary input;
|
|
160
|
+
- prior-summary verbatim blocks;
|
|
161
|
+
- recent raw records;
|
|
162
|
+
- side records;
|
|
163
|
+
- the final candidate JSONL.
|
|
164
|
+
|
|
165
|
+
Reports may expose only counts and content-free line-set digests for excluded
|
|
166
|
+
sets.
|
|
167
|
+
|
|
168
|
+
## Compact-Style Output Pair
|
|
169
|
+
|
|
170
|
+
The engine emits exactly one current Codex-created compact pair:
|
|
171
|
+
|
|
172
|
+
1. a `system` record with `subtype: "compact_boundary"`;
|
|
173
|
+
2. its direct `user` child with `isCompactSummary: true`.
|
|
174
|
+
|
|
175
|
+
Simplified synthetic shape:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{"type":"system","subtype":"compact_boundary","uuid":"BOUNDARY_UUID","parentUuid":null,"compactMetadata":{"codexOfflineCompression":true,"codexOfflineCompressionVersion":"v10","modelPackSchemaVersion":11,"reportSchemaVersion":1,"summaryUuid":"SUMMARY_UUID","preserveMode":"active-chain","resumeLeafInfo":{"status":"valid","selectedLeafUuid":"ACTIVE_LEAF"}}}
|
|
179
|
+
{"type":"user","uuid":"SUMMARY_UUID","parentUuid":"BOUNDARY_UUID","isCompactSummary":true,"message":{"role":"user","content":"SUMMARY_TEXT"}}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The exact open-schema object contains additional observed metadata. The current
|
|
183
|
+
pair is followed by the recent active suffix. In strict active-chain mode, only
|
|
184
|
+
the first recent record has its parent changed to `SUMMARY_UUID`; every later
|
|
185
|
+
recent parent/session edge must already be coherent. A final `last-prompt` is
|
|
186
|
+
deep-copied from the authoritative source pointer so unknown fields survive,
|
|
187
|
+
then only its projected leaf/session values are updated.
|
|
188
|
+
|
|
189
|
+
Validation requires the final pointer's active chain to contain the exact
|
|
190
|
+
current boundary and summary, not merely an older compact pair.
|
|
191
|
+
|
|
192
|
+
## Model-Assisted Summary Protocol v11
|
|
193
|
+
|
|
194
|
+
Model-assisted semantic summary is the default. Deterministic code owns all
|
|
195
|
+
topology, source partitioning, JSONL construction, UUID generation, parent
|
|
196
|
+
rewrites, and validation. The model receives only the frozen evidence pack and
|
|
197
|
+
writes summary prose.
|
|
198
|
+
|
|
199
|
+
### Evidence binding
|
|
200
|
+
|
|
201
|
+
The generated pack contains:
|
|
202
|
+
|
|
203
|
+
- a generic `SOURCE_JSONL` label, never the original filename or full local path;
|
|
204
|
+
- full source-file SHA-256;
|
|
205
|
+
- SHA-256 of the exact active records selected for summary;
|
|
206
|
+
- the digest of the displayed evidence-anchor set;
|
|
207
|
+
- the digest of all required evidence-coverage groups;
|
|
208
|
+
- the digest of an optional external handoff summary;
|
|
209
|
+
- a canonical request digest binding all selection/budget/policy options and the
|
|
210
|
+
loaded importance/topic/template resource content;
|
|
211
|
+
- a digest of the mandatory claim-source map;
|
|
212
|
+
- a full-text `L<number>` record for every non-empty older active human message
|
|
213
|
+
and every older active assistant `text`/`thinking` message;
|
|
214
|
+
- selected line-numbered source/tool/error evidence;
|
|
215
|
+
- `H<number>` anchors for displayed handoff lines;
|
|
216
|
+
- explicit current-state, chronology, supersession, decision, rationale,
|
|
217
|
+
rejected-option, uncertainty, and recent-boundary instructions.
|
|
218
|
+
|
|
219
|
+
The model summary must begin with the exact comment copied from the pack:
|
|
220
|
+
|
|
221
|
+
```html
|
|
222
|
+
<!-- claude-jsonl-compressor:model-summary v11
|
|
223
|
+
source_sha256: SOURCE_SHA256
|
|
224
|
+
summary_source_sha256: SUMMARY_SOURCE_SHA256
|
|
225
|
+
evidence_anchor_lines_digest: EVIDENCE_ANCHOR_LINES_DIGEST
|
|
226
|
+
required_anchor_groups_digest: REQUIRED_ANCHOR_GROUPS_DIGEST
|
|
227
|
+
handoff_summary_digest: HANDOFF_SUMMARY_DIGEST_OR_NONE
|
|
228
|
+
pack_request_digest: PACK_REQUEST_DIGEST
|
|
229
|
+
required_claim_sources_digest: REQUIRED_CLAIM_SOURCES_DIGEST
|
|
230
|
+
-->
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Substantive factual lines cite displayed `L<number>` and, when used, `H<number>`
|
|
234
|
+
anchors. The exact whole line `Unknown from provided anchors.` is the only
|
|
235
|
+
unanchored uncertainty placeholder; a longer line containing that text has no
|
|
236
|
+
exemption. Validation rejects wrong digests, invisible or out-of-range anchors,
|
|
237
|
+
unanchored substantive lines, too little evidence coverage, and common
|
|
238
|
+
no-access boilerplate. It requires at least one cited L anchor from each
|
|
239
|
+
generated group. Every non-empty human/assistant semantic record has its own
|
|
240
|
+
required L group, and prior summaries remain independently required. It also
|
|
241
|
+
requires all nine exact semantic sections printed in the pack, each with an L
|
|
242
|
+
or H anchor. A nonempty handoff generates early/middle/late/latest H coverage
|
|
243
|
+
groups that must all be cited. Handoff text is not trusted merely because it
|
|
244
|
+
contains a special phrase; only generated H anchors are accepted.
|
|
245
|
+
|
|
246
|
+
Only the exact leading metadata comment and the exact required headings are
|
|
247
|
+
exempt from line grounding. A second/unclosed HTML comment, an extra Markdown
|
|
248
|
+
heading, duplicate metadata, renamed/reordered sections, or unsupported body
|
|
249
|
+
line is an error. Under `## Evidence and Source Anchors`, the summary must contain
|
|
250
|
+
exactly one `### Mandatory Evidence Coverage` subsection. Every mandatory
|
|
251
|
+
semantic/prior-summary L anchor appears exactly once as:
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
- L42 support_text_json="exact source substring" disposition=covered
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The JSON string must decode to a meaningful exact substring of that source
|
|
258
|
+
record. This blocks a content-free anchor dump and leaves a mechanically
|
|
259
|
+
checkable excerpt; it does not prove perfect natural-language interpretation.
|
|
260
|
+
|
|
261
|
+
Every active-chain prior compact summary is inserted as a complete dedicated
|
|
262
|
+
evidence record. An explicitly supplied external handoff is inserted in full,
|
|
263
|
+
one JSON-escaped `H<number> full_text_json` line per source line. Two default
|
|
264
|
+
pack ceilings apply together: 500,000 characters and a conservative 150,000
|
|
265
|
+
local estimated tokens. The latter leaves working space in a typical 200k
|
|
266
|
+
summarizer context. If the complete semantic ledger, prior summaries, handoff,
|
|
267
|
+
and minimum structural coverage do not fit, pack generation stops; it does not
|
|
268
|
+
trim or sample mandatory evidence. Optional source/tool/system/error evidence
|
|
269
|
+
is ranked and added only while both ceilings permit, and truncation is reported.
|
|
270
|
+
The caller should raise `--model-pack-char-budget` or
|
|
271
|
+
`--model-pack-estimated-token-budget` only when the summarizing model can read
|
|
272
|
+
the resulting pack. No external tokenizer is installed. Once a model summary
|
|
273
|
+
passes validation, its text is not truncated to meet `--summary-char-budget`;
|
|
274
|
+
insufficient composition space is a hard error. The summary character budget
|
|
275
|
+
has a hard minimum of 4000, and blank compact summaries are invalid.
|
|
276
|
+
|
|
277
|
+
These controls reduce stale-summary and unsupported-claim risk. They do not
|
|
278
|
+
mathematically prove that a natural-language summary has perfect semantics.
|
|
279
|
+
The deterministic safety appendix and recent raw suffix remain independent
|
|
280
|
+
evidence layers.
|
|
281
|
+
|
|
282
|
+
### Weighting and chronology
|
|
283
|
+
|
|
284
|
+
The evidence pack requires every non-empty older active human message and every
|
|
285
|
+
older active assistant `text`/`thinking` message, regardless of language or
|
|
286
|
+
keyword score. Source-text warnings such as U+FFFD are reported but do not make
|
|
287
|
+
mandatory records optional. Within the remaining optional source/tool capacity it gives
|
|
288
|
+
priority to:
|
|
289
|
+
|
|
290
|
+
1. explicit user constraints and requested outcomes;
|
|
291
|
+
2. final/current decisions and their reasons;
|
|
292
|
+
3. supersessions and chronology needed to avoid reviving old decisions;
|
|
293
|
+
4. model research conclusions, implementation decisions, and rationale;
|
|
294
|
+
5. unresolved risks, exact identifiers, source references, and validation
|
|
295
|
+
results;
|
|
296
|
+
6. file/tool content that materially supports the above;
|
|
297
|
+
7. repetitive logs or mechanically recoverable detail.
|
|
298
|
+
|
|
299
|
+
Important evidence can be Chinese, English, Japanese, Korean, Arabic, Russian,
|
|
300
|
+
Hindi, Greek, Hebrew, Armenian, Thai, Georgian, Ethiopic, Bengali, Tamil,
|
|
301
|
+
Telugu, Malayalam, Spanish, French, German, Portuguese, or another language.
|
|
302
|
+
All assistant thinking is semantic evidence without a language-keyword gate;
|
|
303
|
+
multilingual terms and script detection only improve classification and optional
|
|
304
|
+
weighting. Language is not treated as a proxy for importance.
|
|
305
|
+
|
|
306
|
+
## Token Ceilings
|
|
307
|
+
|
|
308
|
+
`--model-pack-estimated-token-budget N` limits the evidence pack read by the
|
|
309
|
+
summary-authoring model. It defaults to 150,000 and is enforced together with
|
|
310
|
+
the character budget. The same non-default value must be supplied when
|
|
311
|
+
generating the pack and when applying the model summary. Mandatory semantic and
|
|
312
|
+
handoff evidence cannot be dropped to satisfy it; optional evidence can be
|
|
313
|
+
truncated and this state is recorded in the pack, compact metadata, and report.
|
|
314
|
+
|
|
315
|
+
`--target-estimated-tokens N` uses a dependency-free heuristic over complete
|
|
316
|
+
retained structured message payloads, including full thinking,
|
|
317
|
+
`tool_use.input`, `tool_result`, and `toolUseResult` data. ASCII is estimated at
|
|
318
|
+
one token per four characters;
|
|
319
|
+
Han/Kana/Hangul at 1.3 each; non-BMP, symbol and combining-mark code points at
|
|
320
|
+
1.5 each; other non-ASCII at 0.8 each; and each record adds a small allowance.
|
|
321
|
+
It narrows the byte-ratio plan and rejects a generated candidate whose
|
|
322
|
+
estimated message tokens exceed `N`. This candidate-output gate is independent
|
|
323
|
+
of the model-pack reading ceiling.
|
|
324
|
+
|
|
325
|
+
This estimate excludes system prompts, tools, MCP schemas, skills, runtime
|
|
326
|
+
injections, and any Claude-side accounting. It is a reproducible local planning
|
|
327
|
+
gate, not a promise that `/context` or an API relay will report the same total.
|
|
328
|
+
`--target-ratio` is only an approximate byte-ratio planning input and is not a
|
|
329
|
+
hard publication gate.
|
|
330
|
+
|
|
331
|
+
## Tool Use and Tool Result Pairing
|
|
332
|
+
|
|
333
|
+
One API turn may be split across several JSONL records:
|
|
334
|
+
|
|
335
|
+
- multiple `tool_use` blocks in one assistant message;
|
|
336
|
+
- adjacent assistant fragments sharing one `message.id`;
|
|
337
|
+
- split user records carrying `tool_result` blocks;
|
|
338
|
+
- hook or attachment records between result fragments.
|
|
339
|
+
|
|
340
|
+
Validation rebuilds the selected active chain, filters API messages, merges
|
|
341
|
+
compatible assistant and user fragments, and checks tool IDs and order. It
|
|
342
|
+
rejects orphan results, wrong IDs, and out-of-order results. The compression cut
|
|
343
|
+
cannot divide a required tool-use/result relationship.
|
|
344
|
+
|
|
345
|
+
## File-History Checkpoint Policies
|
|
346
|
+
|
|
347
|
+
Conversation topology and file checkpoint metadata are separate planes.
|
|
348
|
+
`file-history-snapshot` records commonly lack `uuid` and `parentUuid`, so they
|
|
349
|
+
cannot be relinked into the API-message chain.
|
|
350
|
+
|
|
351
|
+
Policies:
|
|
352
|
+
|
|
353
|
+
- `active-correlated` (default): retain a bounded set only when structural
|
|
354
|
+
identifiers correlate the snapshot to recent active records;
|
|
355
|
+
- `preserve-recent`: rejected in strict active-chain mode; accepted only with
|
|
356
|
+
explicit `--preserve-physical-tail`, which is labeled compatibility mode and
|
|
357
|
+
has no inactive-branch isolation guarantee;
|
|
358
|
+
- `none`: retain no snapshot side records.
|
|
359
|
+
|
|
360
|
+
Preserved snapshots are emitted as side records before the compact pair. JSONL
|
|
361
|
+
compression alone does not guarantee complete file-state rewind because Claude
|
|
362
|
+
Code checkpoint storage and lifecycle have behavior beyond the message chain.
|
|
363
|
+
|
|
364
|
+
## Repeated Compression
|
|
365
|
+
|
|
366
|
+
Old compact pairs on the active chain are part of `summaryIndexes` when they
|
|
367
|
+
fall before the recent suffix. Normal repeated compression folds their useful
|
|
368
|
+
meaning into one new current summary rather than stacking live compact pairs.
|
|
369
|
+
|
|
370
|
+
`compactMetadata.preservedMessages` and `preservedSegment` describe the raw
|
|
371
|
+
suffix that existed when that compact pair was created. Later work can extend
|
|
372
|
+
that suffix, and a later rewind can leave part of the recorded snapshot on an
|
|
373
|
+
inactive branch. A structurally valid historical divergence is therefore a
|
|
374
|
+
source warning, not authority to restore those UUIDs and not a topology error.
|
|
375
|
+
Selection continues from the current `last-prompt` parent chain. Candidate
|
|
376
|
+
publication is stricter: the newly emitted snapshot must match the candidate's
|
|
377
|
+
current chain exactly or publication stops before writing.
|
|
378
|
+
|
|
379
|
+
`--preserve-prior-summaries-verbatim` is an explicit exception. It attempts to
|
|
380
|
+
embed prior `isCompactSummary.message.content` text verbatim inside the one new
|
|
381
|
+
summary and permits the summary text to grow to `1.5 * --summary-char-budget`.
|
|
382
|
+
If the prior summaries still do not fit, the engine uses the normal folded
|
|
383
|
+
model-summary path and reports the fallback reason. Excluded-branch summaries
|
|
384
|
+
are never eligible for either path.
|
|
385
|
+
|
|
386
|
+
## Branch Session Files
|
|
387
|
+
|
|
388
|
+
Observed `/branch` files are not guaranteed to be full physical copies. They
|
|
389
|
+
may retain source UUIDs, rewrite `sessionId`, add `forkedFrom`, relink parents,
|
|
390
|
+
and omit source history outside the branch-relevant chain.
|
|
391
|
+
|
|
392
|
+
The compressor treats exactly one selected JSONL as authoritative. It does not
|
|
393
|
+
merge a branch file with its source. Compress the branch to continue the branch;
|
|
394
|
+
compress or archive the source separately when its physical history matters.
|
|
395
|
+
|
|
396
|
+
## External References
|
|
397
|
+
|
|
398
|
+
JSONL may contain inline tool results, file excerpts, attachment metadata, or
|
|
399
|
+
paths/references to external artifacts such as tool-result storage. Offline
|
|
400
|
+
compression reads the selected JSONL and an explicitly supplied handoff file
|
|
401
|
+
only. It does not dereference, delete, or rewrite external project files,
|
|
402
|
+
`tool-results`, subagent artifacts, settings, or other sessions.
|
|
403
|
+
|
|
404
|
+
If a referenced artifact's contents are not embedded in the JSONL or handoff,
|
|
405
|
+
the model pack knows only the reference, not the external contents.
|
|
406
|
+
|
|
407
|
+
## `Read.pages` Compatibility Repair
|
|
408
|
+
|
|
409
|
+
Claude Code legitimately uses `Read.input.pages`, including for paged document
|
|
410
|
+
reads. The independent repair command exists only for a known downstream
|
|
411
|
+
compatibility case where historical serialized `pages` members must be removed.
|
|
412
|
+
Compression never invokes this repair implicitly.
|
|
413
|
+
|
|
414
|
+
The repairer:
|
|
415
|
+
|
|
416
|
+
- matches only assistant `tool_use` blocks with exact tool name `Read` and an
|
|
417
|
+
`input` object containing `pages`;
|
|
418
|
+
- requires a nonempty `file_path`, exactly one later matching `tool_result`, the
|
|
419
|
+
same nonempty `sessionId`, and result `sourceToolAssistantUUID` equal to the
|
|
420
|
+
tool-use assistant UUID before automatic repair;
|
|
421
|
+
- reports pending calls without changing them;
|
|
422
|
+
- defaults to the strict active chain; `--scope all` is explicit;
|
|
423
|
+
- deletes the exact JSON member byte span without reserializing other data;
|
|
424
|
+
- blocks duplicate-key or overlapping-span ambiguity;
|
|
425
|
+
- preserves BOM, newline style, Unicode spelling, unknown fields, record count,
|
|
426
|
+
UUID/parent signature, and tool ID sequences;
|
|
427
|
+
- re-reads the actual published candidate, verifies exact expected bytes and
|
|
428
|
+
SHA-256, validates the repair invariants, requires an idempotent second scan
|
|
429
|
+
with zero remaining patches, and runs the shared full-transcript
|
|
430
|
+
UUID/parent/compact/tool validator on the published bytes.
|
|
431
|
+
|
|
432
|
+
Candidate and live replacement modes use the same atomic-write, full-hash,
|
|
433
|
+
numbered-backup, source-race, validation, and rollback principles as compression.
|
|
434
|
+
|
|
435
|
+
## Candidate and Live Replacement Transactions
|
|
436
|
+
|
|
437
|
+
Candidate mode requires distinct input and output paths. Candidate JSONL,
|
|
438
|
+
reports, validation, model packs, summaries and work directories must remain
|
|
439
|
+
outside the entire `.claude` tree.
|
|
440
|
+
|
|
441
|
+
Live replacement mode requires one existing regular `.jsonl` input under
|
|
442
|
+
`.claude/projects`, an external `--work-dir`, and caller acknowledgement
|
|
443
|
+
`--confirm-session-closed`. The acknowledgement is an operational assertion,
|
|
444
|
+
not process-lock detection. It:
|
|
445
|
+
|
|
446
|
+
1. reads and hashes the complete original bytes;
|
|
447
|
+
2. writes and validates a candidate outside `.claude`;
|
|
448
|
+
3. rechecks that the source bytes did not change;
|
|
449
|
+
4. creates an exclusive `.backup`, `.backup1`, and so on;
|
|
450
|
+
5. validates immutable candidate bytes and writes a unique same-directory stage
|
|
451
|
+
with flush/fsync;
|
|
452
|
+
6. captures the actual old target, verifies its full bytes against the frozen
|
|
453
|
+
source, and publishes the staged candidate with an atomic no-clobber claim;
|
|
454
|
+
7. verifies published bytes and structure, restoring the captured original on
|
|
455
|
+
failure. If restoration fails, the numbered verified backup remains and the
|
|
456
|
+
error is promoted.
|
|
457
|
+
|
|
458
|
+
If another process recreates the target after capture begins, the transaction
|
|
459
|
+
does not overwrite the external target. It preserves the verified numbered
|
|
460
|
+
backup and, when necessary, places the captured original in another numbered
|
|
461
|
+
backup, then fails without publishing the candidate.
|
|
462
|
+
|
|
463
|
+
Candidate-mode reports are written with the candidate. Live compression delays
|
|
464
|
+
its final sidecar/report until replacement metadata is available, so it does not
|
|
465
|
+
leave a stale pre-commit report. If the JSONL commits and validates but final
|
|
466
|
+
report publication fails, compression returns exit code 3 with
|
|
467
|
+
`operation_state: committed-report-failed`; repair uses the camelCase equivalent
|
|
468
|
+
`operationState`. The receipt includes public artifact labels and frozen,
|
|
469
|
+
candidate, and published hashes. This is a committed state and is not rolled
|
|
470
|
+
back or reported as an ordinary uncommitted failure.
|
|
471
|
+
|
|
472
|
+
Once a numbered backup is created and verified, later failure cleanup never
|
|
473
|
+
deletes that path. This preserves an audit/recovery asset even when publication
|
|
474
|
+
or rollback fails or another process races on a nearby name.
|
|
475
|
+
|
|
476
|
+
Claude Code should be closed for that session during replacement. No other
|
|
477
|
+
session or Claude settings file is part of the transaction. Parent-directory
|
|
478
|
+
fsync is best effort and reported; the project does not promise cross-platform
|
|
479
|
+
power-loss atomicity.
|
|
480
|
+
|
|
481
|
+
## Validation Boundary
|
|
482
|
+
|
|
483
|
+
The validator checks observed-format coherence, including:
|
|
484
|
+
|
|
485
|
+
- parseability and object-per-line structure;
|
|
486
|
+
- unique UUIDs and resolvable parent/session links;
|
|
487
|
+
- exactly one current compact pair;
|
|
488
|
+
- current compact pair reachability from the final pointer;
|
|
489
|
+
- compact preserved-message metadata;
|
|
490
|
+
- non-empty, unique active tool IDs and tool-use/result pairing after fragment
|
|
491
|
+
merging; partial multi-tool ordered subsets are accepted only with an explicit
|
|
492
|
+
compatibility warning/count;
|
|
493
|
+
- absence of internal planning fields in output;
|
|
494
|
+
- source hashes, model-pack metadata, anchor sets, and target estimates where
|
|
495
|
+
applicable.
|
|
496
|
+
|
|
497
|
+
Passing these checks proves coherence under this project's empirical rules. It
|
|
498
|
+
does not make the private transcript format an Anthropic-supported public API.
|
|
499
|
+
When runtime testing is explicitly requested, `/resume`, `/context`, recent
|
|
500
|
+
conversation rewind, and recent file rewind are separate observations.
|