pi-optchat 0.5.0

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/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jonas Silva
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ This grant covers the original implementation. Attributed upstream prompt text
24
+ in src/prompts.ts and bundled dependencies retain their respective rights;
25
+ see THIRD_PARTY_NOTICES.md.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # pi-optchat
2
+
3
+ A Pi extension that implements [Victor Taelin's OptChat recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449): one endless chat per profile, remembered through a summary tree instead of compaction.
4
+
5
+ - **Memory**: every message is logged and summarized into a binary tree. Each turn starts from a fresh context holding a bounded memory view; the agent uses `zoom` and `date` to read originals.
6
+ - **Profiles**: separate memories and instructions, such as `work` and `personal`.
7
+ - **Subagents**: delegate tasks to background agents, inspect them live, and send them guidance.
8
+ - **Import**: bring in history from Claude Code, Codex, or ChatGPT.
9
+ - **Connected windows**: a second Pi window on the same profile becomes a subagent you talk to directly.
10
+
11
+ It runs inside ordinary Pi, with no fork or separate launcher.
12
+
13
+ ## Install
14
+
15
+ ```sh
16
+ pi install npm:pi-optchat
17
+ pi install npm:pi-web-access # optional, for web search and page fetching
18
+ ```
19
+
20
+ Or from GitHub: `pi install git:github.com/jonaslsaa/pi-optchat`.
21
+
22
+ Requirements: Pi 1.0.2 or compatible, Node.js 22.19+, and Git. Tested on macOS; the offline tests also run on Linux.
23
+
24
+ Web access is not bundled. Subagents load the Pi extensions you have installed (except pi-optchat itself), so installing `pi-web-access` gives web tools to the main agent and every subagent.
25
+
26
+ To uninstall, run `pi remove git:github.com/jonaslsaa/pi-optchat`. Profile data is kept.
27
+
28
+ ## Quick start
29
+
30
+ 1. Restart Pi.
31
+ 2. Choose **+ Create profile** and name it, for example `work`.
32
+ 3. Chat normally.
33
+
34
+ The footer shows the active profile. Memory follows the profile across directories and Pi sessions. New sessions show the profile picker with the last-used profile first; resumed sessions restore their profile.
35
+
36
+ For headless use, pass `--optchat-profile work`.
37
+
38
+ ## Commands
39
+
40
+ | Command | Action |
41
+ | --- | --- |
42
+ | `/optchat` | Status and actions menu. |
43
+ | `/optchat profile` | Select or create a profile. Switching starts a fresh Pi session. |
44
+ | `/optchat model` | Compactor model and effort for this profile. |
45
+ | `/optchat agents` | Live agent tree and saved run history. |
46
+ | `/optchat agents model` | Subagent model and effort for this profile. |
47
+ | `/optchat usage` | Token usage and cost estimates. |
48
+ | `/optchat instructions` | Edit this profile's `AGENTS.md`. |
49
+ | `/optchat browse` | Open an HTML snapshot of memory: current view, every tree level, original messages. Run again to refresh. |
50
+ | `/optchat import` | Import history, or resume/discard a paused import. |
51
+ | `/complete` | In a connected window: end the conversation and hand off to the main agent. |
52
+ | `/tell-main <message>` | In a connected window: message the main agent. |
53
+
54
+ ## Models
55
+
56
+ | Role | Default | Change with |
57
+ | --- | --- | --- |
58
+ | Main agent | Whatever is selected in Pi | `/model` |
59
+ | Subagents | Anthropic Opus 5.5, high | `/optchat agents model` |
60
+ | Compactor (summaries, imports, handoffs) | Anthropic Sonnet 5.5, medium | `/optchat model` |
61
+
62
+ Subagent and compactor settings are saved per profile and do not follow the main model. If you use other providers, change them before chatting. Authentication uses Pi's existing provider login.
63
+
64
+ Compression and subagents make extra model requests with your provider credentials.
65
+
66
+ ## Subagents
67
+
68
+ Ask in plain words, for example: "Spawn an agent to investigate this repository and report back."
69
+
70
+ - Children get the profile's memory view (frozen at launch), its instructions, read-only `zoom`/`date`, and normal coding tools plus your installed extensions.
71
+ - Each child reports back on its own when it finishes. The parent stays alive to receive reports; it never polls.
72
+ - The parent can send a running child guidance with `tell`.
73
+ - Delegation goes up to three levels below the main agent (child, grandchild, great-grandchild).
74
+ - At most 8 agents can be active per profile, including parents waiting on descendants. Going over a limit returns an error; there is no queue.
75
+ - Stopping an agent stops its whole subtree. A failed parent stops its descendants.
76
+ - Agents run inside the Pi process. Closing Pi stops them; there is no detached mode.
77
+
78
+ ## Agents and usage inspector
79
+
80
+ An **Agents | Usage** bar sits below the input.
81
+
82
+ | Key | Action |
83
+ | --- | --- |
84
+ | **Down** (empty input) | Focus the bar |
85
+ | **Left/Right**, **Enter** | Pick and open a section |
86
+ | **Escape**, **Up**, or typing | Back to the editor |
87
+ | **F6** | Open Agents directly, keeping your draft |
88
+ | **Tab** | Switch between Agents and Usage |
89
+
90
+ Set a different shortcut with `OPTCHAT_INSPECT_KEY=ctrl+shift+a pi`. If another extension supplies a custom editor, OptChat leaves its Down key alone; use the shortcut or commands instead.
91
+
92
+ **Agents** lists runs as a tree with state, elapsed time, current tool, and last activity. Navigate with **Up/Down**, **Page Up/Down**, **Home/End**, open with **Enter**, and press **M** to pick the subagent model. Inside a transcript:
93
+
94
+ | Key | Action |
95
+ | --- | --- |
96
+ | **T** | Expand tool arguments and results |
97
+ | **F** | Follow live output (scrolling pauses it) |
98
+ | **S** | Send guidance |
99
+ | **X** | Stop this agent and its subtree |
100
+ | **Escape** | Back |
101
+
102
+ Guidance shows as queued until delivered, or undelivered if the child stops first. Guidance you send is also saved in main memory. Reasoning is not shown. Transcripts stay browsable after restart, and browsing them makes no model calls.
103
+
104
+ **Usage** shows this session, last hour, today, last 7 days, or all time (**Left/Right**). It breaks down main agent, subagents, compactor, and imports by model: uncached input, output, cache reads/writes, and estimated cost.
105
+
106
+ - Costs are API-rate estimates, not your subscription bill. Unknown rates show zero.
107
+ - Record counts are not request counts; retries and tool overhead can add records.
108
+ - Main-agent tracking starts with v0.3.0 (resumed sessions are backfilled). Older records without a parent session are left out of **This session**.
109
+ - All views are limited to the active profile.
110
+
111
+ ## Import history
112
+
113
+ Pick the destination profile, then run `/optchat import`.
114
+
115
+ 1. **Source**: Claude Code (`~/.claude/projects`), Codex (`~/.codex/sessions`, `~/.codex/archived_sessions`), or a ChatGPT export (ZIP, folder, or `conversations.json`; ZIP needs `unzip`). Scanning is local and makes no model calls.
116
+ 2. **Select**: for Claude Code and Codex, pick projects (busiest first), optionally filter by start date, then take all conversations or pick some. **Space** toggles, **Enter** continues, type to filter, **Ctrl+A**/**Ctrl+D** select/clear matches, **Esc** cancels. Nothing is classified as work or personal for you.
117
+ 3. **Mode** (only if the profile already has history):
118
+ - **Append**: keep existing summaries and add the import. Faster and cheaper.
119
+ - **Rebuild by conversation start date**: regenerate the whole tree, ordered by conversation start.
120
+ 4. **Preview**: destination, new and duplicate counts, text size, rough token estimate, and compactor. This is not a price quote.
121
+
122
+ **What gets imported**: user messages and final assistant replies, with original dates and source labels, as in Victor's recipe. Tool calls and results, intermediate commentary, reasoning, subagent transcripts, replayed context, and image/audio/file bytes are left out. ChatGPT alternate branches are labelled as alternatives. Imported records are marked as historical so old requests are not treated as new instructions.
123
+
124
+ **Duplicates**: re-importing skips messages already present, even if titles or paths changed. Changed source messages can appear as a separate historical version.
125
+
126
+ **Pausing**: **Pause import** (or Escape) saves progress, and so does restarting Pi. `/optchat import` then offers **Resume** or **Discard staged import**. While an import is pending, chat in that profile is blocked; other profiles still work. Imports need the main agent and its subagents to be idle.
127
+
128
+ **Safety**: imports build a new memory generation and switch to it only when the whole tree is ready. The previous generation stays on disk. Source files are never modified.
129
+
130
+ Damaged or unsupported records are listed before you start, so you can cancel or continue without them. Conversations that disappear during the scan are skipped with a warning.
131
+
132
+ See OpenAI's guides on [exporting ChatGPT data](https://help.openai.com/en/articles/7260999-exporting-your-chatgpt-history-and-data) and the [conversation file format](https://help.openai.com/en/articles/9106926-transfer-exported-conversations-between-chatgpt-accounts).
133
+
134
+ ## Connected windows
135
+
136
+ Each profile is locked to one Pi process. If you open the same profile in a second terminal, Pi offers to connect it to the original window as a subagent.
137
+
138
+ - Your first message starts a subagent in the second window's working directory. Later messages continue the same conversation.
139
+ - The subagent runs inside the original process, which stays the only writer of memory. It appears in the original window's inspector and uses one of the 8 agent slots. While it is open, the original window can't switch profile or import.
140
+ - The main agent is told when the conversation starts. Use `/tell-main <message>` to message it yourself; the subagent has a `tell_main` tool, and the main agent replies with `tell`. Routine turns don't wake the main agent.
141
+ - Run `/complete` when done. The window closes, remaining work stops, and the compactor writes a handoff for the main agent: decisions, changes, evidence, failures, unfinished work, and links to the transcripts.
142
+ - Closing or force-quitting the window also produces a handoff, marked **interrupted**.
143
+ - If the original window is closed cleanly, handoffs are delivered on next start. If it is killed, reopening the profile recovers unfinished handoffs (work is not restarted).
144
+ - Text only. For images, give the agent a file path.
145
+ - The connection is a local socket restricted to your OS user. No daemon or server.
146
+
147
+ Handoff limits: the whole transcript is summarized in one call if it fits in about 128,000 input tokens (estimated at 4 bytes per token; less on smaller models), otherwise in chunks. Output is up to 16,000 tokens, with a 5-minute timeout per call. If summarizing fails, a labelled fallback still reports the task, last result, and transcript locations.
148
+
149
+ ## Storage
150
+
151
+ Profile data lives in `~/.optchat/profiles/<name>/` (override the root with `OPTCHAT_HOME`):
152
+
153
+ | Path | Contents |
154
+ | --- | --- |
155
+ | `main/` | The conversation log (dated JSONL, no reasoning) |
156
+ | `tree/` | Summary nodes |
157
+ | `active-memory.json`, `memories/<id>/` | After an import: pointer to the active `main/` and `tree/`. Older generations are kept. |
158
+ | `imports/pending.json` | Resumable import state |
159
+ | `AGENTS.md` | Profile instructions |
160
+ | `config.json` | Compactor and subagent models |
161
+ | `pending-inputs.json`, `pending-reports.json` | Recovery journals |
162
+ | `runs/` | Subagent sessions and run metadata |
163
+ | `usage.jsonl` | Usage ledger |
164
+ | `memory.html` | Snapshot from `/optchat browse` |
165
+
166
+ Each profile folder is a local Git repository, committed after each turn and on clean shutdown (memory and config; not runs, HTML, or usage). It has no remote, so it is not a backup. To back up, copy the folder while Pi is closed.
167
+
168
+ To delete a profile, delete its folder. Your original Pi sessions are kept in Pi's normal session directory.
169
+
170
+ ## Good to know
171
+
172
+ - **Profiles separate memory and instructions only.** Agents keep full filesystem access and share provider credentials.
173
+ - **Use worktrees** when parallel agents edit the same repository; they share the filesystem.
174
+ - **Instructions**: only the profile's `AGENTS.md` is injected. Repository and global Pi `AGENTS.md` files are not; ask the agent to read them when needed. Skills and prompt templates still work in the main session.
175
+ - **Images** are available during the current run but stored in memory as text placeholders.
176
+ - **Pi's auto-compaction is off.** A single very long run can still hit the model's context limit; stop it and continue in a new turn.
177
+ - **Restarts**: unsent inputs are recovered into memory, and pending subagent reports are delivered. Interrupted subagents are not restarted.
178
+ - **Skill and template inputs** can occasionally be recovered as an unanswered input after a crash, because Pi expands them after the input journal records them. Plain text chat is unaffected.
179
+
180
+ ## How it differs from the recipe
181
+
182
+ The recipe's four prompts are kept verbatim in `src/prompts.ts`, along with its numbers: 512-byte summary nodes, a 128,000-byte memory view, binary merges, 8 compression workers, fixed retry delays, 5 shortening attempts, and a 30,000-character tool output cap. Anthropic requests get stable cache breakpoints on the view. See `docs/victor-recipe.md` for notes.
183
+
184
+ Each run's context is the memory view, the previous exchange, and your new message. Deliberate additions:
185
+
186
+ 1. **Previous exchange kept verbatim.** Your last request (with any steering) and the final answer are included in full, so "why is that?" refers to what you actually read. Tool calls and reasoning are not carried over. It comes on top of the 128,000-byte view and is not truncated. A new Pi session starts with the memory view only.
187
+ 2. **Subagents** are built in with Pi's SDK rather than a separate package. Children report individually instead of per batch, and can delegate two extra levels.
188
+ 3. **Profiles**, the **inspector**, the **usage ledger**, **import**, and **connected windows** are additions. Import adds historical-record guidance to the prompts.
189
+ 4. **Not done**: computer use and hosting on an always-on machine.
190
+
191
+ ## Development
192
+
193
+ ```sh
194
+ git clone https://github.com/jonaslsaa/pi-optchat.git
195
+ cd pi-optchat
196
+ npm ci --ignore-scripts
197
+ pi install .
198
+ ```
199
+
200
+ Restart Pi after source changes. Use `OPTCHAT_HOME` to test against a throwaway data directory.
201
+
202
+ ```sh
203
+ npm run check # type check
204
+ npm test # offline tests, no paid model calls
205
+ npm run test:live # paid Anthropic calls on synthetic data in a disposable profile
206
+ ```
207
+
208
+ ### Publishing to npm
209
+
210
+ Pi's [package directory](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) lists npm packages with the `pi-package` keyword, which the manifest already has. GitHub alone is not enough.
211
+
212
+ ```sh
213
+ npm ci --ignore-scripts
214
+ npm run check && npm test
215
+ npm pack --dry-run
216
+ npm publish --access public
217
+ ```
218
+
219
+ ## Credits and license
220
+
221
+ Based on [Victor Taelin's OptChat recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449) and [OptMem](https://github.com/VictorTaelin/OptMem). This is an independent Pi implementation, not Victor's official OptChat.
222
+
223
+ MIT licensed. See [LICENSE](LICENSE) and [third-party notices](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,19 @@
1
+ # Third-party notices
2
+
3
+ ## Victor Taelin's OptChat recipe
4
+
5
+ The OptChat memory design and the four prompt strings in `src/prompts.ts`
6
+ come from Victor Taelin's publicly shared implementation recipe:
7
+
8
+ https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449
9
+
10
+ That upstream text is credited to Victor Taelin and is not relicensed by this
11
+ repository's MIT grant for original implementation code. The complete recipe
12
+ is linked upstream. This project is an independent Pi extension.
13
+
14
+ ## Pi
15
+
16
+ The extension uses Pi's host-provided SDK packages. Pi is distributed under the
17
+ MIT license:
18
+
19
+ https://github.com/earendil-works/pi
@@ -0,0 +1,20 @@
1
+ # OptChat recipe reference
2
+
3
+ Author: Victor Taelin.
4
+
5
+ Source: https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449
6
+
7
+ The implementation was compared with the recipe fetched on 2026-10-04. The reference content SHA-256 was `8f6997e8944d85e4df53b5704bf7c4e393e4da361071181e9cc2f7d9d1b6e430`.
8
+
9
+ The source remains upstream rather than duplicating the full article here. Its four prompt strings are preserved in `src/prompts.ts`, with attribution in `THIRD_PARTY_NOTICES.md`.
10
+
11
+ ## Implementation mapping
12
+
13
+ - `src/memory.ts`: append-only log, binary summary tree, compression scheduling, bounded view, zoom/date.
14
+ - `src/compactor.ts`: contextual compression and size retries.
15
+ - `src/cache.ts`: stable Anthropic cache boundaries.
16
+ - `src/transcript.ts`: fresh context per parent run, current-run tool loop retained. The previous completed exchange is also retained in full text, an intentional addition to the summary-only recipe for conversational continuity.
17
+ - `src/agents.ts`: asynchronous Pi SDK children and automatic completion reports.
18
+ - `src/import/`: profile-scoped historical imports retain user messages and final assistant replies, following the lighter history described in recipe section 10. Source adapters, final-reply detection, replay filtering, and ChatGPT branch labels are integration choices. Live-chat tool logging remains unchanged.
19
+
20
+ Profiles, native Pi UI, conversation import, and local Git checkpoints are integration choices described in the README.
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "pi-optchat",
3
+ "version": "0.5.0",
4
+ "type": "module",
5
+ "pi": {
6
+ "extensions": [
7
+ "./src/index.ts"
8
+ ]
9
+ },
10
+ "scripts": {
11
+ "check": "tsc --noEmit",
12
+ "test": "tsx --test test/*.test.ts",
13
+ "test:live": "tsx test/live.ts"
14
+ },
15
+ "devDependencies": {
16
+ "@earendil-works/pi-agent-core": "1.0.2",
17
+ "@earendil-works/pi-ai": "1.0.2",
18
+ "@earendil-works/pi-coding-agent": "1.0.2",
19
+ "@earendil-works/pi-tui": "1.0.2",
20
+ "@types/node": "^24.0.0",
21
+ "tsx": "^4.20.0",
22
+ "typebox": "1.3.27",
23
+ "typescript": "^5.9.0"
24
+ },
25
+ "peerDependencies": {
26
+ "@earendil-works/pi-agent-core": "*",
27
+ "@earendil-works/pi-ai": "*",
28
+ "@earendil-works/pi-coding-agent": "*",
29
+ "@earendil-works/pi-tui": "*",
30
+ "typebox": "*"
31
+ },
32
+ "description": "OptChat memory for Pi: persistent profiles, zoomable history, background agents, and conversation imports.",
33
+ "keywords": [
34
+ "pi-package",
35
+ "pi-extension",
36
+ "optchat",
37
+ "memory",
38
+ "subagents"
39
+ ],
40
+ "author": "Jonas",
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/jonaslsaa/pi-optchat.git"
45
+ },
46
+ "homepage": "https://github.com/jonaslsaa/pi-optchat#readme",
47
+ "bugs": {
48
+ "url": "https://github.com/jonaslsaa/pi-optchat/issues"
49
+ },
50
+ "engines": {
51
+ "node": ">=22.19.0"
52
+ },
53
+ "files": [
54
+ "src",
55
+ "docs",
56
+ "README.md",
57
+ "LICENSE",
58
+ "THIRD_PARTY_NOTICES.md"
59
+ ]
60
+ }