pi-midcompact 0.2.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/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # pi-midcompact
2
+
3
+ **Compress stale parts of a long Pi session without deleting the original history.**
4
+
5
+ Long-running work accumulates exploration, command output, rejected approaches, and completed phases. `pi-midcompact` lets you and the Agent replace only the parts you have reviewed with concise summaries, leaving the current task and important decisions in full context.
6
+
7
+ - Choose exactly which conversation ranges to compress.
8
+ - Review the proposed boundaries and summaries before anything changes.
9
+ - Keep the original Pi session entries available for later recall.
10
+ - Keep compression local to the current session-tree branch.
11
+
12
+ ## Install
13
+
14
+ From npm:
15
+
16
+ ```bash
17
+ pi install npm:pi-midcompact
18
+ ```
19
+
20
+ From GitHub:
21
+
22
+ ```bash
23
+ pi install git:github.com/frostime/pi-midcompact
24
+ ```
25
+
26
+ Restart Pi or run `/reload` after installation. The extension is built for Pi `0.84.x`.
27
+
28
+ ## Use It
29
+
30
+ Start a transaction at a natural breakpoint: the current work is complete enough to summarize, and Pi is idle. The current point becomes a frozen **anchor**. The Agent plans against that snapshot, so later planning discussion cannot accidentally become part of the compressed working context.
31
+
32
+ ### 1. Set the compression checkpoint
33
+
34
+ Run:
35
+
36
+ ```text
37
+ /midcompact
38
+ ```
39
+
40
+ Pi creates a temporary transaction after the anchor and tells the Agent how to plan the compression. No conversation is changed yet.
41
+
42
+ ### 2. Discuss what to compress with the Agent
43
+
44
+ Describe the goal in normal language. For example:
45
+
46
+ ```text
47
+ Compress the early repository exploration and routine command output.
48
+ Keep the user's requirements, the rejected database decision, and the final validation errors verbatim.
49
+ Aim for a moderate reduction, not the smallest possible context.
50
+ ```
51
+
52
+ The Agent locates relevant parts of the frozen conversation, proposes one or more ranges, and writes a summary for each range. You can ask it to preserve a specific message, split a range, or revise a summary.
53
+
54
+ ### 3. Review the proposal
55
+
56
+ Run:
57
+
58
+ ```text
59
+ /midcompact review
60
+ ```
61
+
62
+ The native TUI displays the frozen conversation as a linear timeline. Each item is marked either `KEEP` or as belonging to a proposed range. Review the range boundaries and the summary that will replace each range.
63
+
64
+ You can edit a selected summary or topic in the TUI. To change range boundaries or leave an important hole uncompressed, tell the Agent what to keep and ask it to revise the plan, then review it again.
65
+
66
+ ### 4. Commit the reviewed compression
67
+
68
+ When the plan is correct, run:
69
+
70
+ ```text
71
+ /midcompact commit
72
+ ```
73
+
74
+ This is deliberately a human command. The Agent cannot commit compression itself.
75
+
76
+ Pi returns to the anchor, discards the temporary planning branch, stores the reviewed compression state, and resumes work from the committed branch. Future model requests receive the selected old ranges as summaries instead of raw messages.
77
+
78
+ ![A compression transaction keeps planning separate from the working branch.](./figures/transaction-lifecycle.svg)
79
+
80
+ ### 5. Continue working or abort
81
+
82
+ Keep working normally after committing. If you decide not to compress, run:
83
+
84
+ ```text
85
+ /midcompact abort
86
+ ```
87
+
88
+ This returns to the anchor and discards the transaction without changing the active context.
89
+
90
+ ## What the Agent Does
91
+
92
+ During an active transaction, the Agent uses the `midcompact` tool against the frozen anchor snapshot:
93
+
94
+ ![How the Agent turns semantic judgment into a reviewed compression plan.](./figures/agent-planning.svg)
95
+
96
+ | Action | Purpose |
97
+ | --- | --- |
98
+ | `locate` | Finds likely conversation landmarks and shows readable previews. |
99
+ | `plan` | Adds, revises, removes, or displays proposed compression ranges and summaries. |
100
+ | `recall` | Searches committed summaries or temporarily retrieves original content from a compressed block. |
101
+
102
+ The Agent makes semantic decisions: which exploration is stale, which user requirements and decisions must stay visible, and what a useful summary needs to retain. The extension enforces the mechanical rules: ranges cannot overlap, incomplete tool exchanges cannot be compressed, and the Agent cannot bypass the human commit gate.
103
+
104
+ Temporary references such as `a0007` exist only during planning. They are not inserted into normal prompts or retained as permanent message identifiers.
105
+
106
+ ## What Happens Behind the Scenes
107
+
108
+ A committed compression does not rewrite or delete the Pi session.
109
+
110
+ ![Compression replaces a reviewed range only in later model requests.](./figures/context-projection.svg)
111
+
112
+ 1. `/midcompact` freezes the current session-tree leaf as the anchor and starts a temporary maintenance branch.
113
+ 2. The Agent and you discuss a draft on that branch. This planning chatter is abandoned at commit.
114
+ 3. `/midcompact commit` returns to the anchor and saves a branch-local `midcompact-state` entry containing the reviewed ranges and summaries.
115
+ 4. Before later model requests, the extension finds the exact selected raw message sequences and projects them into summary messages.
116
+ 5. The underlying session entries remain unchanged. If an exact match cannot be found, the extension keeps the raw messages rather than removing uncertain content.
117
+
118
+ This is why the process is both selective and reversible at the information-access level: a summary saves context, while the source history remains available through recall or the Pi session tree.
119
+
120
+ ## Review Controls
121
+
122
+ Inside `/midcompact review`:
123
+
124
+ ```text
125
+ n/p or Left/Right select a proposed range
126
+ Up/Down, j/k scroll
127
+ PgUp/PgDn page
128
+ x expand the selected range's atoms
129
+ e edit the selected summary
130
+ t edit the selected topic
131
+ d remove the selected range
132
+ Enter/Esc/q close
133
+ ```
134
+
135
+ ## Commands
136
+
137
+ | Command | Result |
138
+ | --- | --- |
139
+ | `/midcompact` | Starts a transaction at the current session-tree leaf. |
140
+ | `/midcompact review` | Opens the draft review timeline. |
141
+ | `/midcompact commit` | Commits the reviewed draft. Human only. |
142
+ | `/midcompact abort` | Abandons the transaction and returns to the anchor. |
143
+ | `/midcompact status` | Displays the current draft, or the committed compression state on this branch. |
144
+
145
+ The extension shows planning status in Pi's footer only while a transaction is active. It disappears after commit or abort.
146
+
147
+ ## Guarantees and Limits
148
+
149
+ - **Original history is retained.** Compression changes what later model requests see, not the stored Pi messages.
150
+ - **State is branch-local.** Navigating with `/tree` to a point before a committed state restores raw history; returning to its descendant restores the projection.
151
+ - **Human review is required.** The Agent can propose a plan but cannot execute `/midcompact commit`.
152
+ - **Tool protocol is protected.** Unknown, incomplete, or orphaned tool exchanges are not compressible.
153
+ - **Repeated transactions work.** Later transactions can compress newly accumulated raw context; existing summaries remain protected.
154
+ - **Native Pi `/compact` interaction needs more real-session validation.** Avoid relying on mixed automatic/native compaction behavior for critical work until it has been exercised in your environment.
155
+ - **Review is TUI-only.** There is no browser review interface in this version.
@@ -0,0 +1,118 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1300" height="450" viewBox="0 0 1300 450" role="img" aria-labelledby="title desc">
2
+ <title id="title">How the Agent locates a slice without injecting message IDs</title>
3
+ <desc id="desc">A continuous frozen conversation is shown without IDs on its units. The agent identifies a start and end landmark, locate returns temporary references for both, and plan combines those references, the slice between them, and a summary into a draft ready for human review.</desc>
4
+
5
+ <defs>
6
+ <marker id="arrow-slate" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto">
7
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#64748b"/>
8
+ </marker>
9
+ </defs>
10
+
11
+ <rect width="1300" height="450" fill="#ffffff"/>
12
+ <g font-family="Arial, Helvetica, sans-serif">
13
+ <text x="40" y="43" font-size="28" font-weight="700" fill="#172033">How the Agent locates a slice without injecting message IDs</text>
14
+ <text x="40" y="70" font-size="16" fill="#526176">Normal conversation stays untouched. The Agent describes a semantic landmark, locate resolves it to a temporary ref, and only those refs are used to define a candidate slice.</text>
15
+ <line x1="40" y1="92" x2="1260" y2="92" stroke="#d8dee8" stroke-width="1.5"/>
16
+
17
+ <text x="40" y="120" font-size="14" font-weight="700" fill="#526176">FROZEN CONVERSATION SNAPSHOT</text>
18
+
19
+ <g id="conversation-units">
20
+ <rect x="40" y="135" width="195" height="67" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.7"/>
21
+ <text x="58" y="159" font-size="12.5" font-weight="700" fill="#047857">KEEP USER</text>
22
+ <text x="58" y="183" font-size="15" fill="#172033">Project constraints</text>
23
+
24
+ <rect x="245" y="135" width="195" height="67" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="2.2"/>
25
+ <text x="263" y="159" font-size="12.5" font-weight="700" fill="#a16207">ASSISTANT</text>
26
+ <text x="263" y="183" font-size="15" fill="#172033">Source exploration</text>
27
+
28
+ <rect x="450" y="135" width="195" height="67" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="2.2"/>
29
+ <text x="468" y="159" font-size="12.5" font-weight="700" fill="#a16207">TOOL EXCHANGE</text>
30
+ <text x="468" y="183" font-size="15" fill="#172033">read, rg, test output</text>
31
+
32
+ <rect x="655" y="135" width="195" height="67" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="2.2"/>
33
+ <text x="673" y="159" font-size="12.5" font-weight="700" fill="#a16207">ASSISTANT</text>
34
+ <text x="673" y="183" font-size="15" fill="#172033">Compare approaches</text>
35
+
36
+ <rect x="860" y="135" width="195" height="67" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="2.2"/>
37
+ <text x="878" y="159" font-size="12.5" font-weight="700" fill="#a16207">ASSISTANT</text>
38
+ <text x="878" y="183" font-size="15" fill="#172033">Decision + validation</text>
39
+
40
+ <rect x="1065" y="135" width="195" height="67" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.7"/>
41
+ <text x="1083" y="159" font-size="12.5" font-weight="700" fill="#047857">KEEP USER</text>
42
+ <text x="1083" y="183" font-size="15" fill="#172033">Implement the change</text>
43
+ </g>
44
+
45
+ <g id="slice-boundaries">
46
+ <line x1="342" y1="202" x2="342" y2="221" stroke="#d97706" stroke-width="2"/>
47
+ <rect x="276" y="221" width="132" height="22" rx="11" fill="#fff7ed" stroke="#d97706" stroke-width="1.2"/>
48
+ <text x="342" y="237" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">start boundary</text>
49
+
50
+ <line x1="957" y1="202" x2="957" y2="221" stroke="#d97706" stroke-width="2"/>
51
+ <rect x="891" y="221" width="132" height="22" rx="11" fill="#fff7ed" stroke="#d97706" stroke-width="1.2"/>
52
+ <text x="957" y="237" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">end boundary</text>
53
+
54
+ <path d="M 245 250 L 245 260 L 1055 260 L 1055 250" fill="none" stroke="#d97706" stroke-width="2"/>
55
+ <text x="650" y="281" text-anchor="middle" font-size="14" fill="#8a5808">candidate slice: every conversation atom from the start boundary through the end boundary</text>
56
+ </g>
57
+
58
+ <g id="planning-process">
59
+ <g id="choose-start">
60
+ <circle cx="54" cy="316" r="13" fill="#2563eb"/>
61
+ <text x="54" y="321" text-anchor="middle" font-size="14" font-weight="700" fill="#ffffff">1</text>
62
+ <text x="76" y="321" font-size="16" font-weight="700" fill="#173b7a">Choose a start landmark</text>
63
+ <text x="40" y="346" font-size="13.5" fill="#526176">Marks this phase stale.</text>
64
+ <text x="40" y="366" font-size="13.5" fill="#526176">Its start can be a user message,</text>
65
+ <text x="40" y="385" font-size="13.5" fill="#526176">assistant reply, or tool exchange.</text>
66
+ </g>
67
+
68
+ <line x1="236" y1="347" x2="269" y2="347" stroke="#64748b" stroke-width="2.3" marker-end="url(#arrow-slate)"/>
69
+
70
+ <g id="locate-start">
71
+ <circle cx="290" cy="316" r="13" fill="#d97706"/>
72
+ <text x="290" y="321" text-anchor="middle" font-size="14" font-weight="700" fill="#ffffff">2</text>
73
+ <text x="312" y="321" font-size="16" font-weight="700" fill="#7c4400">locate finds the node</text>
74
+ <text x="276" y="346" font-size="13.5" fill="#526176">locate("source exploration")</text>
75
+ <rect x="276" y="357" width="176" height="32" rx="5" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
76
+ <text x="290" y="379" font-size="14" fill="#172033"><tspan font-weight="700">start ref:</tspan><tspan fill="#9a3412"> a0007</tspan></text>
77
+ </g>
78
+
79
+ <line x1="462" y1="347" x2="495" y2="347" stroke="#64748b" stroke-width="2.3" marker-end="url(#arrow-slate)"/>
80
+
81
+ <g id="locate-end">
82
+ <circle cx="516" cy="316" r="13" fill="#d97706"/>
83
+ <text x="516" y="321" text-anchor="middle" font-size="14" font-weight="700" fill="#ffffff">3</text>
84
+ <text x="538" y="321" font-size="16" font-weight="700" fill="#7c4400">Repeat for the end</text>
85
+ <text x="502" y="346" font-size="13.5" fill="#526176">locate("decision")</text>
86
+ <rect x="502" y="357" width="176" height="32" rx="5" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
87
+ <text x="516" y="379" font-size="14" fill="#172033"><tspan font-weight="700">end ref:</tspan><tspan fill="#9a3412"> a0012</tspan></text>
88
+ </g>
89
+
90
+ <line x1="688" y1="347" x2="721" y2="347" stroke="#64748b" stroke-width="2.3" marker-end="url(#arrow-slate)"/>
91
+
92
+ <g id="plan-draft">
93
+ <rect x="731" y="301" width="286" height="96" rx="8" fill="#fff7ed" stroke="#ea580c" stroke-width="2"/>
94
+ <circle cx="757" cy="321" r="13" fill="#ea580c"/>
95
+ <text x="757" y="326" text-anchor="middle" font-size="14" font-weight="700" fill="#ffffff">4</text>
96
+ <text x="780" y="326" font-size="16" font-weight="700" fill="#9a3412">plan submits the slice</text>
97
+ <text x="748" y="350" font-size="13.5" fill="#526176">start: a0007 end: a0012</text>
98
+ <text x="748" y="371" font-size="13.5" fill="#526176">slice: every atom in between</text>
99
+ <text x="748" y="390" font-size="13.5" fill="#526176">summary: reviewed phase in concise form</text>
100
+ </g>
101
+
102
+ <line x1="1017" y1="349" x2="1040" y2="349" stroke="#64748b" stroke-width="2.3" marker-end="url(#arrow-slate)"/>
103
+
104
+ <g id="complete-draft">
105
+ <rect x="1050" y="301" width="210" height="96" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"/>
106
+ <circle cx="1076" cy="321" r="13" fill="#059669"/>
107
+ <text x="1076" y="326" text-anchor="middle" font-size="14" font-weight="700" fill="#ffffff">5</text>
108
+ <text x="1099" y="326" font-size="16" font-weight="700" fill="#065f46">Draft d1 is ready</text>
109
+ <text x="1067" y="352" font-size="13.5" fill="#047857">a0007 -&gt; a0012</text>
110
+ <text x="1067" y="373" font-size="13.5" fill="#047857">summary attached</text>
111
+ <text x="1067" y="390" font-size="13" fill="#047857">review before commit</text>
112
+ </g>
113
+ </g>
114
+
115
+ <line x1="40" y1="416" x2="1260" y2="416" stroke="#d8dee8" stroke-width="1.5"/>
116
+ <text x="40" y="440" font-size="14" fill="#8a5808">No message IDs are injected into normal conversation. Temporary refs exist only inside this frozen planning transaction and disappear with the maintenance branch.</text>
117
+ </g>
118
+ </svg>
@@ -0,0 +1,64 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="390" viewBox="0 0 1200 390" role="img" aria-labelledby="title desc">
2
+ <title id="title">Midcompact changes the projected model context, not the stored Pi session</title>
3
+ <desc id="desc">Raw Pi history appears on the left. A reviewed middle range is kept in storage but represented as one summary in the later context request shown on the right. Other messages remain unchanged.</desc>
4
+
5
+ <defs>
6
+ <marker id="arrow-blue" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto">
7
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#2563eb"/>
8
+ </marker>
9
+ </defs>
10
+
11
+ <rect width="1200" height="390" fill="#ffffff"/>
12
+ <g font-family="Arial, Helvetica, sans-serif">
13
+ <text x="40" y="43" font-size="27" font-weight="700" fill="#172033">Midcompact changes the projected model context, not the stored Pi session</text>
14
+ <text x="40" y="70" font-size="16" fill="#526176">Raw session history stays intact. Reviewed ranges are replaced by summaries only in the projected context sent to the model.</text>
15
+ <line x1="40" y1="92" x2="1160" y2="92" stroke="#d8dee8" stroke-width="1.5"/>
16
+
17
+ <g id="stored-history">
18
+ <rect x="40" y="116" width="450" height="218" rx="10" fill="#fbfcfe" stroke="#94a3b8" stroke-width="2"/>
19
+ <text x="64" y="146" font-size="18" font-weight="700" fill="#172033">Stored Pi session history</text>
20
+ <text x="466" y="146" text-anchor="end" font-size="14" fill="#526176">unchanged</text>
21
+
22
+ <rect x="65" y="164" width="400" height="31" rx="5" fill="#ffffff" stroke="#64748b" stroke-width="1.5"/>
23
+ <text x="82" y="185" font-size="14" fill="#172033"><tspan font-weight="700">User</tspan><tspan fill="#526176"> project requirements</tspan></text>
24
+
25
+ <rect x="57" y="207" width="416" height="91" rx="7" fill="#fffbeb" stroke="#d97706" stroke-width="2" stroke-dasharray="6 4"/>
26
+ <text x="72" y="225" font-size="12" font-weight="700" fill="#a16207">REVIEWED RANGE: RAW ENTRIES STAY HERE</text>
27
+ <rect x="65" y="232" width="400" height="24" rx="4" fill="#ffffff" stroke="#d97706" stroke-width="1.4"/>
28
+ <text x="82" y="249" font-size="13" fill="#172033"><tspan font-weight="700">Assistant</tspan><tspan fill="#526176"> source exploration</tspan></text>
29
+ <rect x="65" y="263" width="400" height="24" rx="4" fill="#ffffff" stroke="#d97706" stroke-width="1.4"/>
30
+ <text x="82" y="280" font-size="13" fill="#172033"><tspan font-weight="700">Tools</tspan><tspan fill="#526176"> commands and output</tspan></text>
31
+
32
+ <rect x="65" y="304" width="400" height="18" rx="4" fill="#ffffff" stroke="#64748b" stroke-width="1.3"/>
33
+ <text x="82" y="318" font-size="12.5" fill="#172033"><tspan font-weight="700">Assistant</tspan><tspan fill="#526176"> final decision remains verbatim</tspan></text>
34
+ </g>
35
+
36
+ <g id="projection-arrow">
37
+ <line x1="515" y1="226" x2="680" y2="226" stroke="#2563eb" stroke-width="3" marker-end="url(#arrow-blue)"/>
38
+ <rect x="535" y="184" width="122" height="28" rx="14" fill="#eff6ff" stroke="#2563eb" stroke-width="1.5"/>
39
+ <text x="596" y="203" text-anchor="middle" font-size="13" font-weight="700" fill="#1d4ed8">context hook</text>
40
+ <text x="596" y="254" text-anchor="middle" font-size="13" fill="#526176">exact range match</text>
41
+ <text x="596" y="274" text-anchor="middle" font-size="13" fill="#526176">before a request</text>
42
+ </g>
43
+
44
+ <g id="projected-context">
45
+ <rect x="710" y="116" width="450" height="218" rx="10" fill="#fbfcfe" stroke="#94a3b8" stroke-width="2"/>
46
+ <text x="734" y="146" font-size="18" font-weight="700" fill="#172033">Context sent to the model</text>
47
+ <text x="1136" y="146" text-anchor="end" font-size="14" fill="#047857">smaller request</text>
48
+
49
+ <rect x="735" y="164" width="400" height="31" rx="5" fill="#ffffff" stroke="#64748b" stroke-width="1.5"/>
50
+ <text x="752" y="185" font-size="14" fill="#172033"><tspan font-weight="700">User</tspan><tspan fill="#526176"> project requirements</tspan></text>
51
+
52
+ <rect x="735" y="207" width="400" height="76" rx="7" fill="#fffbeb" stroke="#d97706" stroke-width="2"/>
53
+ <text x="752" y="232" font-size="15" font-weight="700" fill="#7c4400">Summary c0001</text>
54
+ <text x="752" y="254" font-size="13.5" fill="#8a5808">key findings, decisions, validation state</text>
55
+ <text x="752" y="273" font-size="13.5" fill="#8a5808">from the reviewed exploration</text>
56
+
57
+ <rect x="735" y="296" width="400" height="26" rx="4" fill="#ffffff" stroke="#64748b" stroke-width="1.3"/>
58
+ <text x="752" y="314" font-size="12.5" fill="#172033"><tspan font-weight="700">Assistant</tspan><tspan fill="#526176"> final decision remains verbatim</tspan></text>
59
+ </g>
60
+
61
+ <line x1="40" y1="354" x2="1160" y2="354" stroke="#d8dee8" stroke-width="1.5"/>
62
+ <text x="40" y="380" font-size="15.5" fill="#526176">If the extension cannot find the exact reviewed sequence, it sends the raw history unchanged instead of removing uncertain content.</text>
63
+ </g>
64
+ </svg>
@@ -0,0 +1,117 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1400" height="900" viewBox="0 0 1400 900" role="img" aria-labelledby="title desc">
2
+ <title id="title">Midcompact transaction lifecycle in the Pi session tree</title>
3
+ <desc id="desc">A main Pi session tree reaches an anchor. A temporary maintenance branch is used for locate, plan, and human review. On commit the maintenance branch is abandoned, the session returns to the anchor, and a branch-local midcompact-state entry is appended. Earlier raw history remains stored while selected spans are projected as compressed blocks.</desc>
4
+ <defs>
5
+ <style><![CDATA[
6
+ text { font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif; }
7
+ .title { font-size: 32px; font-weight: 800; fill: #0f172a; }
8
+ .subtitle { font-size: 17px; fill: #475569; }
9
+ .section { font-size: 13px; font-weight: 800; letter-spacing: .08em; fill: #64748b; }
10
+ .label { font-size: 18px; font-weight: 700; fill: #0f172a; }
11
+ .label-sm { font-size: 15px; font-weight: 700; fill: #0f172a; }
12
+ .body { font-size: 15px; fill: #334155; }
13
+ .small { font-size: 13px; fill: #64748b; }
14
+ .blue { fill:#2563eb; }
15
+ .green { fill:#047857; }
16
+ .orange { fill:#c2410c; }
17
+ .main { stroke:#1e293b; stroke-width:4; fill:none; }
18
+ .dash { stroke:#94a3b8; stroke-width:3; stroke-dasharray:9 8; fill:none; }
19
+ .node { fill:#fff; stroke:#334155; stroke-width:3; }
20
+ .anchor { fill:#eff6ff; stroke:#2563eb; stroke-width:4; }
21
+ .state { fill:#ecfdf5; stroke:#10b981; stroke-width:3; }
22
+ .maint { fill:#f8fafc; stroke:#94a3b8; stroke-width:2.5; stroke-dasharray:10 8; }
23
+ .step { fill:#fff; stroke:#cbd5e1; stroke-width:2; }
24
+ .orangeBox { fill:#fff7ed; stroke:#fb923c; stroke-width:2; }
25
+ .blueBox { fill:#eff6ff; stroke:#93c5fd; stroke-width:2; }
26
+ .greenBox { fill:#ecfdf5; stroke:#86efac; stroke-width:2; }
27
+ .legend { fill:#f8fafc; stroke:#cbd5e1; stroke-width:1.5; }
28
+ ]]></style>
29
+ <marker id="arrow-slate" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker>
30
+ <marker id="arrow-green" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L10,5 L0,10 z" fill="#10b981"/></marker>
31
+ </defs>
32
+
33
+ <rect width="1400" height="900" fill="#fff"/>
34
+ <text x="55" y="62" class="title">A midcompact transaction lives in the session tree</text>
35
+ <text x="55" y="92" class="subtitle">Planning happens on a temporary branch. Commit returns to the anchor and saves only branch-local compression state.</text>
36
+ <line x1="55" y1="114" x2="1345" y2="114" stroke="#e2e8f0" stroke-width="1.5"/>
37
+
38
+ <!-- Main tree -->
39
+ <text x="70" y="150" class="section">MAIN SESSION TREE</text>
40
+ <line x1="245" y1="190" x2="245" y2="785" class="main"/>
41
+ <line x1="245" y1="230" x2="245" y2="305" class="dash"/>
42
+
43
+ <circle cx="245" cy="190" r="16" class="node"/>
44
+ <text x="285" y="196" class="label">T1 · session start</text>
45
+
46
+ <circle cx="245" cy="320" r="16" class="node"/>
47
+ <text x="285" y="326" class="label">T20 · earlier work</text>
48
+
49
+ <circle cx="245" cy="405" r="16" class="node"/>
50
+ <text x="285" y="411" class="label">T35 · more work</text>
51
+
52
+ <circle cx="245" cy="505" r="23" class="anchor"/>
53
+ <polygon points="245,489 249,499 260,499 251,506 255,517 245,511 235,517 239,506 230,499 241,499" fill="#2563eb"/>
54
+ <text x="290" y="512" class="label blue">T50 · anchor</text>
55
+ <text x="290" y="537" class="small blue">/midcompact freezes the snapshot here</text>
56
+
57
+ <!-- maintenance branch -->
58
+ <path d="M268 505 H 575" class="dash"/>
59
+ <rect x="575" y="205" width="725" height="430" rx="24" class="maint"/>
60
+ <text x="610" y="242" class="label">Temporary maintenance branch</text>
61
+ <text x="610" y="268" class="body">The Agent can discuss, locate, revise, and ask you to review without polluting the future working context.</text>
62
+
63
+ <rect x="615" y="315" width="180" height="82" rx="16" class="step"/>
64
+ <circle cx="646" cy="343" r="14" fill="#2563eb"/><text x="646" y="348" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">1</text>
65
+ <text x="676" y="350" class="label-sm">locate</text>
66
+ <text x="635" y="378" class="small">resolve semantic landmarks</text>
67
+ <text x="635" y="397" class="small">to temporary refs</text>
68
+
69
+ <line x1="795" y1="356" x2="840" y2="356" stroke="#64748b" stroke-width="3" marker-end="url(#arrow-slate)"/>
70
+
71
+ <rect x="850" y="315" width="180" height="82" rx="16" class="step"/>
72
+ <circle cx="881" cy="343" r="14" fill="#d97706"/><text x="881" y="348" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">2</text>
73
+ <text x="911" y="350" class="label-sm">plan</text>
74
+ <text x="870" y="378" class="small">select ranges + KEEP holes</text>
75
+ <text x="870" y="397" class="small">write summaries</text>
76
+
77
+ <line x1="1030" y1="356" x2="1075" y2="356" stroke="#64748b" stroke-width="3" marker-end="url(#arrow-slate)"/>
78
+
79
+ <rect x="1085" y="315" width="180" height="82" rx="16" class="orangeBox"/>
80
+ <circle cx="1116" cy="343" r="14" fill="#ea580c"/><text x="1116" y="348" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">3</text>
81
+ <text x="1146" y="350" class="label-sm">human review</text>
82
+ <text x="1105" y="378" class="small">inspect ranges + summaries</text>
83
+ <text x="1105" y="397" class="small">revise before commit</text>
84
+
85
+ <rect x="615" y="445" width="650" height="120" rx="18" class="blueBox"/>
86
+ <text x="640" y="477" class="label-sm blue">Commit semantics</text>
87
+ <text x="640" y="507" class="body">/midcompact commit waits for idle, navigates back to T50 with summarize=false,</text>
88
+ <text x="640" y="533" class="body">then appends one midcompact-state entry on the main branch.</text>
89
+ <text x="640" y="559" class="small">The maintenance conversation remains in the session file as an abandoned branch, but never enters future model context.</text>
90
+
91
+ <!-- commit back -->
92
+ <path d="M940 635 V 680 H 310" class="dash" marker-end="url(#arrow-green)"/>
93
+ <text x="805" y="670" class="small green">commit only the state</text>
94
+
95
+ <!-- state entry -->
96
+ <rect x="95" y="650" width="150" height="64" rx="16" class="state"/>
97
+ <text x="170" y="688" text-anchor="middle" class="label-sm green">state entry</text>
98
+ <line x1="245" y1="682" x2="270" y2="682" stroke="#10b981" stroke-width="3" marker-end="url(#arrow-green)"/>
99
+ <text x="285" y="677" class="label-sm green">midcompact-state</text>
100
+ <text x="285" y="701" class="small green">controls the projected view of earlier history</text>
101
+
102
+ <circle cx="245" cy="760" r="16" class="node"/>
103
+ <text x="285" y="766" class="label">T80 · new work continues</text>
104
+
105
+ <!-- compressed span annotations: state controls these earlier spans -->
106
+ <path d="M170 216 h-18 v92 h18" stroke="#f59e0b" stroke-width="5" fill="none" stroke-linecap="round"/>
107
+ <text x="62" y="255" class="label-sm orange">c0001</text><text x="52" y="278" class="small orange">projected summary</text>
108
+ <path d="M170 337 h-18 v54 h18" stroke="#f59e0b" stroke-width="5" fill="none" stroke-linecap="round"/>
109
+ <text x="62" y="365" class="label-sm orange">c0002</text>
110
+ <path d="M170 422 h-18 v54 h18" stroke="#f59e0b" stroke-width="5" fill="none" stroke-linecap="round"/>
111
+ <text x="62" y="450" class="label-sm orange">c0003</text>
112
+
113
+ <rect x="70" y="805" width="1260" height="62" rx="16" class="legend"/>
114
+ <text x="95" y="833" class="label-sm">Important:</text>
115
+ <text x="185" y="833" class="body">the orange blocks are projection rules, not replacements in the stored tree.</text>
116
+ <text x="185" y="857" class="body">Rollback to a point before the state entry and the original uncompressed history is visible again.</text>
117
+ </svg>
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "pi-midcompact",
3
+ "version": "0.2.1",
4
+ "description": "Branch-aware mid-context compression for the Pi coding agent",
5
+ "author": "frostime",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/frostime/pi-midcompact.git"
9
+ },
10
+ "homepage": "https://github.com/frostime/pi-midcompact#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/frostime/pi-midcompact/issues"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "type": "module",
18
+ "keywords": [
19
+ "pi-package",
20
+ "pi",
21
+ "coding-agent",
22
+ "context",
23
+ "compression",
24
+ "session"
25
+ ],
26
+ "files": [
27
+ "src",
28
+ "skills",
29
+ "README.md",
30
+ "figures"
31
+ ],
32
+ "scripts": {
33
+ "typecheck": "tsc -p tsconfig.json --noEmit",
34
+ "test": "rm -rf .test-dist && tsc -p tsconfig.test.json && node test/install-mocks.mjs && node --test test/core.test.mjs test/runtime.test.mjs",
35
+ "typecheck:contract": "tsc -p tsconfig.test.json --noEmit",
36
+ "pack:check": "npm pack --dry-run"
37
+ },
38
+ "peerDependencies": {
39
+ "@earendil-works/pi-ai": "^0.84.1",
40
+ "@earendil-works/pi-coding-agent": "^0.84.1",
41
+ "@earendil-works/pi-tui": "^0.84.1"
42
+ },
43
+ "devDependencies": {
44
+ "@earendil-works/pi-ai": "^0.84.1",
45
+ "@earendil-works/pi-coding-agent": "^0.84.1",
46
+ "typescript": "^5.9.3",
47
+ "@earendil-works/pi-tui": "^0.84.1"
48
+ },
49
+ "pi": {
50
+ "extensions": [
51
+ "./src/index.ts"
52
+ ],
53
+ "skills": [
54
+ "./skills"
55
+ ]
56
+ }
57
+ }
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: midcompact
3
+ description: Use during an active /midcompact transaction to selectively compress stale middle sections of a long Pi conversation, or later to recall exact details from compressed blocks.
4
+ ---
5
+
6
+ # Midcompact
7
+
8
+ Use this skill only when a `/midcompact` transaction is active, or when exact information must be recovered from a previously compressed block.
9
+
10
+ ## Mental model
11
+
12
+ The transaction is based on a frozen anchor snapshot. Maintenance discussion, locator calls, draft revisions, and review happen on a temporary branch. A successful commit returns to the anchor without summarizing that maintenance branch, then stores only the reviewed compression projection.
13
+
14
+ The extension handles session-tree mechanics and protocol safety. You decide semantic value.
15
+
16
+ Do not infer importance from a tool name. A user constraint, approval, correction, decision, or other critical fact may appear inside any message or tool exchange. Inspect actual content.
17
+
18
+ ## Context awareness
19
+
20
+ The tool reports approximate context telemetry while planning:
21
+
22
+ - anchor usage captured when `/midcompact` started;
23
+ - approximate raw tokens selected by the current draft;
24
+ - approximate summary tokens;
25
+ - approximate whole-context usage if the draft were committed now.
26
+
27
+ Treat these numbers as **awareness, not a target**. Do not maximize token reduction or keep adding ranges merely because more compression is possible. Use the scale information together with semantic value and the user's conversational guidance. If the user says they only want a modest reduction, preserve more context; if they want more headroom, look for additional stale regions.
28
+
29
+ Projected values are estimates. Prefer semantic correctness over apparent numeric precision.
30
+
31
+ ## Compression workflow
32
+
33
+ 1. Decide which completed or stale regions are candidates for compression.
34
+ 2. Use `midcompact(action="locate", ...)` to resolve semantic landmarks to atom refs. Locator results include readable previews; request `detail="full"` when a boundary is ambiguous.
35
+ 3. Build a draft with `midcompact(action="plan", op="add", start=..., end=..., summary=...)`.
36
+ - Use multiple ranges for non-contiguous compression.
37
+ - To preserve an important atom verbatim inside a broader phase, split the compression into ranges around that atom.
38
+ - Prefer KEEP-by-omission when uncertain.
39
+ - After each meaningful draft change, use the returned context telemetry to understand its scale; do not treat it as a quota.
40
+ 4. Use `midcompact(action="plan", op="show")` and present the complete proposed plan to the user. Include what each range begins/ends with, not only atom IDs.
41
+ 5. Recommend `/midcompact review` when the user wants to inspect the linear anchor timeline, proposed ranges, summaries, and KEEP holes. Incorporate requested changes with `op="update"`, `op="remove"`, additional ranges, or the review UI.
42
+ 6. After the user is satisfied, ask them to run `/midcompact commit`. The Agent cannot commit itself. The explicit user command is the commit gate and returns the session tree to the anchor before persisting the projection.
43
+
44
+ A good summary preserves what the next working Agent needs: user intent and constraints, decisions and rationale, relevant file paths/signatures/errors, validation state, rejected approaches when the reason matters, unresolved issues, and the next useful state. Remove repetitive exploration and process noise rather than merely shortening prose.
45
+
46
+ ## Repeated compression
47
+
48
+ A session may be midcompacted multiple times. Existing compressed blocks remain active and protected; a later transaction can compress newly accumulated raw history around them. Do not attempt to recursively compress an already compressed block in the current version.
49
+
50
+ ## Recall
51
+
52
+ Compression is reversible at the information-access level. Original session entries remain stored.
53
+
54
+ - `midcompact(action="recall", pattern="...")` searches active compressed block summaries/topics.
55
+ - `midcompact(action="recall", ref="c0001")` temporarily returns the original content for that block.
56
+
57
+ Recall does not change the compression projection. Use it when a summary lacks a detail needed for current work.