pi-optchat 0.8.5 → 0.8.7
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 +91 -102
- package/docs/connected-windows.md +63 -0
- package/docs/import.md +74 -0
- package/docs/inspector.md +45 -0
- package/docs/recipe-differences.md +52 -0
- package/docs/storage.md +25 -0
- package/docs/subagents.md +100 -0
- package/docs/victor-recipe.md +2 -2
- package/package.json +1 -1
- package/src/agent-view.ts +2 -2
- package/src/agents.ts +65 -27
- package/src/cache.ts +16 -4
- package/src/compactor.ts +7 -5
- package/src/import/job.ts +2 -2
- package/src/index.ts +8 -7
- package/src/inspector.ts +4 -4
- package/src/memory.ts +57 -27
- package/src/navigation.ts +3 -3
- package/src/prompts.ts +7 -2
- package/src/runs.ts +2 -0
- package/src/settings.ts +5 -3
- package/src/window-bridge.ts +6 -5
package/README.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
# pi-optchat
|
|
4
4
|
|
|
5
|
-
A Pi extension that
|
|
5
|
+
A Pi extension that gives you one endless chat per profile, remembered through a summary tree instead of compaction. It implements [Victor Taelin's OptChat recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449).
|
|
6
6
|
|
|
7
|
-
- **Memory**: every message is
|
|
7
|
+
- **Memory**: every message is kept, and each turn starts from a fresh context holding a bounded view of everything so far.
|
|
8
8
|
- **Profiles**: separate memories and instructions, such as `work` and `personal`.
|
|
9
|
-
- **Subagents**: delegate tasks to background agents,
|
|
9
|
+
- **Subagents**: delegate tasks to background agents, watch them live, and send them guidance.
|
|
10
10
|
- **Import**: bring in history from Claude Code (conversations and memories), Codex, Pi and [OMP](https://github.com/can1357/oh-my-pi), or ChatGPT.
|
|
11
|
-
- **Connected windows**: a second Pi window on the same profile becomes a subagent you talk to directly, or opens an existing background subagent
|
|
11
|
+
- **Connected windows**: a second Pi window on the same profile becomes a subagent you talk to directly, or opens an existing background subagent.
|
|
12
12
|
|
|
13
13
|
It runs inside ordinary Pi, with no fork or separate launcher.
|
|
14
14
|
|
|
@@ -35,11 +35,23 @@ To uninstall, run `pi remove git:github.com/jonaslsaa/pi-optchat`. Profile data
|
|
|
35
35
|
|
|
36
36
|
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.
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
### Headless and RPC
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
- `pi -p`, `--mode rpc` and other extensions' runners need `--optchat-profile work`. Without it (and without a saved profile in a resumed session) the run is plain Pi with no OptChat memory.
|
|
41
|
+
- In hosts that create sessions themselves (Pi Web), send `/optchat profile work` as the first message of a new session.
|
|
42
|
+
- If the profile is open in another Pi, `pi -p` joins it as a connected window by default; `--optchat-connect auto|join|off` controls this.
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
Details, errors and join rules: [docs/connected-windows.md](docs/connected-windows.md#headless-and-rpc-runs).
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
- Every message is logged and becomes one line: a short one (up to 512 bytes) word for word, a longer one summarized by the compactor model to about 512 bytes (up to 640 with the default Summary size tolerance).
|
|
49
|
+
- Pairs of lines merge into a binary tree of summaries: recent lines cover one message each, older lines cover more.
|
|
50
|
+
- Each turn starts from a fresh context: the memory view (the tree's lines, up to 128,000 bytes), your previous exchange, and your new message.
|
|
51
|
+
- When the view passes 128,000 bytes, lines merge in one batch down to 64,000, so between merges it only grows at the end and each turn reads the last one's view from the cache.
|
|
52
|
+
- The agent reads originals with `zoom` (open a line into the two it was made from, or a message in full) and `date`.
|
|
53
|
+
|
|
54
|
+
[Victor's recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449) explains the design; [How it differs from the recipe](#how-it-differs-from-the-recipe) lists what OptChat changes.
|
|
43
55
|
|
|
44
56
|
## Commands
|
|
45
57
|
|
|
@@ -47,7 +59,7 @@ If that profile is open in another Pi, `pi -p` joins it like a connected window:
|
|
|
47
59
|
| --- | --- |
|
|
48
60
|
| `/optchat` | Status and actions menu. |
|
|
49
61
|
| `/optchat profile` | Select or create a profile. Switching starts a fresh Pi session. |
|
|
50
|
-
| `/optchat settings` | This profile's settings
|
|
62
|
+
| `/optchat settings` | This profile's [settings](#settings). |
|
|
51
63
|
| `/optchat model` | Compactor model and effort for this profile. Type to filter the models you are logged in to; the current one is marked. |
|
|
52
64
|
| `/optchat agents` | Live agent tree and saved run history. |
|
|
53
65
|
| `/optchat agents model` | Subagent model and effort for this profile, picked the same way. |
|
|
@@ -73,7 +85,7 @@ Compression and subagents make extra model requests with your provider credentia
|
|
|
73
85
|
|
|
74
86
|
## Settings
|
|
75
87
|
|
|
76
|
-
`/optchat settings` opens this profile's settings. Each row shows its value and default, the selected row says what it does and when a change applies, and a change is saved right away to the profile's `config.json`. Defaults follow Victor's recipe, except Previous exchange, Summary size tolerance and
|
|
88
|
+
`/optchat settings` opens this profile's settings. Each row shows its value and default, the selected row says what it does and when a change applies, and a change is saved right away to the profile's `config.json`. Defaults follow Victor's recipe, except Previous exchange, Summary size tolerance and Turn refresh threshold.
|
|
77
89
|
|
|
78
90
|
| Setting | Default | What it does |
|
|
79
91
|
| --- | --- | --- |
|
|
@@ -82,14 +94,14 @@ Compression and subagents make extra model requests with your provider credentia
|
|
|
82
94
|
| Subagent levels | 1 | 1: only the main agent starts subagents. 2 or more: subagents may start their own, that many levels deep. Applies to subagents started or resumed after the change. |
|
|
83
95
|
| Max active agents | 8 | Subagents running at once in the profile, all levels together, so it also caps how deep a chain can go. |
|
|
84
96
|
| Group subagent reports | off | Off: each subagent reports as soon as it finishes (the recipe). On: the subagents started by one spawn report together, in one message once the last of them finishes. Applies to the next spawn. |
|
|
85
|
-
| Previous exchange | on | Replays your last request and answer in full with the next turn
|
|
97
|
+
| Previous exchange | on | Replays your last request and answer in full with the next turn. Off is the recipe. |
|
|
86
98
|
| Previous exchange limit | 16 KB | A larger last exchange is left out. |
|
|
87
|
-
| Memory search | off | Gives the agent, and subagents started or resumed after the change, a `search` tool over your original messages
|
|
99
|
+
| Memory search | off | Gives the agent, and subagents started or resumed after the change, a `search` tool over your original messages. Off is the recipe: zoom and date only. Applies from the next turn. |
|
|
88
100
|
| Summary size tolerance | 640 bytes | The compactor is always asked for 512-byte lines; a longer line up to this size is kept instead of retried. 512 is the recipe's strict rule. |
|
|
89
|
-
| Turn refresh threshold | 30% | Once the current turn's verbatim messages pass this share of the model's context window, they move into memory and the turn goes on with a fresh window (see Good to know). Type 30, 30% or 0.3. 0% is off, as in the recipe. Applies from the next call. |
|
|
90
|
-
|
|
|
101
|
+
| Turn refresh threshold | 30% | Once the current turn's verbatim messages pass this share of the model's context window, they move into memory and the turn goes on with a fresh window (see [Good to know](#good-to-know)). Type 30, 30% or 0.3. 0% is off, as in the recipe. Applies from the next call. |
|
|
102
|
+
| Summaries at once | 8 | Summaries built at once, by chat compaction and by an import, 1 to 64. With N at once, a summary can see up to N−1 lines not summarized yet before it, so higher is faster but a little less accurate (at 8 that costs about 0.8 points per summary, #108). Higher also hits your provider's rate limits harder (the compactor retries what is refused), so if your provider caps parallel requests, set it below that cap so the main turn has room. Applies to the next import, and to chat once the profile opens again. A `config.json` that still says `importJobs` keeps its value. |
|
|
91
103
|
|
|
92
|
-
Numbers must be whole numbers of at least 1 (512 for the summary size tolerance, at most 64 for
|
|
104
|
+
Numbers must be whole numbers of at least 1 (512 for the summary size tolerance, at most 64 for Summaries at once); Turn refresh threshold is a percentage from 0% to 90%. Missing keys in an older `config.json` take their defaults.
|
|
93
105
|
|
|
94
106
|
**Upgrading from 0.6.x:** subagent levels used to be fixed at 3 and now default to 1, so subagents no longer start their own subagents until you set Subagent levels to 2 or 3.
|
|
95
107
|
|
|
@@ -99,18 +111,15 @@ Numbers must be whole numbers of at least 1 (512 for the summary size tolerance,
|
|
|
99
111
|
|
|
100
112
|
Ask in plain words, for example: "Spawn an agent to investigate this repository and report back."
|
|
101
113
|
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- **Max active agents** (8 by default) caps how many agents can be active per profile, including parents waiting on descendants. Going over a limit returns an error; there is no queue.
|
|
112
|
-
- Stopping an agent stops its whole subtree. A failed parent stops its descendants.
|
|
113
|
-
- Agents run inside the Pi process. Closing Pi stops them; there is no detached mode. Subagents that were working when Pi closed, crashed or `/reload`ed are resumed from their saved transcripts when the profile next opens in interactive Pi, and the main agent is told which. Headless `pi -p` doesn't resume them; they wait for the next interactive start. Ones you stopped or paused aren't resumed.
|
|
114
|
+
- **What they get**: the profile's memory view (frozen at launch) and instructions, read-only `zoom`/`date`, normal coding tools, your installed extensions, and your MCP servers.
|
|
115
|
+
- **Reports**: each child reports when it finishes, as one message starting `[id]`, shown in a dark grey `↳ subagent <id>` box. Turn on **Group subagent reports** to get one message per spawn instead.
|
|
116
|
+
- **Model**: children run the profile's subagent model. Ask for another in your request ("review it with anthropic/claude-haiku-5-5 at low") and the agent sets that task's `model` and `thinking`.
|
|
117
|
+
- **Talking**: the parent sends guidance with `tell`; the child messages its parent mid-run with `tell_parent`. `tell` to a finished child resumes it with its saved transcript.
|
|
118
|
+
- **Limits**: by default only the main agent starts subagents. **Subagent levels** lets them delegate further, and **Max active agents** (8) caps how many run at once; going over returns an error, there is no queue.
|
|
119
|
+
- **Stopping**: stopping an agent stops its whole subtree. Agents run inside the Pi process, so closing Pi stops them.
|
|
120
|
+
- **Restarts**: agents cut off by a close, crash or `/reload` resume when the profile next opens in interactive Pi, and the main agent is told which. Ones you stopped or paused stay stopped.
|
|
121
|
+
|
|
122
|
+
More (MCP inheritance, per-task models, report formats, the "agents at work" status line, resume rules): [docs/subagents.md](docs/subagents.md).
|
|
114
123
|
|
|
115
124
|
## Agents, usage and activity inspector
|
|
116
125
|
|
|
@@ -126,90 +135,61 @@ An **Agents | Usage | Activity** bar sits below the input.
|
|
|
126
135
|
|
|
127
136
|
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.
|
|
128
137
|
|
|
129
|
-
**Agents** lists runs as a tree with state, elapsed time, current tool, and last activity.
|
|
130
|
-
|
|
131
|
-
**Enter** swaps the screen to that agent's conversation, drawn with Pi's own chat components, so it reads like the main chat: its task, replies, and collapsed tool calls, following live output. Typing and **Enter** send it guidance. Guidance from the main agent and reports from the agent's own agents show in labelled boxes, so only your own messages look typed. **Escape** goes back to the main chat.
|
|
138
|
+
**Agents** lists runs as a tree with state, elapsed time, current tool, and last activity. **M** picks the subagent model; **D** twice deletes the selected agent and the agents it started. **Enter** opens that agent's conversation, drawn like the main chat; type to send it guidance.
|
|
132
139
|
|
|
133
|
-
| Key | Action |
|
|
140
|
+
| Key (in an agent's conversation) | Action |
|
|
134
141
|
| --- | --- |
|
|
135
142
|
| **Escape** | Clear a draft, else back to the main chat |
|
|
136
|
-
| **Ctrl+C** | Clear a draft, else interrupt the agent's current step. Never ends the agent
|
|
143
|
+
| **Ctrl+C** | Clear a draft, else interrupt the agent's current step. Never ends the agent; with nothing queued it waits for you |
|
|
137
144
|
| **Up** (empty input) | Take your newest queued message back to edit; send it again, or clear it to drop it |
|
|
138
145
|
| **Ctrl+X** twice | Stop this agent and the agents it started (the only key that ends it) |
|
|
139
146
|
| **Page Up/Down**, mouse wheel | Scroll; back at the bottom it follows again. The wheel needs Pi's default fullscreen mode |
|
|
140
147
|
| **Ctrl+O** | Expand tool output (Pi's own toggle) |
|
|
141
148
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
**Usage** shows this session, last hour, today, last 7 days, or all time (**Left/Right**): one row per role and model (main agent, subagents, compactor, imports) with estimated cost, share of the total, output tokens, and how much input came from the cache. Costs are API prices, not your subscription bill.
|
|
149
|
+
**Usage** shows token use and estimated cost per role and model, for this session, last hour, today, last 7 days, or all time (**Left/Right**). Costs are API prices, not your subscription bill.
|
|
145
150
|
|
|
146
151
|

|
|
147
152
|
|
|
148
|
-
**Activity** is a memory gauge: how
|
|
153
|
+
**Activity** is a memory gauge: how full the 128 KB view is, whether summaries are **Settled** or **Catching up**, the last error if summarizing keeps failing, and running agents. The bar's Activity item gets a **●** while summaries or agents are at work.
|
|
149
154
|
|
|
150
155
|

|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
- Record counts are not request counts; retries and tool overhead can add records.
|
|
154
|
-
- Main-agent tracking starts with v0.3.0 (resumed sessions are backfilled). Older records without a parent session are left out of **This session**.
|
|
155
|
-
- All views are limited to the active profile.
|
|
157
|
+
Details (deleting agents, interrupts, usage caveats, failed summaries): [docs/inspector.md](docs/inspector.md).
|
|
156
158
|
|
|
157
159
|
## Import history
|
|
158
160
|
|
|
159
161
|
Pick the destination profile, then run `/optchat import`.
|
|
160
162
|
|
|
161
|
-
1. **Source**: Claude Code
|
|
162
|
-
2. **Select**: for
|
|
163
|
-
3. **Mode** (only if the profile already has history):
|
|
164
|
-
|
|
165
|
-
- **Rebuild by conversation start date**: regenerate the whole tree, ordered by conversation start.
|
|
166
|
-
4. **Preview**: destination, new and duplicate counts, text size, rough token estimate, and compactor. This is not a price quote: a big import costs about 3x that estimate in compactor input, because every message is summarized and then re-read in merges, each with the memory view as (mostly cached) context.
|
|
167
|
-
|
|
168
|
-
**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. So is the output Claude Code logs for slash and shell commands; the command itself stays as typed (`/name args` or `!command`). A message typed to Claude Code while it was working counts as a user message; Claude Code's `[Request interrupted by user]` markers and the replies they cut off are left out. So are the context messages Codex injects, such as the AGENTS.md instructions and the environment context, and the messages OMP injects (reminders, background job notices). Pi / OMP keep `/skill:name args`, `!command` and `$code` as typed, without the skill's text or the output; `!!` and `$$` commands, kept from the model, stay out. Dropped text never becomes a conversation's title. ChatGPT alternate branches are labelled as alternatives, and so are Pi / OMP branches left by a rewind (`[alternate branch]`). Pi sessions that ran under OptChat are skipped: their messages are already in a profile's memory. A forked session adds only its new messages. Imported records are marked as historical so old requests are not treated as new instructions.
|
|
169
|
-
|
|
170
|
-
**Claude Code memories**: the auto-memory topic files in `~/.claude/projects/*/memory/` (not `MEMORY.md`, which only indexes them), picked by project. Each file becomes one dated note in the memory tree, not part of the prompt. An edited file comes in again as a newer note.
|
|
171
|
-
|
|
172
|
-
**Duplicates**: re-importing skips messages already present, even if titles or paths changed. A resumed Claude Code session copies earlier messages into its own file; those copies are matched by message id and text, so they come in once, also against messages an earlier import stored. Changed source messages can appear as a separate historical version.
|
|
163
|
+
1. **Source**: Claude Code, Claude Code memories, Codex, Pi / OMP, or a ChatGPT export (ZIP, folder, or `conversations.json`). Scanning is local and makes no model calls.
|
|
164
|
+
2. **Select**: for the local sources, pick projects (busiest first), optionally filter by start date, then take all conversations or pick some.
|
|
165
|
+
3. **Mode** (only if the profile already has history): **Append** keeps existing summaries and adds the import (faster, cheaper); **Rebuild by conversation start date** regenerates the whole tree.
|
|
166
|
+
4. **Preview**: destination, new and duplicate counts, text size, rough token estimate, and compactor. A big import costs about 3x that estimate in compactor input.
|
|
173
167
|
|
|
174
|
-
|
|
168
|
+
- Only user messages and final assistant replies come in, with original dates and source labels, marked as historical so old requests are not treated as new instructions. Tool calls, reasoning and file bytes are left out.
|
|
169
|
+
- Re-importing skips messages already present.
|
|
170
|
+
- **Pause import** (or Escape, or restarting Pi) saves progress; `/optchat import` then offers **Resume** or **Discard staged import**. Chat in that profile is blocked while an import is pending.
|
|
171
|
+
- Imports switch to the new memory only when the whole tree is ready; the previous one stays on disk. Source files are never modified.
|
|
175
172
|
|
|
176
|
-
|
|
173
|
+
Source paths, selection keys, exactly what is left out, and duplicate rules: [docs/import.md](docs/import.md).
|
|
177
174
|
|
|
178
|
-
|
|
175
|
+
## Connected windows
|
|
179
176
|
|
|
180
|
-
|
|
177
|
+
Each profile is locked to one Pi process. Open the same profile in a second terminal and Pi offers to connect it to the original window as a subagent.
|
|
181
178
|
|
|
182
|
-
|
|
179
|
+
- Your first message starts a subagent in the second window's working directory; later messages continue it. The window looks like a normal Pi chat.
|
|
180
|
+
- The subagent runs inside the original process, which stays the only writer of memory.
|
|
181
|
+
- `/tell-main <message>` messages the main agent. `/complete` ends the conversation and the compactor writes a handoff for the main agent; closing the window also produces one, marked **interrupted**.
|
|
182
|
+
- Text only. The connection is a local socket restricted to your OS user (on Windows a named pipe, without that restriction; see [Windows](#windows)); no daemon or server.
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
To open an existing background agent instead, pick it from the menu, or pass its ID:
|
|
185
185
|
|
|
186
186
|
```sh
|
|
187
187
|
pi --optchat-profile work --optchat-agent 8ab62e89
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
This opens that
|
|
191
|
-
|
|
192
|
-
- The original Pi window stays the only owner: it runs the agent, and reports still go to the agent's parent. Opening the window starts no new agent or model call.
|
|
193
|
-
- **Closing the terminal or `/complete` only detaches.** The agent keeps running. Stop or interrupt it from the main window's **Agents** page, which can open the same agent at the same time, as can other terminals.
|
|
194
|
-
- A finished agent opens for reading, without being restarted.
|
|
195
|
-
- This needs interactive Pi and a running owner window. An unknown ID, or a conversation owned by another connected window, is refused rather than starting a new one. The attached terminal saves no session to resume; run the command again instead. The agent ID is not a Pi session ID.
|
|
196
|
-
|
|
197
|
-
## Connected windows
|
|
198
|
-
|
|
199
|
-
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, or to go back to the profile picker. Only an interactive or RPC Pi accepts connections; a headless `pi -p` run holding the profile does not.
|
|
190
|
+
This opens that same agent's session; what you type is guidance to it. Closing the terminal or `/complete` only detaches, and the agent keeps running.
|
|
200
191
|
|
|
201
|
-
|
|
202
|
-
- The window looks like a normal Pi chat: replies, tool calls with their output and running time, the working spinner, and reports from the subagent's own agents in the dark box. Ctrl+O expands tool output.
|
|
203
|
-
- 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.
|
|
204
|
-
- The main agent is told when the conversation starts. Use `/tell-main <message>` to message it yourself; the subagent can use `tell_parent`, and the main agent replies with `tell`. Routine turns don't wake the main agent.
|
|
205
|
-
- 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.
|
|
206
|
-
- Closing or force-quitting the window also produces a handoff, marked **interrupted**.
|
|
207
|
-
- 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).
|
|
208
|
-
- Closing the original window, or running `/reload` in it, ends every connected conversation; Pi gives no chance to warn before a reload. The connected window then shows **disconnected**. `/new` there starts over: after the profile picker if Pi was started without `--optchat-profile`, a profile still open elsewhere offers **Start a connected subagent conversation here** again, and a free one opens in this window.
|
|
209
|
-
- Text only. For images, give the agent a file path.
|
|
210
|
-
- The connection is a local socket restricted to your OS user. No daemon or server.
|
|
211
|
-
|
|
212
|
-
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.
|
|
192
|
+
Details (reload behaviour, handoff limits, attach rules, headless joins): [docs/connected-windows.md](docs/connected-windows.md).
|
|
213
193
|
|
|
214
194
|
## Storage
|
|
215
195
|
|
|
@@ -228,45 +208,54 @@ Profile data lives in `~/.optchat/profiles/<name>/` (override the root with `OPT
|
|
|
228
208
|
| `usage.jsonl` | Usage ledger |
|
|
229
209
|
| `memory.html` | Snapshot from `/optchat browse` |
|
|
230
210
|
|
|
231
|
-
Each profile folder is a local Git repository, committed after each turn
|
|
232
|
-
|
|
233
|
-
To delete a profile, delete its folder. Your original Pi sessions are kept in Pi's normal session directory.
|
|
211
|
+
- Each profile folder is a local Git repository, committed after each turn. It has no remote, so it is not a backup: copy the folder while Pi is closed.
|
|
212
|
+
- To delete a profile, delete its folder. Your original Pi sessions are kept in Pi's normal session directory.
|
|
234
213
|
|
|
235
|
-
|
|
214
|
+
Git checkpoints and the pluggable `Store` seam (for memory on another machine): [docs/storage.md](docs/storage.md).
|
|
236
215
|
|
|
237
216
|
## Windows
|
|
238
217
|
|
|
239
218
|
The same install and commands work on Windows, and the offline tests run there too. What differs:
|
|
240
219
|
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
220
|
+
- The profile lock and connected-window bridge use named pipes instead of socket files, so a Windows profile is not permission-protected the way a POSIX socket file is.
|
|
221
|
+
- ZIP exports are read with Windows' own `tar.exe` instead of `unzip`.
|
|
222
|
+
- `~` in a subagent task directory is your home directory; `~\project` is read as a home path only on Windows.
|
|
223
|
+
- File modes and directory fsync are POSIX-only and are skipped.
|
|
245
224
|
- Files are opened with `explorer.exe` instead of `open` or `xdg-open`.
|
|
246
225
|
|
|
226
|
+
Pipe names and permissions: [docs/storage.md](docs/storage.md#windows-differences).
|
|
227
|
+
|
|
247
228
|
## Good to know
|
|
248
229
|
|
|
249
230
|
- **Profiles separate memory and instructions only.** Agents keep full filesystem access and share provider credentials.
|
|
250
|
-
- **Tab title**: the terminal tab shows the profile and what it is doing: `π personal` while waiting for you, `● π personal` while the agent works, plus `· 2 agents` while subagents run. A connected window shows `↳ personal`, `● ↳ personal`, then `↳ personal · done` or `↳ personal · disconnected`. OptChat replaces Pi's default title and puts its own back when Pi resets it (new session, reload, rename).
|
|
251
231
|
- **Use worktrees** when parallel agents edit the same repository; they share the filesystem.
|
|
252
232
|
- **Instructions**: the main agent and subagents get Pi's usual global and repository `AGENTS.md` files and your skills, followed by the profile's `AGENTS.md`, which comes last and wins. OptChat replaces only Pi's opening prompt. Prompt templates work in the main session only.
|
|
253
|
-
- **
|
|
254
|
-
- **
|
|
255
|
-
- **
|
|
233
|
+
- **Tab title**: `π personal` while waiting for you, `● π personal` while the agent works, plus `· 2 agents` while subagents run. A connected window shows `↳ personal`, `● ↳ personal`, then `↳ personal · done` or `↳ personal · disconnected`. OptChat replaces Pi's default title and puts its own back when Pi resets it (new session, reload, rename).
|
|
234
|
+
- **Images** you paste, or a tool returns, are kept under the profile's `images/` (once each, shrunk to 2,048 px on the long side and about 1.5 MB with Pi's own resizer; smaller ones stay as they are). The log names each as `[image <hash>]`, and `zoom(id, 1)` returns a message's images with its text. Summaries stay text. Imported conversations keep a text placeholder.
|
|
235
|
+
- **Long turns** (#146): Pi's auto-compaction is off for the main agent, since memory replaces it. Once the current turn's verbatim messages pass the Turn refresh threshold (30% of the model's window by default), they are flushed to memory, the view is rebuilt, and only the task message plus the last tool call and its result stay verbatim; the earlier steps are the view's last lines, a zoom away. In an A/B on a 200K model, turns that otherwise gave up around 100K tokens kept going and covered the whole task. `OPTCHAT_REFRESH_AT` (a fraction, e.g. `0.3`; `0` is off) overrides the setting. Subagents use Pi's own compaction instead, starting at about the same point.
|
|
236
|
+
- **Restarts**: unsent inputs are recovered into memory, and pending subagent reports are delivered.
|
|
256
237
|
- **Prompt-template inputs** can be saved twice: expanded, and later in their original form as an unanswered input, because Pi expands them after the input journal records them. Skill commands (`/skill:name`) are matched back to their journaled input and don't have this problem. Plain text chat is unaffected.
|
|
257
238
|
|
|
258
239
|
## How it differs from the recipe
|
|
259
240
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
241
|
+
OptChat keeps the recipe's numbers: 512-byte lines, binary merges, the 128,000 → 64,000-byte view, 8 compression workers, 5 shortening attempts, a 30,000-character tool output cap. The ones you can turn off or tune are [settings](#settings). Prompt-by-prompt detail: [docs/recipe-differences.md](docs/recipe-differences.md).
|
|
242
|
+
|
|
243
|
+
| Area | Recipe | OptChat | Why |
|
|
244
|
+
| --- | --- | --- | --- |
|
|
245
|
+
| Prompts | The original and 2026-10-08 prompts | The same, lightly adapted, all in `src/prompts.ts`: reports start `[id]`, a note on `[OptChat status]`, "don't poll slow things", the size limit as a ceiling rather than a target | Fit OptChat's tools; the size wording gave less filler with no recall loss (#129) |
|
|
246
|
+
| Compactor instructions | Gets your instructions | Doesn't | An A/B found they added nothing (#112) |
|
|
247
|
+
| Summary size | Strict 512 bytes | Asked for 512, keeps up to 640 without a retry | Saves retries for a little view space |
|
|
248
|
+
| Memory view | Sawtooth, 128,000 → 64,000 bytes | Same, saved to `view.json` with the compactions' view and reloaded as they were | A restart keeps both prompt prefixes cached |
|
|
249
|
+
| Compaction view | Ends at the first unsummarized line | Shows that line as a placeholder and keeps the lines after it | Cutting there hid short lines like an echo's own tool call; summaries scored lower (#101) |
|
|
250
|
+
| Tool-result summaries | Result only | Also sees the raw tool call | Recall 3.88 → 4.22 (#153) |
|
|
251
|
+
| Cache marks | View in 4-line blocks, one mark on the last whole block | Two more marks, 20 and 40 blocks before it | With one mark, a turn that added over 80 lines made the next turn rewrite the whole view; now up to 240 lines still read from cache |
|
|
252
|
+
| Previous exchange | Memory view only | Last request and answer in full (up to 16 KB) | "Why is that?" refers to what you actually read |
|
|
253
|
+
| Subagents | Reports start `[Name]` | Built in with Pi's SDK, not a separate package; reports start `[id]`; Subagent levels setting (default 1) | |
|
|
254
|
+
| Memory search | Not there | Opt-in `search` over original messages | Exact names, numbers and errors the view doesn't show |
|
|
255
|
+
| Large messages | Returned whole, middle cut by the 30,000-character cap | `zoom(id, 1)` pages at 25,000 characters | Nothing cut out |
|
|
256
|
+
| Long turns | No limit; a long turn can run out of window | Turn refresh at 30% of the window | Turns kept going past ~100K tokens (#146) |
|
|
257
|
+
| Profiles, inspector, usage, import, connected windows | Not there | Added | |
|
|
258
|
+
| Computer use, always-on hosting | In the recipe | Not done | |
|
|
270
259
|
|
|
271
260
|
## Development
|
|
272
261
|
|
|
@@ -298,6 +287,6 @@ The workflow checks that the tag matches `package.json`, runs the type check and
|
|
|
298
287
|
|
|
299
288
|
## Credits and license
|
|
300
289
|
|
|
301
|
-
Based on [Victor Taelin's OptChat recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449) and [OptMem](https://github.com/VictorTaelin/OptMem). His revised gist (2026-10-08) calls his own version UniiChat. This is an independent Pi implementation, not Victor's official OptChat.
|
|
290
|
+
Based on [Victor Taelin's OptChat recipe](https://gist.github.com/VictorTaelin/91837951a5ce5b38f341ec1ba1df6449) and [OptMem](https://github.com/VictorTaelin/OptMem). His revised gist (2026-10-08) calls his own version UniiChat. This is an independent Pi implementation, not Victor's official OptChat. See [docs/victor-recipe.md](docs/victor-recipe.md) for how the code maps to the recipe.
|
|
302
291
|
|
|
303
292
|
MIT licensed. See [LICENSE](LICENSE) and [third-party notices](THIRD_PARTY_NOTICES.md).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Connected windows, background agents and headless runs
|
|
2
|
+
|
|
3
|
+
Each profile is locked to one Pi process. This page covers the ways a second Pi can reach a profile that is already open.
|
|
4
|
+
|
|
5
|
+
## Connected windows
|
|
6
|
+
|
|
7
|
+
If you open the same profile in a second terminal, Pi offers to connect it to the original window as a subagent, or to go back to the profile picker. Only an interactive or RPC Pi accepts connections; a headless `pi -p` run holding the profile does not.
|
|
8
|
+
|
|
9
|
+
- Your first message starts a subagent in the second window's working directory. Later messages continue the same conversation.
|
|
10
|
+
- The window looks like a normal Pi chat: replies, tool calls with their output and running time, the working spinner, and reports from the subagent's own agents in the dark box. Ctrl+O expands tool output.
|
|
11
|
+
- The subagent runs inside the original process, which stays the only writer of memory. It appears in the original window's inspector and takes one of the profile's active agent slots (Max active agents, 8 by default). While it is open, the original window can't switch profile or import.
|
|
12
|
+
- The main agent is told when the conversation starts. Use `/tell-main <message>` to message it yourself; the subagent can use `tell_parent`, and the main agent replies with `tell`. Routine turns don't wake the main agent.
|
|
13
|
+
- Text only. For images, give the agent a file path.
|
|
14
|
+
- The connection is a local socket restricted to your OS user. No daemon or server. On Windows it is a machine-wide named pipe without file permissions, so it has no such restriction (see [storage.md](storage.md#windows-differences)).
|
|
15
|
+
|
|
16
|
+
### Ending a conversation
|
|
17
|
+
|
|
18
|
+
- 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.
|
|
19
|
+
- Closing or force-quitting the window also produces a handoff, marked **interrupted**.
|
|
20
|
+
- 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).
|
|
21
|
+
- Closing the original window, or running `/reload` in it, ends every connected conversation; Pi gives no chance to warn before a reload. The connected window then shows **disconnected**. `/new` there starts over: after the profile picker if Pi was started without `--optchat-profile`, a profile still open elsewhere offers **Start a connected subagent conversation here** again, and a free one opens in this window.
|
|
22
|
+
|
|
23
|
+
### Handoff limits
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
## Open an existing background agent in another terminal
|
|
28
|
+
|
|
29
|
+
When the profile is already open, `pi --optchat-profile work` in a second terminal offers **Start a connected subagent conversation here**, followed by **Open subagent <id> · <state> · <task>** for each running, waiting or paused background agent. You can also skip the menu with the ID shown in the main window's **Agents** page or a subagent report:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pi --optchat-profile work --optchat-agent 8ab62e89
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This opens that **same agent's session** as a normal Pi chat: its task, previous replies and tool results, then live output. Messages you type are guidance to that agent; a paused agent continues when you send one. `/tell-main` still contacts the main agent.
|
|
36
|
+
|
|
37
|
+
- The original Pi window stays the only owner: it runs the agent, and reports still go to the agent's parent. Opening the window starts no new agent or model call.
|
|
38
|
+
- **Closing the terminal or `/complete` only detaches.** The agent keeps running. Stop or interrupt it from the main window's **Agents** page, which can open the same agent at the same time, as can other terminals.
|
|
39
|
+
- A finished agent opens for reading, without being restarted.
|
|
40
|
+
- This needs interactive Pi and a running owner window. An unknown ID, or a conversation owned by another connected window, is refused rather than starting a new one.
|
|
41
|
+
- The attached terminal saves no session to resume; run the command again instead. The agent ID is not a Pi session ID.
|
|
42
|
+
|
|
43
|
+
## Headless and RPC runs
|
|
44
|
+
|
|
45
|
+
For headless use (`pi -p`, `--mode rpc`, other extensions' runners), pass `--optchat-profile work`.
|
|
46
|
+
|
|
47
|
+
- Without it, and without a saved profile in a resumed session, a headless run is plain Pi with no OptChat memory.
|
|
48
|
+
- If the requested profile can't open (misspelled, deleted, or busy and not joinable, see below), the run reports the error and doesn't answer.
|
|
49
|
+
|
|
50
|
+
In RPC and SDK hosts that create sessions themselves (Pi Web), send `/optchat profile work` as the first message of a new session. A profile is open in one session at a time, so a second session on it gets "Profile already running".
|
|
51
|
+
|
|
52
|
+
### Joining a busy profile with `pi -p`
|
|
53
|
+
|
|
54
|
+
If the profile is open in another Pi, `pi -p` joins it like a connected window: a subagent in that Pi answers, only its final reply goes to stdout, and the main agent gets the handoff. `--optchat-connect` picks when:
|
|
55
|
+
|
|
56
|
+
| Value | Behaviour |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `auto` (default) | Joins only when the profile is busy. |
|
|
59
|
+
| `join` | Always joins, and fails if no Pi has the profile open. |
|
|
60
|
+
| `off` | Reports the busy profile as an error. |
|
|
61
|
+
|
|
62
|
+
- A failed join exits non-zero.
|
|
63
|
+
- A profile held by another `pi -p` (or JSON-mode) run can't be joined, since that run exits after its own prompt. Once it exits, `auto` opens the profile itself; `join` still fails, as no Pi has it open.
|
package/docs/import.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Import in detail
|
|
2
|
+
|
|
3
|
+
The README has the steps. This page lists what each source brings in and how duplicates, pauses and failures are handled.
|
|
4
|
+
|
|
5
|
+
## Sources
|
|
6
|
+
|
|
7
|
+
| Source | Where it reads |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Claude Code | `~/.claude/projects` |
|
|
10
|
+
| Claude Code memories | `~/.claude/projects/*/memory/` |
|
|
11
|
+
| Codex | `~/.codex/sessions`, `~/.codex/archived_sessions` |
|
|
12
|
+
| Pi / OMP | `~/.pi/agent/sessions`, `~/.omp/agent/sessions`, and each OMP profile's `~/.omp/profiles/<name>/agent/sessions` (both write the same session format) |
|
|
13
|
+
| ChatGPT export | A ZIP, folder, or `conversations.json`. A ZIP is read with `unzip` on macOS/Linux and the built-in `tar.exe` on Windows; nothing is extracted to disk. |
|
|
14
|
+
|
|
15
|
+
Scanning is local and makes no model calls.
|
|
16
|
+
|
|
17
|
+
## Selecting
|
|
18
|
+
|
|
19
|
+
For Claude Code, its memories, Codex, and Pi / OMP, pick projects (busiest first), optionally filter by start date, then take all conversations or pick some.
|
|
20
|
+
|
|
21
|
+
| Key | Action |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| **Tab** (and **Space** when the filter is empty) | Toggle |
|
|
24
|
+
| **Enter** | Continue |
|
|
25
|
+
| Typing | Filter |
|
|
26
|
+
| **Ctrl+A** / **Ctrl+D** | Select / clear matches |
|
|
27
|
+
| **Esc** | Cancel |
|
|
28
|
+
|
|
29
|
+
Nothing is classified as work or personal for you.
|
|
30
|
+
|
|
31
|
+
## Cost
|
|
32
|
+
|
|
33
|
+
The preview shows a rough token estimate. This is not a price quote: a big import costs about 3x that estimate in compactor input, because every message is summarized and then re-read in merges, each with the memory view as (mostly cached) context.
|
|
34
|
+
|
|
35
|
+
## What gets imported
|
|
36
|
+
|
|
37
|
+
User messages and final assistant replies, with original dates and source labels, as in Victor's recipe. Imported records are marked as historical so old requests are not treated as new instructions.
|
|
38
|
+
|
|
39
|
+
Left out:
|
|
40
|
+
|
|
41
|
+
- Tool calls and results, intermediate commentary, reasoning, subagent transcripts, replayed context, and image/audio/file bytes. Imported conversations keep a text placeholder for images.
|
|
42
|
+
- The output Claude Code logs for slash and shell commands. The command itself stays as typed (`/name args` or `!command`).
|
|
43
|
+
- Claude Code's `[Request interrupted by user]` markers and the replies they cut off. A message typed to Claude Code while it was working counts as a user message.
|
|
44
|
+
- The context messages Codex injects, such as the AGENTS.md instructions and the environment context.
|
|
45
|
+
- The messages OMP injects (reminders, background job notices).
|
|
46
|
+
- For Pi / OMP, the skill's text and command output: `/skill:name args`, `!command` and `$code` stay as typed. `!!` and `$$` commands, kept from the model, stay out.
|
|
47
|
+
- Pi sessions that ran under OptChat: their messages are already in a profile's memory.
|
|
48
|
+
|
|
49
|
+
Also:
|
|
50
|
+
|
|
51
|
+
- Dropped text never becomes a conversation's title.
|
|
52
|
+
- ChatGPT alternate branches are labelled as alternatives, and so are Pi / OMP branches left by a rewind (`[alternate branch]`).
|
|
53
|
+
- A forked session adds only its new messages.
|
|
54
|
+
|
|
55
|
+
## Claude Code memories
|
|
56
|
+
|
|
57
|
+
The auto-memory topic files in `~/.claude/projects/*/memory/` (not `MEMORY.md`, which only indexes them), picked by project. Each file becomes one dated note in the memory tree, not part of the prompt. An edited file comes in again as a newer note.
|
|
58
|
+
|
|
59
|
+
## Duplicates
|
|
60
|
+
|
|
61
|
+
Re-importing skips messages already present, even if titles or paths changed. A resumed Claude Code session copies earlier messages into its own file; those copies are matched by message id and text, so they come in once, also against messages an earlier import stored. Changed source messages can appear as a separate historical version.
|
|
62
|
+
|
|
63
|
+
## Pausing
|
|
64
|
+
|
|
65
|
+
**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.
|
|
66
|
+
|
|
67
|
+
## Safety
|
|
68
|
+
|
|
69
|
+
- Imports build a new memory generation and switch to it only when the whole tree is ready. The previous generation stays on disk.
|
|
70
|
+
- Source files are never modified.
|
|
71
|
+
- Damaged or unsupported records are listed before you start, so you can cancel or continue without them.
|
|
72
|
+
- Conversations that disappear during the scan are skipped with a warning.
|
|
73
|
+
|
|
74
|
+
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).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Inspector in detail
|
|
2
|
+
|
|
3
|
+
The README has the keys. This page covers what each page shows and the edge cases.
|
|
4
|
+
|
|
5
|
+
## Agents
|
|
6
|
+
|
|
7
|
+
Runs are listed as a tree with state, elapsed time, current tool, and last activity. Navigate with **Up/Down**, **Page Up/Down**, **Home/End**, and press **M** to pick the subagent model.
|
|
8
|
+
|
|
9
|
+
### Deleting an agent
|
|
10
|
+
|
|
11
|
+
Press **D** twice to delete the selected agent and the agents it started, with their transcripts.
|
|
12
|
+
|
|
13
|
+
- An agent that is still working is stopped first, and its stop report reaches its parent before it is deleted. The report tells the parent that you dropped the task, so it does not delegate it again.
|
|
14
|
+
- Deleting a finished agent sends no report, so memory logs `[id] deleted by the user` right away, without a model turn.
|
|
15
|
+
- The main agent can no longer resume a deleted agent.
|
|
16
|
+
- Deleting a connected window that is still open stops it like closing the window; its handoff still reaches the main agent, but the transcript the handoff points to is deleted.
|
|
17
|
+
|
|
18
|
+
### An agent's conversation
|
|
19
|
+
|
|
20
|
+
**Enter** swaps the screen to that agent's conversation, drawn with Pi's own chat components, so it reads like the main chat: its task, replies, and collapsed tool calls, following live output. Typing and **Enter** send it guidance. Guidance from the main agent and reports from the agent's own agents show in labelled boxes, so only your own messages look typed. **Escape** goes back to the main chat.
|
|
21
|
+
|
|
22
|
+
- **Ctrl+C** never ends the agent: queued messages go to it at once and it carries on; with none queued it waits for you (**interrupted · waiting for you**) until your next message, or a `tell` from the main agent, resumes it.
|
|
23
|
+
- When you interrupt an agent with nothing queued, the agent that started it gets a one-line note instead of a report, so it isn't left waiting.
|
|
24
|
+
- Guidance shows as queued until delivered, or undelivered if the child stops first. Guidance you send is also saved in main memory.
|
|
25
|
+
- Reasoning is not shown.
|
|
26
|
+
- Transcripts stay browsable after restart, and browsing them makes no model calls.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
Shows this session, last hour, today, last 7 days, or all time (**Left/Right**): one row per role and model (main agent, subagents, compactor, imports) with estimated cost, share of the total, output tokens, and how much input came from the cache.
|
|
31
|
+
|
|
32
|
+
- Costs are API-rate estimates, not your subscription bill. Unknown rates show zero.
|
|
33
|
+
- Record counts are not request counts; retries and tool overhead can add records.
|
|
34
|
+
- Main-agent tracking starts with v0.3.0 (resumed sessions are backfilled). Older records without a parent session are left out of **This session**.
|
|
35
|
+
- All views are limited to the active profile.
|
|
36
|
+
|
|
37
|
+
## Activity
|
|
38
|
+
|
|
39
|
+
A memory gauge: how many messages the profile holds and how much of the 128 KB view they fill, then either **Settled** or **Catching up · 12 of 40 summaries** with a progress bar counted from when the backlog last grew from empty.
|
|
40
|
+
|
|
41
|
+
- If summarizing keeps failing, the last error and the retry countdown show under it. A turn waiting for summaries shows the same error next to its spinner, usually a summarizer model you aren't logged in to (`/optchat model`).
|
|
42
|
+
- Once every summary a turn waits for has failed, the turn goes on, with "(not summarized yet: zoom it)" in place of the missing lines, and the failed summaries keep retrying in the background.
|
|
43
|
+
- A summary the model itself won't write (a refusal, an empty reply, or 5 replies cut off at the token limit) isn't retried: that line keeps the start of what it summarizes, after "(not summarized: zoom it)", and a warning names it once. Errors such as a dropped connection, a rate limit or a missing login keep retrying.
|
|
44
|
+
- It also counts running agents, and interrupted ones waiting for you; their list is on Agents.
|
|
45
|
+
- While summaries or agents are at work, the bar's Activity item gets a **●**.
|