@bastani/atomic 0.8.27-alpha.1 → 0.8.28-alpha.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  5. package/dist/builtin/mcp/package.json +2 -2
  6. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  7. package/dist/builtin/subagents/package.json +1 -1
  8. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  9. package/dist/builtin/web-access/package.json +1 -1
  10. package/dist/builtin/workflows/CHANGELOG.md +20 -0
  11. package/dist/builtin/workflows/README.md +11 -9
  12. package/dist/builtin/workflows/package.json +1 -1
  13. package/dist/builtin/workflows/src/authoring.d.ts +5 -2
  14. package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +3 -1
  15. package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +17 -25
  16. package/dist/builtin/workflows/src/extension/index.ts +133 -18
  17. package/dist/builtin/workflows/src/extension/render-result.ts +22 -2
  18. package/dist/builtin/workflows/src/extension/workflow-schema.ts +3 -3
  19. package/dist/builtin/workflows/src/runs/foreground/executor.ts +210 -16
  20. package/dist/builtin/workflows/src/sdk-surface.ts +1 -1
  21. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +42 -5
  22. package/dist/builtin/workflows/src/shared/store-types.ts +8 -2
  23. package/dist/builtin/workflows/src/shared/store.ts +51 -0
  24. package/dist/builtin/workflows/src/shared/types.ts +14 -4
  25. package/dist/builtin/workflows/src/tui/graph-view.ts +4 -1
  26. package/dist/builtin/workflows/src/tui/prompt-card.ts +6 -0
  27. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +11 -1
  28. package/dist/core/agent-session.d.ts +4 -4
  29. package/dist/core/agent-session.d.ts.map +1 -1
  30. package/dist/core/agent-session.js +147 -31
  31. package/dist/core/agent-session.js.map +1 -1
  32. package/dist/core/auth-guidance.d.ts +10 -1
  33. package/dist/core/auth-guidance.d.ts.map +1 -1
  34. package/dist/core/auth-guidance.js +26 -1
  35. package/dist/core/auth-guidance.js.map +1 -1
  36. package/dist/core/compaction/branch-summarization.d.ts +2 -2
  37. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  38. package/dist/core/compaction/branch-summarization.js +7 -7
  39. package/dist/core/compaction/branch-summarization.js.map +1 -1
  40. package/dist/core/compaction/compaction.d.ts +4 -84
  41. package/dist/core/compaction/compaction.d.ts.map +1 -1
  42. package/dist/core/compaction/compaction.js +3 -479
  43. package/dist/core/compaction/compaction.js.map +1 -1
  44. package/dist/core/compaction/context-compaction.d.ts.map +1 -1
  45. package/dist/core/compaction/context-compaction.js +39 -82
  46. package/dist/core/compaction/context-compaction.js.map +1 -1
  47. package/dist/core/compaction/index.d.ts +1 -1
  48. package/dist/core/compaction/index.d.ts.map +1 -1
  49. package/dist/core/compaction/index.js +1 -1
  50. package/dist/core/compaction/index.js.map +1 -1
  51. package/dist/core/extensions/types.d.ts +10 -8
  52. package/dist/core/extensions/types.d.ts.map +1 -1
  53. package/dist/core/extensions/types.js.map +1 -1
  54. package/dist/core/index.d.ts +1 -1
  55. package/dist/core/index.d.ts.map +1 -1
  56. package/dist/core/index.js.map +1 -1
  57. package/dist/core/messages.d.ts +1 -11
  58. package/dist/core/messages.d.ts.map +1 -1
  59. package/dist/core/messages.js +10 -25
  60. package/dist/core/messages.js.map +1 -1
  61. package/dist/core/session-manager.d.ts +5 -8
  62. package/dist/core/session-manager.d.ts.map +1 -1
  63. package/dist/core/session-manager.js +12 -76
  64. package/dist/core/session-manager.js.map +1 -1
  65. package/dist/core/settings-manager.d.ts +0 -3
  66. package/dist/core/settings-manager.d.ts.map +1 -1
  67. package/dist/core/settings-manager.js +0 -4
  68. package/dist/core/settings-manager.js.map +1 -1
  69. package/dist/index.d.ts +3 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +3 -3
  72. package/dist/index.js.map +1 -1
  73. package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -5
  74. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  75. package/dist/modes/interactive/components/chat-message-renderer.js +5 -9
  76. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  77. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  78. package/dist/modes/interactive/components/chat-session-host.js +0 -3
  79. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  80. package/dist/modes/interactive/components/index.d.ts +0 -1
  81. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  82. package/dist/modes/interactive/components/index.js +0 -1
  83. package/dist/modes/interactive/components/index.js.map +1 -1
  84. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  85. package/dist/modes/interactive/interactive-mode.js +4 -27
  86. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  87. package/dist/modes/rpc/rpc-client.d.ts +1 -1
  88. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  89. package/dist/modes/rpc/rpc-client.js +2 -2
  90. package/dist/modes/rpc/rpc-client.js.map +1 -1
  91. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  92. package/dist/modes/rpc/rpc-mode.js +1 -1
  93. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  94. package/dist/modes/rpc/rpc-types.d.ts +0 -1
  95. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  96. package/dist/modes/rpc/rpc-types.js.map +1 -1
  97. package/docs/compaction.md +210 -181
  98. package/docs/extensions.md +31 -20
  99. package/docs/json.md +3 -4
  100. package/docs/session-format.md +12 -21
  101. package/docs/sessions.md +3 -1
  102. package/docs/settings.md +2 -5
  103. package/docs/workflows.md +11 -9
  104. package/examples/extensions/README.md +1 -1
  105. package/examples/extensions/custom-compaction.ts +43 -106
  106. package/examples/extensions/handoff.ts +6 -44
  107. package/examples/extensions/trigger-compact.ts +5 -4
  108. package/package.json +5 -5
  109. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
  110. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  111. package/dist/modes/interactive/components/compaction-summary-message.js +0 -43
  112. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
