README.md
1 # grounded-compaction 2 3 This extension can play two roles: 4 * Replace Pi's compaction summarizer with configurable model presets, custom summarization prompt contracts, and deterministic files-touched tracking that covers Pi native tools, RepoPrompt, and bash-derived file operations 5 * Augment branch summarization during `/tree` with the same files-touched grounding and optional replacement of the summarization prompt contract with a custom one 6 7 > ⚠ **May conflict with other compaction extensions**: this extension hooks `session_before_compact` and returns a custom compaction result. Any other extension that does the same (e.g. `agentic-compaction`) is incompatible. Having both active creates a race condition where the last handler to respond wins. Enable only one. 8 9 ## Why 10 11 Pi's native compaction [deterministically tracks](https://github.com/badlogic/pi-mono/blob/629341c18f3482d891b665a844975096b47b4779/packages/coding-agent/src/core/compaction/utils.ts#L74-L79) file activity from its built-in `read`, `write`, and `edit` tool calls. Operations through bash or custom tools like RepoPrompt are invisible to it. This extension uses a [shared collector](../../../packages/pi-files-touched/README.md) (`extensions/_shared/files-touched-core.ts`) that also covers RepoPrompt tools (`read_file`, `apply_edits`, `file_actions`, `git mv/rm`), bash patterns (`sed -i`, `mv`, `rm`, shell redirections, etc.), and normalizes all path spellings so the same file appears once regardless of how different tools referred to it. 12 13 Since compaction also [serializes messages to text](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/compaction.md#message-serialization) before summarizing, which entails that there is no prefix-cache opportunity cost to routing compaction to a cheaper or faster model, you may want to be able to do that sometimes or as a default policy. The "presets" grant that option. 14 15 ## Compaction and branch summarization 16 17 For background on Pi's compaction lifecycle, see the [compaction docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/compaction.md). Branch summarization is the summary generated when navigating `/tree` — effectively compaction in any direction across the session tree, rather than just forward along a session's chronology. This extension augments both. 18 19 ## Files 20 21 - **Config**: `config.json` (see `config.json.example` for presets) 22 - **Compaction prompt**: `compaction-prompt.md` (falls back to default embedded in [`index.ts`](index.ts) if blank or missing) 23 - **Branch-summary prompt**: `branch-summary-prompt.md` (falls back to Pi's stock branch summarization prompt if blank or missing) 24 - Examples: `compaction-prompt.md.example`, `branch-summary-prompt.md.example` 25 26 ## Config 27 28 ```json 29 { 30 "includeFilesTouched": { 31 "inCompactionSummary": true, 32 "inBranchSummary": true 33 }, 34 "defaultPreset": "current", 35 "presets": {} 36 } 37 ``` 38 39 ### `includeFilesTouched` 40 41 Controls files-touched grounding per feature. Accepts `true`, `false`, or an object with both fields required: 42 43 ```json 44 { "inCompactionSummary": true, "inBranchSummary": false } 45 ``` 46 47 Boolean applies to both; omitted defaults to both enabled. 48 49 For compaction, the manifest is passed into the summarizer prompt and a cumulative version is appended verbatim to the persisted summary. For branch summaries, the manifest is injected into the prompt instructions for Pi's native summarizer to reproduce. In both cases, the manifest also serves as a recall aid for the summarizer itself — file operations buried across many tool calls in a long context are easy to miss without an authoritative inventory. 50 51 ### `defaultPreset` and `presets` 52 53 These are compaction-only. `defaultPreset` controls which model runs `/compact` by default; an explicit `--preset <name>` or `-p <name>` always overrides it. 54 55 ```json 56 { 57 "defaultPreset": "fast", 58 "presets": { 59 "fast": { "model": "openai-codex/gpt-5.4-mini", "thinkingLevel": "low" }, 60 "deep": { "model": "anthropic/claude-opus-4-6", "thinkingLevel": "high" } 61 } 62 } 63 ``` 64 65 `"current"` uses the session's active model and thinking level. Preset lookup is deterministic: exact match → case-insensitive → prefix → normalized substring. Failed lookups fall back to the current session model with a warning. 66 67 ## `/compact` usage 68 69 ```text 70 /compact 71 /compact focus on parser regressions 72 /compact --preset cheap 73 /compact -p deep focus on parser regressions 74 ``` 75 76 Only a leading `--preset` / `-p` is special; everything after is freeform focus text passed to the summarizer. `--preset current` / `-p current` explicitly uses the session model even when `defaultPreset` names something else. 77 78 ## Branch-summary augmentation 79 80 During `/tree`, if the user chooses to summarize: 81 82 - If `branch-summary-prompt.md` has content, it replaces Pi's stock branch-summary instructions 83 - If files-touched grounding is enabled, the manifest is injected with instructions to reproduce it verbatim 84 - If neither is active, the extension does nothing and Pi's stock flow runs unmodified 85 - On any failure, the extension returns nothing and Pi's stock flow proceeds 86 87 The user's freeform focus text from the `/tree` prompt is preserved in either mode. 88 89 ### Why branch-summary control is narrower than compaction 90 91 For compaction, this extension fully owns the LLM call: it can select a different model via presets, control thinking level independently, and manage token budgets. A session running Opus with a high thinkingLevel can compact cheaply with Gemini Flash. 92 93 For branch summaries, Pi's `session_before_tree` hook only exposes prompt instruction overrides. The extension cannot control model selection, thinking level, or token budgeting for branch summaries without mutating persistent session state. Native branch summarization always uses the current session model with a fixed `maxTokens` of 2048 and no explicit reasoning level -- the thinking overhead is minimal, but the per-token cost of the base model still applies. At this time of writing there is no way to select a cheaper model for branch summaries from an extension. 94 95 ## How compaction summaries are structured 96 97 The extension mirrors Pi's stock compaction boundaries: `messagesToSummarize` for history, `turnPrefixMessages` for split-turn prefixes, and `previousSummary` for cumulative updates. On repeated compactions, that means resuming from the previous compaction's `firstKeptEntryId`, not from the compaction entry itself, and the files-touched manifests follow that same boundary. When files-touched is enabled, manifests are passed to the summarizer per-span and a cumulative whole-branch manifest is appended to the final persisted summary: 98 99 ````md 100 --- 101 102 ## Files touched (cumulative) 103 R=read, W=write, E=edit, M=move/rename, D=delete 104 105 ```text 106 RE src/foo.ts 107 W src/bar.ts 108 ``` 109 ```` 110 111 `compaction.details` records the model and thinking level that actually ran: 112 113 ```ts 114 { model: "provider/modelId", thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" } 115 ``` 116 117 ## Failure policy 118 119 **Compaction**: failed presets fall back to the session model. If the session model also fails after an explicit preset directive, compaction is cancelled to avoid leaking raw directive text. Aborts return cancellation quietly. 120 121 **Branch summary**: any failure returns `undefined` with a warning, letting Pi's stock flow proceed. 122 123 For npm installation and package-specific docs, see [`packages/pi-grounded-compaction/README.md`](../../packages/pi-grounded-compaction/README.md)