Compact Agent Trace Deterministically With No Info Loss. Stop Summarization With “/compact”.
Lvmin Zhang recently wrote a paper VCC. The open-source version is here (basically an agent skill).
VCC is a compiler that compiles agent traces (Claude Code’s JSONL) into agent-friendly views. A Claude Code JSONL log can exceed ten thousand lines. VCC runs a full compiler pipeline — lex, parse, IR, lower, emit — to transform this raw log into three views: a full view, a UI view, and an adaptive view. These views are much shorter, structured, created deterministically on-the-fly from the agent trace and discarded after usage. Three views together enable progressive disclosure.
Three Views by Example
Imagine a user asks a coding agent to write a pet-tracking module. The agent thinks, tries to read an existing file (which fails), then writes a new one. Here is how VCC renders that same trace under each view.
Full View
The full view is the complete transcript. Line numbers are assigned once and shared across all views. Let’s say this is example.txt:
1 [user]
2
3 I have two pets.
4 Can you write a Python module for tracking them?
5 One is a dog named Buddy and a cat named Whiskers.
6
7 ══════════════════════════════
8 [assistant]
9
10 >>>thinking
11 The user wants a pet tracking module.
12 They have a dog (Buddy) and a cat (Whiskers).
13 Let me check if there's an existing file first.
14 <<<thinking
15
16 Sure! Let me check if there's an existing file.
17
18 >>>tool_call Read:tu01
19 file_path: src/pets.py
20 <<<tool_call
21
22 ══════════════════════════════
23 [tool_error] Read:tu01
24
25 Error: file not found src/pets.py
26
27 ══════════════════════════════
28 [assistant]
29
30 >>>thinking
31 No existing file.
32 I'll create Dog and Cat subclasses.
33 The dog needs walk tracking.
34 The cat needs nap tracking.
35 <<<thinking
36
37 No existing file.
38 I'll create a module with Dog and Cat classes.
39
40 >>>tool_call Write:tu02
41 file_path: src/pets.py
42 content: |
43 class Pet:
44 def __init__(self, name, species):
45 self.name = name
46 self.species = species
47
48 class Dog(Pet):
49 def __init__(self, name):
50 super().__init__(name, 'dog')
51 self.walks = []
52
53 def log_walk(self, duration, distance):
54 self.walks.append({'min': duration, 'km': distance})
55
56 class Cat(Pet):
57 def __init__(self, name):
58 super().__init__(name, 'cat')
59 self.naps = []
60
61 def log_nap(self, duration, spot):
62 self.naps.append({'min': duration, 'spot': spot})
63 <<<tool_call
64
65 ══════════════════════════════
66 [tool] Write:tu02
67
68 File written successfully.
69
70 ══════════════════════════════
71 [assistant]
72
73 Created src/pets.py.
Everything is here: the user’s request, the agent’s internal reasoning (>>>thinking), the tool calls with their full parameters, the tool results, and the final response. This is the canonical reference — all pointers from the other views point back here.
UI View
The UI view simulates what the user actually saw during the session. Thinking blocks are gone. Tool calls are collapsed to one-line summaries. The two separate assistant turns are merged into one continuous response, because that’s how the user experienced it:
[user]
I have two pets.
Can you write a Python module for tracking them?
One is a dog named Buddy and a cat named Whiskers.
[assistant]
Sure! Let me check if there's an existing file.
* Read "src/pets.py" (example.txt:18-20,23-25)
No existing file.
I'll create a module with Dog and Cat classes.
* Write "src/pets.py" (example.txt:40-63,66-68)
Created src/pets.py.
The pointers like (example.txt:18-20,23-25) tell you where to find the full detail: lines 18–20 hold the tool call, lines 23–25 hold the tool result. You can jump there in the full view whenever you need the specifics.
Adaptive View (--grep dog)
Now suppose you search for “dog” across the trace. Only blocks containing a match are shown, but the conversation structure is preserved — and each match is tagged with its semantic role:
[user]
(example.txt:3-5)
5: One is a dog named Buddy and a cat named Whiskers.
══════════════════════════════
[assistant]
>>>thinking
(example.txt:11-13)
12: They have a dog (Buddy) and a cat (Whiskers).
<<<thinking
══════════════════════════════
[assistant]
>>>thinking
(example.txt:31-34)
33: The dog needs walk tracking.
<<<thinking
>>>tool_call Write:tu02
(example.txt:41-62)
50: super().__init__(name, 'dog')
<<<tool_call
Write:tu02 spans 22 lines of code (41–62), but only line 50 ('dog') matched — the entire Cat class (56–62) is absent. The pointer 41-62 tells you where to read the full block. This is not grep: grep gives you isolated lines stripped of their conversational identity, while VCC tells you that line 5 is a user message, line 12 is internal reasoning, line 33 is also reasoning, and line 50 is inside a tool call. Those semantic distinctions matter for analysis.
There is also a transposed version — same matches as a flat list, each tagged with what it is and where to find it:
(example.txt:3-5) [user]
5: One is a dog named Buddy and a cat named Whiskers.
(example.txt:11-13) [thinking]
12: They have a dog (Buddy) and a cat (Whiskers).
(example.txt:31-34) [thinking]
33: The dog needs walk tracking.
(example.txt:41-62) [tool_call]
50: super().__init__(name, 'dog')
The adaptive view keeps conversation order, so it is good for understanding context around a match. The transposed view is a flat list, so it is good for scanning all matches at once. All pointers point into the full view.
Progressive Disclosure
The three views enable a progressive-disclosure workflow. An agent (or human analyst) begins with the UI view to scan the overall session trajectory — the sequence of user requests, assistant actions, and outcomes — without wading through tool I/O or chain-of-thought internals. Targeted searches via the adaptive view then locate specific content blocks of interest, each annotated with its semantic role and a line-range pointer. Following a pointer into the full view recovers the complete, verbatim content of that block and its immediate surroundings. Because the full view is a single file, a pointer dereference yields immediately adjacent surrounding context — you see not just the block you jumped to, but what came before and after it.
Projection, Not Summarization
VCC stores nothing. Views are dynamic — they are computed on the fly from the original JSONL, then thrown away after use. This makes VCC fundamentally different from multi-level memory systems like MemGPT, A-MEM, or RAPTOR, which maintain static, precomputed artifacts (summaries, embeddings, knowledge-graph nodes) connected by persistent edges. Those systems perform abstraction — generating new content not present in the source, introducing lossy compression whose faithfulness must be evaluated empirically. VCC performs projection — selecting and arranging existing content from the source, annotated with exact coordinates for recovering the unselected remainder. The system is lossless by construction: not in the sense that every view contains all information, but in the sense that every view contains a verifiable path back to the full information.