@@ -1,32 +1,54 @@
1
1
  # Compaction & Branch Summarization
2
2
 
3
- LLMs have limited context windows. When conversations grow too long, Atomic's default compaction path uses **Verbatim Compaction**: it deletes safe older transcript objects while preserving every retained object exactly as it was recorded. This page covers default auto/manual compaction, legacy summary compaction internals, and branch summarization.
3
+ LLMs have limited context windows. When conversations grow too long, Atomic's compaction behavior uses **Verbatim Compaction**: it deletes safe older transcript objects while preserving every retained object exactly as it was recorded. This page covers default auto/manual compaction, how it compares to the retired legacy summary compaction, and branch summarization.
4
4
 
5
- Atomic's default compaction design and terminology are informed by Morph's Context Compaction work: [Morph's Context Compaction](https://www.morphllm.com/context-compaction). Atomic follows the same core idea that coding agents often benefit more from deleting low-signal context than from rewriting high-signal details like file paths, line numbers, commands, and error strings into a lossy summary.
5
+ Atomic's compaction design and terminology are informed by Morph's Context Compaction work: [Morph's Context Compaction](https://www.morphllm.com/context-compaction). Atomic follows the same core idea that coding agents often benefit more from deleting low-signal context than from rewriting high-signal details like file paths, line numbers, commands, and error strings into a lossy summary.
6
6
 
7
7
  **Source files** ([atomic](https://github.com/bastani-inc/atomic)):
8
8
 
9
9
  - [`packages/coding-agent/src/core/compaction/context-compaction.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/context-compaction.ts) - Verbatim Compaction planner, transcript tools, validation, and prompt
10
- - [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Legacy summary compaction logic and shared threshold helpers
11
10
  - [`packages/coding-agent/src/core/compaction/branch-summarization.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) - Branch summarization
12
11
  - [`packages/coding-agent/src/core/compaction/utils.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
13
- - [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`ContextCompactionEntry`, `CompactionEntry`, `BranchSummaryEntry`) and active-context rebuild logic
12
+ - [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`ContextCompactionEntry`, `BranchSummaryEntry`) and active-context rebuild logic
14
13
  - [`packages/coding-agent/src/core/extensions/types.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/extensions/types.ts) - Extension event types
15
14
 
16
15
  For TypeScript definitions in your project, inspect `node_modules/@bastani/atomic/dist/`.
17
16
 
18
17
  ## Overview
19
18
 
20
- Atomic has three compaction/summarization mechanisms:
19
+ Atomic has one context compaction behavior and one separate branch-summarization mechanism:
21
20
 
22
21
  | Mechanism | Trigger | Purpose |
23
22
  |-----------|---------|---------|
24
- | Verbatim Compaction (default context compaction) | Context exceeds threshold, context overflow, or `/compact` | Delete safe old transcript entries/content blocks while retaining surviving content verbatim |
25
- | Summary compaction internals | Legacy core APIs and legacy extension hooks | Summarize old messages into replacement context |
23
+ | Verbatim Compaction (context compaction) | Context exceeds threshold, context overflow, or `/compact` | Delete safe old transcript entries/content blocks while retaining surviving content verbatim |
26
24
  | Branch summarization | `/tree` navigation | Preserve useful context when switching branches |
27
25
 
26
+ Summary compaction — the earlier behavior that generated replacement prose — has been removed as an active runtime path. Historical JSONL lines with `type:"compaction"` remain readable on disk but are not injected into active LLM context. See [Legacy Summary Compaction (Retired)](#legacy-summary-compaction-retired) for a comparison and historical reference.
27
+
28
28
  `/compact` has no user-facing arguments. It uses a fixed internal prompt, transcript-bound inspection/deletion tools, local validation, and a `context_compaction` session entry. Auto-compaction uses the same deletion-only path.
29
29
 
30
+ ## Verbatim vs. Summary Compaction
31
+
32
+ Atomic uses Verbatim Compaction as its sole compaction strategy. The following comparison explains why, and documents what legacy summary compaction used to do.
33
+
34
+ | Property | Verbatim Compaction | Summary Compaction (retired) |
35
+ |----------|---------------------|------------------------------|
36
+ | Mechanism | Deletes entries/content blocks | Rewrites earlier context into new prose |
37
+ | Surviving content | Exact original transcript content | Generated summary text |
38
+ | File paths / commands / errors | Kept exact or deleted | Can be paraphrased or omitted |
39
+ | Line numbers and stack traces | Kept exact or deleted | Can be distorted in summary |
40
+ | Auditability | Deleted targets are listed and inspectable | Omission/paraphrase is hard to audit |
41
+ | Recoverability | Pre-compaction backup snapshot; deleted targets listed in entry | Generated summary cannot be losslessly reversed |
42
+ | Failure mode | Needed context may be deleted (mitigated by validation and backups) | Needed context may be silently distorted |
43
+ | Atomic end state | **Canonical behavior** | **Removed runtime behavior** |
44
+
45
+ Coding agents depend on exact file paths (`src/foo.ts:42`), exact commands (`npm run build`), exact error strings, and exact line numbers. A generated summary that says "an error occurred in the auth module" instead of recording the actual stack trace loses irreplaceable information. Deletion is honest: what remains is unchanged, and what was deleted is listed in an inspectable `context_compaction` entry.
46
+
47
+ Deletion can still lose needed context. Atomic mitigates this with:
48
+ - **Local validation**: Protected entries (user tasks, recent context, unresolved errors, failed commands) cannot be deleted in standard mode.
49
+ - **Pre-compaction backups**: A `.compact.bak` snapshot is written before each compaction for persisted sessions.
50
+ - **Auditable targets**: The `context_compaction` entry records every deleted entry/content-block ID.
51
+
30
52
  ## Default Context Compaction (Verbatim Compaction)
31
53
 
32
54
  ### What "Verbatim" Means
@@ -36,7 +58,7 @@ Verbatim Compaction never asks a model to rewrite the conversation for the main
36
58
  - **Whole entries** such as an old assistant message or obsolete tool result.
37
59
  - **Individual content blocks** inside a multi-block message, such as one stale tool call block while keeping other blocks.
38
60
 
39
- Atomic records those targets in an append-only `context_compaction` entry. When the active branch is rebuilt, Atomic filters the targeted objects out and reuses every retained entry/content block unchanged. There is no generated summary, no paraphrasing, and no replacement message inserted by default.
61
+ Atomic records those targets in an append-only `context_compaction` entry. When the active branch is rebuilt, Atomic filters the targeted objects out and reuses every retained entry/content block unchanged. There is no generated summary, no paraphrasing, and no replacement message inserted.
40
62
 
41
63
  The raw session JSONL remains append-only. Deleted objects stay available in the stored session file and backup snapshot; they are only omitted from future active LLM context on that branch.
42
64
 
@@ -50,11 +72,34 @@ contextTokens > contextWindow - reserveTokens
50
72
 
51
73
  By default, `reserveTokens` is 16384 tokens. Configure it in `~/.atomic/agent/settings.json` or `<project-dir>/.atomic/settings.json`; legacy `.pi` paths are also supported. This leaves room for the LLM's response.
52
74
 
53
- You can also trigger compaction manually with `/compact`. Custom summary instructions are no longer accepted because default compaction is deletion-only and retained transcript content stays verbatim.
75
+ You can also trigger compaction manually with `/compact`. Custom summary instructions are not accepted because Verbatim Compaction is deletion-only and retained transcript content stays verbatim.
54
76
 
55
77
  ### How It Works
56
78
 
57
- 1. **Collect active branch context.** Atomic walks the current session branch, applies any earlier `context_compaction` logical deletions, and respects legacy summary-compaction boundaries if they exist.
79
+ ```mermaid
80
+ %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#f8f9fa','primaryTextColor':'#2c3e50','primaryBorderColor':'#4a5568','lineColor':'#4a90e2','secondaryColor':'#ffffff','tertiaryColor':'#e9ecef'}}}%%
81
+ flowchart TD
82
+ A["🗣 /compact · auto-threshold · auto-overflow"]
83
+ B["collect active branch context\napply prior context_compaction deletions"]
84
+ C["build compactable transcript\n(entry IDs · roles · token estimates · text)"]
85
+ D["mark protected context\n(user tasks · recent 5 entries · errors · failed commands)"]
86
+ E["write temporary transcript file\nsend manifest to planner"]
87
+ F["internal deletion planner\nfixed prompt · lowest thinking level"]
88
+ G["transcript-bound tools\ncontext_search · context_read · context_delete · context_grep_delete"]
89
+ H["validateContextDeletionRequest()\nlocal airlock: unknown · protected · orphaning · empty checks"]
90
+ I["write pre-compaction backup snapshot"]
91
+ J["appendContextCompaction()\ndeletedTargets · protectedEntryIds · stats · backupPath"]
92
+ K["buildSessionContext()\nfilter deleted targets · reuse survivors verbatim"]
93
+ L["emit session_compact event\nContextCompactionResult · contextCompactionEntry"]
94
+
95
+ A --> B --> C --> D --> E --> F
96
+ F <--> G
97
+ G --> H
98
+ H -->|validated| I --> J --> K --> L
99
+ H -->|rejected| F
100
+ ```
101
+
102
+ 1. **Collect active branch context.** Atomic walks the current session branch and applies any earlier `context_compaction` logical deletions.
58
103
  2. **Build a compactable transcript.** Each compactable entry includes a stable `entryId`, role, token estimate, full text, content-block indexes, tool-call IDs, and tool-result links.
59
104
  3. **Mark protected context.** Standard compaction protects user instructions, custom messages, branch/summary messages, the last five context-eligible entries, unresolved assistant/tool errors, and failed bash executions.
60
105
  4. **Write a temporary transcript file.** The compaction assistant receives a compact manifest plus the path to a JSONL transcript file. It should inspect with tools instead of loading the whole transcript into prompt context.
@@ -82,7 +127,7 @@ Tool calls are cumulative during one compaction run. The assistant can apply sev
82
127
  In standard mode, Atomic protects:
83
128
 
84
129
  - User messages and user-provided task context.
85
- - Custom messages, branch summaries, and existing summary-compaction messages.
130
+ - Custom messages, branch summaries, and branch-summary context.
86
131
  - The last five context-eligible entries on the active branch.
87
132
  - Assistant messages whose stop reason is an error.
88
133
  - Tool results marked as errors.
@@ -172,111 +217,80 @@ No generated summary is inserted. Every surviving entry/content block is reused
172
217
  verbatim; deleted objects are simply omitted from the active LLM context.
173
218
  ```
174
219
 
175
- ## Summary Compaction Internals
220
+ ## Extension Hooks for Compaction
176
221
 
177
- The older summarization pipeline still exists in the core compaction module and for legacy extension hook types, but `/compact` and auto-compaction no longer use it by default.
222
+ Extensions can observe, cancel, or contribute exact deletion targets to the compaction pipeline. They cannot provide generated summaries.
178
223
 
179
- ```text
180
- Before summary compaction:
224
+ ### session_before_compact
181
225
 
182
- entry: 0 1 2 3 4 5 6 7 8 9
183
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┐
184
- │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
185
- └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
186
- └────────┬───────┘ └──────────────┬──────────────┘
187
- messagesToSummarize kept messages
188
-
189
- firstKeptEntryId (entry 4)
226
+ Fired before the internal deletion planner runs. Extensions can cancel compaction or provide their own validated deletion request.
190
227
 
191
- After compaction (new entry appended):
228
+ ```typescript
229
+ pi.on("session_before_compact", async (event, ctx) => {
230
+ const { preparation, branchEntries, reason, mode, signal } = event;
192
231
 
193
- entry: 0 1 2 3 4 5 6 7 8 9 10
194
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
195
- hdr usr ass tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
196
- └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
197
- └──────────┬──────┘ └──────────────────────┬───────────────────┘
198
- not sent to LLM sent to LLM
199
-
200
- starts from firstKeptEntryId
232
+ // preparation.transcript.entries - entries eligible for deletion
233
+ // preparation.transcript.protectedEntryIds - entries that cannot be deleted in standard mode
234
+ // preparation.transcript.tokensBefore - context token estimate before compaction
235
+ // branchEntries - all entries on current branch
236
+ // reason - "manual" | "threshold" | "overflow"
237
+ // mode - "standard" | "critical_overflow"
201
238
 
202
- What the LLM sees:
239
+ // Cancel compaction:
240
+ return { cancel: true };
203
241
 
204
- ┌────────┬─────────┬─────┬─────┬──────┬──────┬─────┬──────┐
205
- system │ summary │ usr │ ass │ tool │ tool │ ass │ tool │
206
- └────────┴─────────┴─────┴─────┴──────┴──────┴─────┴──────┘
207
- ↑ ↑ └─────────────────┬────────────────┘
208
- prompt from cmp messages from firstKeptEntryId
242
+ // Or provide a deletion request (Atomic validates it locally before persisting):
243
+ return {
244
+ deletionRequest: {
245
+ deletions: [
246
+ { kind: "entry", entryId: "abc123" },
247
+ { kind: "content_block", entryId: "def456", blockIndex: 2 },
248
+ ],
249
+ },
250
+ };
251
+ });
209
252
  ```
210
253
 
211
- On repeated legacy summary compactions, the summarized span starts at the previous compaction's kept boundary (`firstKeptEntryId`), not at the compaction entry itself, falling back to the entry after the previous compaction if that kept entry cannot be found in the path. This preserves messages that survived the earlier compaction by including them in the next summarization pass as well. Atomic also recalculates `tokensBefore` from the rebuilt session context before writing the new `CompactionEntry`, so the token count reflects the actual pre-compaction context being replaced.
212
-
213
- ### Split Turns
254
+ If `{ cancel: true }` is returned, compaction aborts with a cancellation error. If `{ deletionRequest }` is returned, Atomic validates it through the same local airlock as model-proposed deletions unknown IDs, protected targets, orphaning, and empty-context plans are rejected and skips the internal planner. If nothing is returned, the internal planner runs normally.
214
255
 
215
- A "turn" starts with a user message and includes all assistant responses and tool calls until the next user message. The legacy summary pipeline normally cuts at turn boundaries.
256
+ ### session_compact
216
257
 
217
- When a single turn exceeds `keepRecentTokens`, the cut point lands mid-turn at an assistant message. This is a "split turn":
258
+ Fired after compaction succeeds and the `context_compaction` entry is persisted.
218
259
 
219
- ```text
220
- Split turn (one huge turn exceeds budget):
221
-
222
- entry: 0 1 2 3 4 5 6 7 8
223
- ┌─────┬─────┬─────┬──────┬─────┬──────┬──────┬─────┬──────┐
224
- hdr usr ass tool │ ass │ tool │ tool │ ass │ tool │
225
- └─────┴─────┴─────┴──────┴─────┴──────┴──────┴─────┴──────┘
226
- ↑ ↑
227
- turnStartIndex = 1 firstKeptEntryId = 7
228
- │ │
229
- └──── turnPrefixMessages (1-6) ───────┘
230
- └── kept (7-8)
231
-
232
- isSplitTurn = true
233
- messagesToSummarize = [] (no complete turns before)
234
- turnPrefixMessages = [usr, ass, tool, ass, tool, tool]
260
+ ```typescript
261
+ pi.on("session_compact", async (event, ctx) => {
262
+ // event.result - ContextCompactionResult
263
+ // event.contextCompactionEntry - the saved ContextCompactionEntry
264
+ // event.reason - "manual" | "threshold" | "overflow"
265
+ // event.fromExtension - true if extension provided the deletionRequest
266
+
267
+ const { result } = event;
268
+ ctx.ui.notify(
269
+ `Compaction: deleted ${result.stats.objectsDeleted} objects, ` +
270
+ `${result.stats.percentReduction}% token reduction`,
271
+ "info",
272
+ );
273
+ });
235
274
  ```
236
275
 
237
- For split turns, Atomic generates two summaries and merges them:
238
-
239
- 1. **History summary**: Previous context (if any)
240
- 2. **Turn prefix summary**: The early part of the split turn
241
-
242
- ### Cut Point Rules
243
-
244
- Valid legacy summary-compaction cut points are:
276
+ ### ctx.compact()
245
277
 
246
- - User messages
247
- - Assistant messages
248
- - BashExecution messages
249
- - Custom messages (custom_message, branch_summary)
250
-
251
- Never cut at tool results because they must stay with their tool call.
252
-
253
- ### CompactionEntry Structure
254
-
255
- Defined in [`session-manager.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/session-manager.ts):
278
+ Trigger Verbatim Compaction without awaiting completion. See [Extensions](/extensions) for full `ctx.compact()` documentation.
256
279
 
257
280
  ```typescript
258
- interface CompactionEntry<T = unknown> {
259
- type: "compaction";
260
- id: string;
261
- parentId: string | null;
262
- timestamp: string; // ISO timestamp
263
- summary: string;
264
- firstKeptEntryId: string;
265
- tokensBefore: number;
266
- fromHook?: boolean; // true if provided by extension (legacy field name)
267
- details?: T; // implementation-specific data
268
- }
269
-
270
- // Legacy summary compaction uses this for details (from compaction.ts):
271
- interface CompactionDetails {
272
- readFiles: string[];
273
- modifiedFiles: string[];
274
- }
281
+ ctx.compact({
282
+ onComplete: (result) => {
283
+ ctx.ui.notify(`Compacted: deleted ${result.stats.objectsDeleted} objects`, "info");
284
+ },
285
+ onError: (error) => {
286
+ ctx.ui.notify(`Compaction failed: ${error.message}`, "error");
287
+ },
288
+ });
275
289
  ```
276
290
 
277
- Extensions can store any JSON-serializable data in `details`. The legacy summary compaction pipeline tracks file operations, but custom extension implementations can use their own structure.
291
+ `ctx.compact()` does not accept custom instructions. Verbatim Compaction uses a fixed internal prompt; no custom summary text can be injected.
278
292
 
279
- See [`prepareCompaction()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) and [`compact()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) for the implementation.
293
+ See [examples/extensions/trigger-compact.ts](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/examples/extensions/trigger-compact.ts) for a full example.
280
294
 
281
295
  ## Branch Summarization
282
296
 
@@ -284,6 +298,8 @@ See [`prepareCompaction()`](https://github.com/bastani-inc/atomic/blob/main/pack
284
298
 
285
299
  When you use `/tree` to navigate to a different branch, Atomic offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
286
300
 
301
+ Branch summarization is a separate mechanism from context compaction. It generates a summary of the abandoned branch path and injects it into the new branch position. This is appropriate here because the alternative (losing branch context entirely on navigation) is worse than a lossy summary.
302
+
287
303
  ### How It Works
288
304
 
289
305
  1. **Find common ancestor**: Deepest node shared by old and new positions
@@ -292,6 +308,20 @@ When you use `/tree` to navigate to a different branch, Atomic offers to summari
292
308
  4. **Generate summary**: Call LLM with structured format
293
309
  5. **Append entry**: Save `BranchSummaryEntry` at navigation point
294
310
 
311
+ ```mermaid
312
+ %%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#f8f9fa','primaryTextColor':'#2c3e50','primaryBorderColor':'#4a5568','lineColor':'#4a90e2','secondaryColor':'#ffffff','tertiaryColor':'#e9ecef'}}}%%
313
+ flowchart TD
314
+ A["user navigates /tree\nold leaf → new target"]
315
+ B["find common ancestor"]
316
+ C["collect abandoned branch entries\n(old leaf → common ancestor)"]
317
+ D["prepare with token budget\n(newest first)"]
318
+ E["generate branch summary\nLLM call · structured format"]
319
+ F["append BranchSummaryEntry\nat common ancestor or new target"]
320
+ G["navigate to new target\nbranch summary context carried forward"]
321
+
322
+ A --> B --> C --> D --> E --> F --> G
323
+ ```
324
+
295
325
  ```text
296
326
  Tree before navigation:
297
327
 
@@ -311,12 +341,12 @@ After navigation with summary:
311
341
 
312
342
  ### Cumulative File Tracking
313
343
 
314
- Legacy summary compaction and branch summarization track files cumulatively. When generating a summary, Atomic extracts file operations from:
344
+ Branch summarization tracks files cumulatively. When generating a summary, Atomic extracts file operations from:
315
345
 
316
346
  - Tool calls in the messages being summarized
317
- - Previous compaction or branch summary `details` (if any)
347
+ - Previous branch summary `details` (if any)
318
348
 
319
- This means file tracking accumulates across multiple summary compactions or nested branch summaries, preserving the full history of read and modified files.
349
+ This means file tracking accumulates across nested branch summaries, preserving the full history of read and modified files.
320
350
 
321
351
  ### BranchSummaryEntry Structure
322
352
 
@@ -341,13 +371,13 @@ interface BranchSummaryDetails {
341
371
  }
342
372
  ```
343
373
 
344
- Same as legacy summary compaction, extensions can store custom data in `details`.
374
+ Extensions can store custom data in `details`.
345
375
 
346
376
  See [`collectEntriesForBranchSummary()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) for the implementation.
347
377
 
348
- ## Legacy Summary Format
378
+ ## Branch Summary Format
349
379
 
350
- Legacy summary compaction and branch summarization use the same structured format:
380
+ Branch summarization uses a structured format:
351
381
 
352
382
  ```markdown
353
383
  ## Goal
@@ -385,9 +415,9 @@ path/to/changed.ts
385
415
  </modified-files>
386
416
  ```
387
417
 
388
- ### Message Serialization
418
+ ### Message Serialization for Branch Summaries
389
419
 
390
- Before legacy summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
420
+ Before branch summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
391
421
 
392
422
  ```text
393
423
  [User]: What they said
@@ -399,81 +429,9 @@ Before legacy summarization, messages are serialized to text via [`serializeConv
399
429
 
400
430
  This prevents the model from treating it as a conversation to continue.
401
431
 
402
- Tool results are truncated to 2000 characters during serialization. Content beyond that limit is replaced with a marker indicating how many characters were truncated. This keeps summarization requests within reasonable token budgets, since tool results (especially from `read` and `bash`) are typically the largest contributors to context size.
432
+ Tool results are truncated to 2000 characters during serialization. Content beyond that limit is replaced with a marker indicating how many characters were truncated.
403
433
 
404
- ## Custom Summarization via Extensions
405
-
406
- Extensions can still customize the legacy summary compaction pipeline and branch summarization. Default `/compact` and auto-compaction use deletion-only Verbatim Compaction and do not call summary customization hooks. See [`extensions/types.ts`](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/src/core/extensions/types.ts) for event type definitions.
407
-
408
- ### session_before_compact
409
-
410
- Fired before legacy summary compaction. Can cancel or provide custom summary. See `SessionBeforeCompactEvent` and `CompactionPreparation` in the types file.
411
-
412
- ```typescript
413
- pi.on("session_before_compact", async (event, ctx) => {
414
- const { preparation, branchEntries, customInstructions, signal } = event;
415
-
416
- // preparation.messagesToSummarize - messages to summarize
417
- // preparation.turnPrefixMessages - split turn prefix (if isSplitTurn)
418
- // preparation.previousSummary - previous compaction summary
419
- // preparation.fileOps - extracted file operations
420
- // preparation.tokensBefore - context tokens before compaction
421
- // preparation.firstKeptEntryId - where kept messages start
422
- // preparation.settings - compaction settings
423
-
424
- // branchEntries - all entries on current branch (for custom state)
425
- // signal - AbortSignal (pass to LLM calls)
426
-
427
- // Cancel:
428
- return { cancel: true };
429
-
430
- // Custom summary:
431
- return {
432
- compaction: {
433
- summary: "Your summary...",
434
- firstKeptEntryId: preparation.firstKeptEntryId,
435
- tokensBefore: preparation.tokensBefore,
436
- details: { /* custom data */ },
437
- }
438
- };
439
- });
440
- ```
441
-
442
- #### Converting Messages to Text
443
-
444
- To generate a summary with your own model, convert messages to text using `serializeConversation`:
445
-
446
- ```typescript
447
- import { convertToLlm, serializeConversation } from "@bastani/atomic";
448
-
449
- pi.on("session_before_compact", async (event, ctx) => {
450
- const { preparation } = event;
451
-
452
- // Convert AgentMessage[] to Message[], then serialize to text
453
- const conversationText = serializeConversation(
454
- convertToLlm(preparation.messagesToSummarize)
455
- );
456
- // Returns:
457
- // [User]: message text
458
- // [Assistant thinking]: thinking content
459
- // [Assistant]: response text
460
- // [Assistant tool calls]: read(path="..."); bash(command="...")
461
- // [Tool result]: output text
462
-
463
- // Now send to your model for summarization
464
- const summary = await myModel.summarize(conversationText);
465
-
466
- return {
467
- compaction: {
468
- summary,
469
- firstKeptEntryId: preparation.firstKeptEntryId,
470
- tokensBefore: preparation.tokensBefore,
471
- }
472
- };
473
- });
474
- ```
475
-
476
- See [custom-compaction.ts](https://github.com/bastani-inc/atomic/blob/main/packages/coding-agent/examples/extensions/custom-compaction.ts) for a complete example using a different model.
434
+ ## Extension Hooks for Branch Summarization
477
435
 
478
436
  ### session_before_tree
479
437
 
@@ -514,8 +472,7 @@ Configure compaction in `~/.atomic/agent/settings.json` or `<project-dir>/.atomi
514
472
  {
515
473
  "compaction": {
516
474
  "enabled": true,
517
- "reserveTokens": 16384,
518
- "keepRecentTokens": 20000
475
+ "reserveTokens": 16384
519
476
  }
520
477
  }
521
478
  ```
@@ -524,6 +481,78 @@ Configure compaction in `~/.atomic/agent/settings.json` or `<project-dir>/.atomi
524
481
  |---------|---------|-------------|
525
482
  | `enabled` | `true` | Enable automatic Verbatim Compaction. |
526
483
  | `reserveTokens` | `16384` | Tokens to reserve for the next LLM response; auto-compaction starts when context usage exceeds `contextWindow - reserveTokens`. |
527
- | `keepRecentTokens` | `20000` | Legacy summary-compaction retained-token budget. Default Verbatim Compaction protects recent entries structurally instead of using this as a token cut point. |
528
484
 
529
485
  Disable auto-compaction with `"enabled": false`. You can still compact manually with `/compact`.
486
+
487
+ ## Legacy Summary Compaction (Retired)
488
+
489
+ Summary compaction — an earlier behavior that generated replacement prose for older context — has been removed as an active runtime path in Atomic. This section documents it for historical reference only.
490
+
491
+ ### What it did
492
+
493
+ The summary compaction pipeline:
494
+ 1. Selected a cut point (user message boundary) called `firstKeptEntryId`.
495
+ 2. Passed all messages before that cut point to an LLM to generate a replacement summary.
496
+ 3. Appended a `CompactionEntry` with `type:"compaction"` to the session JSONL.
497
+ 4. When rebuilding active context, injected a `compactionSummary` message at the boundary.
498
+
499
+ ```text
500
+ (Historical — no longer the active behavior)
501
+
502
+ Before summary compaction:
503
+
504
+ entry: 0 1 2 3 4 5 6 7 8 9
505
+ ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┐
506
+ │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
507
+ └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
508
+ └────────┬───────┘ └──────────────┬──────────────┘
509
+ messagesToSummarize kept messages
510
+
511
+ firstKeptEntryId (entry 4)
512
+
513
+ After compaction (new entry appended):
514
+
515
+ entry: 0 1 2 3 4 5 6 7 8 9 10
516
+ ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
517
+ │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
518
+ └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
519
+ └──────────┬──────┘ └──────────────────────┬───────────────────┘
520
+ not sent to LLM sent to LLM
521
+
522
+ starts from firstKeptEntryId
523
+
524
+ What the LLM saw:
525
+
526
+ ┌────────┬─────────┬─────┬─────┬──────┬──────┬─────┬──────┐
527
+ │ system │ summary │ usr │ ass │ tool │ tool │ ass │ tool │
528
+ └────────┴─────────┴─────┴─────┴──────┴──────┴─────┴──────┘
529
+ ↑ ↑ └─────────────────┬────────────────┘
530
+ prompt from cmp messages from firstKeptEntryId
531
+ ```
532
+
533
+ ### Why it was removed
534
+
535
+ The core problem: a generated summary can paraphrase or omit exact file paths (`src/auth/middleware.ts:87`), commands (`npm run build -- --watch`), error strings, and line numbers. For coding agents, this loss of precision frequently causes confusion and regressions. Verbatim Compaction is honest: what remains is unchanged, and what was deleted is recorded.
536
+
537
+ See [Verbatim vs. Summary Compaction](#verbatim-vs-summary-compaction) for the full comparison.
538
+
539
+ ### Historical entry types
540
+
541
+ `type:"compaction"` JSONL lines may exist in sessions created before the removal. They remain readable on disk and visible in session exports, but Atomic does not inject them as active LLM context. If you encounter sessions with these entries, they are safe to leave in place.
542
+
543
+ `type:"compaction"` entry structure (historical):
544
+ ```typescript
545
+ interface CompactionEntry {
546
+ type: "compaction";
547
+ id: string;
548
+ parentId: string | null;
549
+ timestamp: string;
550
+ summary: string; // generated replacement prose
551
+ firstKeptEntryId: string; // cut point boundary
552
+ tokensBefore: number;
553
+ fromHook?: boolean;
554
+ details?: unknown;
555
+ }
556
+ ```
557
+
558
+ This entry type is no longer produced by Atomic. Extension hooks that returned `{ compaction: { summary, firstKeptEntryId, tokensBefore } }` no longer have effect; update extensions to use the new `{ cancel: true }` or `{ deletionRequest }` hook returns instead.
@@ -8,7 +8,7 @@ Extensions are TypeScript modules that extend Atomic's behavior. They can subscr
8
8
 
9
9
  **Key capabilities:**
10
10
  - **Custom tools** - Register tools the LLM can call via `pi.registerTool()`
11
- - **Event interception** - Block or modify tool calls, inject context, customize legacy summary compaction and branch summaries
11
+ - **Event interception** - Block or modify tool calls, inject context, observe/cancel deletion-only compaction, and customize branch summaries
12
12
  - **User interaction** - Prompt users via `ctx.ui` (select, confirm, input, notify)
13
13
  - **Custom UI components** - Full TUI components with keyboard input via `ctx.ui.custom()` for complex interactions
14
14
  - **Custom commands** - Register commands like `/mycommand` via `pi.registerCommand()`
@@ -19,7 +19,7 @@ Extensions are TypeScript modules that extend Atomic's behavior. They can subscr
19
19
  - Permission gates (confirm before `rm -rf`, `sudo`, etc.)
20
20
  - Git checkpointing (stash at each turn, restore on branch)
21
21
  - Path protection (block writes to `.env`, `node_modules/`)
22
- - Legacy custom summary compaction (summarize older context your way)
22
+ - Compaction policies (cancel compaction or provide exact deletion targets)
23
23
  - Conversation summaries (see `summarize.ts` example)
24
24
  - Interactive tools (questions, wizards, custom dialogs)
25
25
  - Stateful tools (todo lists, connection pools)
@@ -322,11 +322,9 @@ user sends another prompt ◄─────────────────
322
322
  └─► resources_discover { reason: "startup" }
323
323
 
324
324
  /compact or auto-compaction
325
- └─► compaction_start / compaction_end (deletion-only context compaction)
326
-
327
- legacy summary compaction APIs
328
- ├─► session_before_compact (can cancel or customize)
329
- └─► session_compact
325
+ ├─► compaction_start / compaction_end (deletion-only context compaction status)
326
+ ├─► session_before_compact (can cancel or provide a deletion request)
327
+ └─► session_compact (after the context_compaction entry is persisted)
330
328
 
331
329
  /tree navigation
332
330
  ├─► session_before_tree (can cancel or customize)
@@ -416,28 +414,41 @@ Do cleanup work in `session_shutdown`, then reestablish any in-memory state in `
416
414
 
417
415
  #### session_before_compact / session_compact
418
416
 
419
- Fired by the legacy summary compaction pipeline. `/compact` and auto-compaction now use deletion-only context compaction by default, so extensions should not rely on these events for default compaction. See [Compaction](/compaction) for details.
417
+ Fired by `/compact` and auto-compaction. Compaction is deletion-only: extensions can cancel the run or return exact entry/content-block deletion targets for Atomic to validate locally. Extensions cannot return generated summaries.
420
418
 
421
419
  ```typescript
422
420
  pi.on("session_before_compact", async (event, ctx) => {
423
- const { preparation, branchEntries, customInstructions, signal } = event;
421
+ const { preparation, branchEntries, reason, mode, signal } = event;
422
+ const { transcript } = preparation;
423
+
424
+ // transcript.entries - compactable entries on the active branch
425
+ // transcript.protectedEntryIds - entries protected from standard compaction
426
+ // transcript.tokensBefore - token estimate before compaction
427
+ // branchEntries - raw session entries on the current branch
428
+ // reason - "manual" | "threshold" | "overflow"
429
+ // mode - "standard" | "critical_overflow"
430
+
431
+ if (signal.aborted) return { cancel: true };
424
432
 
425
- // Cancel:
433
+ // Cancel compaction:
426
434
  return { cancel: true };
427
435
 
428
- // Custom summary:
436
+ // Or provide a deletion request. Atomic validates IDs, protected targets,
437
+ // tool-call/tool-result pairing, and non-empty remaining context before saving.
429
438
  return {
430
- compaction: {
431
- summary: "...",
432
- firstKeptEntryId: preparation.firstKeptEntryId,
433
- tokensBefore: preparation.tokensBefore,
434
- }
439
+ deletionRequest: {
440
+ deletions: [
441
+ { kind: "entry", entryId: "abc123", rationale: "Old successful command output" },
442
+ { kind: "content_block", entryId: "def456", blockIndex: 2, rationale: "Verbose obsolete log" },
443
+ ],
444
+ },
435
445
  };
436
446
  });
437
447
 
438
448
  pi.on("session_compact", async (event, ctx) => {
439
- // event.compactionEntry - the saved compaction
440
- // event.fromExtension - whether extension provided it
449
+ // event.result - ContextCompactionResult with deletedTargets/protectedEntryIds/stats
450
+ // event.contextCompactionEntry - the saved context_compaction entry
451
+ // event.fromExtension - true if session_before_compact provided deletionRequest
441
452
  });
442
453
  ```
443
454
 
@@ -963,7 +974,7 @@ ctx.compact({
963
974
  });
964
975
  ```
965
976
 
966
- `customInstructions` is deprecated. Passing a non-empty value to default compaction fails because Verbatim Compaction does not accept custom summary instructions.
977
+ Verbatim Compaction uses a fixed internal prompt; no custom summary text can be injected.
967
978
 
968
979
  ### ctx.getSystemPrompt()
969
980
 
@@ -2572,7 +2583,7 @@ All examples in [examples/extensions/](https://github.com/bastani-inc/atomic/tre
2572
2583
  | `prompt-customizer.ts` | Add context-aware tool guidance using `systemPromptOptions` | `on("before_agent_start")`, `BuildSystemPromptOptions` |
2573
2584
  | `file-trigger.ts` | File watcher triggers messages | `sendMessage` |
2574
2585
  | **Compaction & Sessions** |||
2575
- | `custom-compaction.ts` | Legacy custom compaction summary | `on("session_before_compact")` |
2586
+ | `custom-compaction.ts` | Custom deletion-request compaction policy | `on("session_before_compact")` |
2576
2587
  | `trigger-compact.ts` | Trigger compaction manually | `compact()` |
2577
2588
  | `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
2578
2589
  | `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |