pi-optchat README

The project's README from github.com/jonaslsaa/pi-optchat. As one markdown file: README.md.

Pi-OptChat: persistent memory for Pi

pi-optchat

A Pi extension that implements Victor Taelin's OptChat recipe: one endless chat per profile, remembered through a summary tree instead of compaction.

It runs inside ordinary Pi, with no fork or separate launcher.

Install

pi install npm:pi-optchat
pi install npm:pi-web-access   # optional, for web search and page fetching

Or from GitHub: pi install git:github.com/jonaslsaa/pi-optchat.

Requirements: Pi 1.0.2 or compatible, Node.js 22.19+, and Git. Tested on macOS; the offline tests also run on Linux.

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.

To uninstall, run pi remove git:github.com/jonaslsaa/pi-optchat. Profile data is kept.

Quick start

  1. Restart Pi.
  2. Choose + Create profile and name it, for example work.
  3. Chat normally.

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.

For headless use, pass --optchat-profile work.

Commands

Command Action
/optchat Status and actions menu.
/optchat profile Select or create a profile. Switching starts a fresh Pi session.
/optchat settings This profile's settings: models, subagent levels and limits, previous exchange, summary size tolerance.
/optchat model Compactor model and effort for this profile. Type to filter the models you are logged in to; the current one is marked.
/optchat agents Live agent tree and saved run history.
/optchat agents model Subagent model and effort for this profile, picked the same way.
/optchat usage Token usage and cost estimates.
/optchat activity Memory gauge: view size, summaries catching up, running agents.
/optchat instructions Edit this profile's AGENTS.md.
/optchat browse Open a readable snapshot of memory: the shape of what the model sees, summaries you can open down to the original messages, and search that shows where each message is folded. Run again to refresh.
/optchat import Import history, or resume/discard a paused import.
/complete In a connected window: end the conversation and hand off to the main agent.
/tell-main <message> In a connected window: message the main agent.

Models

Role Default Change with
Main agent Whatever is selected in Pi /model
Subagents Anthropic Opus 5.5, high /optchat agents model
Compactor (summaries, imports, handoffs) Anthropic Sonnet 5.5, medium /optchat model

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.

Compression and subagents make extra model requests with your provider credentials.

Settings

/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 and Summary size tolerance, which keep OptChat's earlier behaviour.

Setting Default What it does
Compactor model Sonnet 5.5, medium Same as /optchat model. Applies to the next summary.
Subagent model Opus 5.5, high Same as /optchat agents model. Applies to new subagents.
Subagent levels 1 1: only the main agent starts subagents (the recipe). 2 or more: subagents may start their own, that many levels deep. Applies to subagents started or resumed after the change.
Max active agents 8 Subagents running at once in the profile, all levels together, so it also caps how deep a chain can go.
Group subagent reports on The subagents started by one spawn report together, in one message once the last of them finishes (the recipe). Off: each reports as soon as it finishes. Applies to the next spawn.
Previous exchange on Replays your last request and answer in full with the next turn (see below). Off is the recipe.
Previous exchange limit 16 KB A larger last exchange is left out.
Memory search off Gives the agent, and subagents started or resumed after the change, a search tool over your original messages (see below). Off is the recipe: zoom and date only. Applies from the next turn.
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.

Numbers must be whole numbers of at least 1 (512 for the summary size tolerance). Missing keys in an older config.json take their defaults.

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.

Settings page

Subagents

Ask in plain words, for example: "Spawn an agent to investigate this repository and report back."

Agents, usage and activity inspector

An Agents | Usage | Activity bar sits below the input.

Key Action
Down (empty input) Focus the bar
Left/Right, Enter Pick and open a section
Escape, Up, or typing Back to the editor
F6 Open Agents directly, keeping your draft
Tab Cycle Agents, Usage and Activity

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.

Agents lists runs 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.

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.

Key Action
Escape Clear a draft, else back to the main chat
Ctrl+C Clear a draft, else interrupt the agent's current step. 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
Up (empty input) Take your newest queued message back to edit; send it again, or clear it to drop it
Ctrl+X twice Stop this agent and the agents it started (the only key that ends it)
Page Up/Down, mouse wheel Scroll; back at the bottom it follows again. The wheel needs Pi's default fullscreen mode
Ctrl+O Expand tool output (Pi's own toggle)

Guidance shows as queued until delivered, or undelivered if the child stops first. 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. 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.

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.

Usage page

Activity is 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. If summarizing keeps failing, the last error and the retry countdown show under it. A turn stuck waiting for summaries shows the same error next to its spinner, usually a summarizer model you aren't logged in to (/optchat model). It also counts running agents, and interrupted ones waiting for you; their list is on Agents. While summaries or agents are at work, the bar's Activity item gets a ●.

Activity page

Import history

Pick the destination profile, then run /optchat import.

  1. Source: Claude Code (~/.claude/projects), Claude Code memories, 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.
  2. Select: for Claude Code, its memories, and Codex, pick projects (busiest first), optionally filter by start date, then take all conversations or pick some. Tab toggles (and Space when the filter is empty), Enter continues, type to filter, Ctrl+A/Ctrl+D select/clear matches, Esc cancels. Nothing is classified as work or personal for you.
  3. Mode (only if the profile already has history):
    • Append: keep existing summaries and add the import. Faster and cheaper.
    • Rebuild by conversation start date: regenerate the whole tree, ordered by conversation start.
  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.

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). So are the context messages Codex injects, such as the AGENTS.md instructions and the environment context. Dropped text never becomes a conversation's title. ChatGPT alternate branches are labelled as alternatives. Imported records are marked as historical so old requests are not treated as new instructions.

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.

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.

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.

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.

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.

See OpenAI's guides on exporting ChatGPT data and the conversation file format.

Connected windows

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.

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.

Storage

Profile data lives in ~/.optchat/profiles/<name>/ (override the root with OPTCHAT_HOME):

Path Contents
main/ The conversation log (dated JSONL, no reasoning)
tree/ Summary nodes
active-memory.json, memories/<id>/ After an import: pointer to the active main/ and tree/. Older generations are kept.
imports/pending.json Resumable import state
AGENTS.md Profile instructions
config.json Compactor and subagent models
pending-inputs.json, pending-reports.json Recovery journals
runs/ Subagent sessions and run metadata
usage.jsonl Usage ledger
memory.html Snapshot from /optchat browse

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.

To delete a profile, delete its folder. Your original Pi sessions are kept in Pi's normal session directory.

Good to know

How it differs from the recipe

The recipe's four prompts are kept verbatim in src/prompts.ts (the view doc adds one sentence: you can zoom out too, from a message to the summaries above it), along with its numbers: 512-byte summary nodes (by default summaries up to 640 bytes are accepted without a retry, as long as they are smaller than what they replace; see Summary size tolerance), 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. Each compactor request shows a 512-byte example line for scale. It is a true line about OptChat itself, labelled as not from the chat and fenced off in <example> tags, with the text to summarize in <input> tags: shown bare, a made-up example was sometimes summarized as if it were chat and spread up the tree. Anthropic requests get stable cache breakpoints on the view, and when that view is not cached yet, one compactor call goes first and the others wait until it starts answering, so they read the cache instead of each writing it. See docs/victor-recipe.md for notes.

Each run's context is the memory view, the previous exchange, and your new message. Deliberate additions (the ones that change the recipe's behaviour are settings, see Settings):

  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. If it is over 16,000 bytes (about 4,000 tokens, usually a big paste; Previous exchange limit) it is left out entirely, and the model relies on the view and zoom as in Victor's recipe. A new Pi session starts with the memory view only.
  2. Subagents are built in with Pi's SDK rather than a separate package. With Subagent levels above 1 they can delegate further.
  3. Memory search (off by default). With the setting on, the agent also gets search(text, before?): plain, case-insensitive text matching over the original messages, never the summaries (a summary can be wrong, and one fact repeats at every level of the tree), skipping logged zoom and search results. It returns 20 hits at a time, newest first, each with its id, the view line that holds it when that is a summary (1234 (in 1024+256)), its date and a snippet; before: id pages back, and zoom(id, 1) reads a hit. One line about it is added to the system prompt. Turning it on or off changes the cached prompt once.
  4. Profiles, the inspector, the usage ledger, import, and connected windows are additions. Import adds historical-record guidance to the prompts.
  5. Not done: computer use and hosting on an always-on machine.

Development

git clone https://github.com/jonaslsaa/pi-optchat.git
cd pi-optchat
npm ci --ignore-scripts
pi install .

Restart Pi after source changes. Use OPTCHAT_HOME to test against a throwaway data directory.

npm run check      # type check
npm test           # offline tests, no paid model calls
npm run test:live  # paid Anthropic calls on synthetic data in a disposable profile

Publishing to npm

Pi's package directory lists npm packages with the pi-package keyword, which the manifest already has. GitHub alone is not enough.

Publishing a GitHub release publishes to npm. The Publish workflow uses npm trusted publishing, so no token or npm login is involved:

  1. Merge a PR that bumps version in package.json.
  2. gh release create vX.Y.Z --target main --generate-notes

The workflow checks that the tag matches package.json, runs the type check and tests, and publishes with provenance. It skips versions already on npm. To retry a tag, run it by hand: gh workflow run publish.yml -f tag=vX.Y.Z.

Credits and license

Based on Victor Taelin's OptChat recipe and OptMem. This is an independent Pi implementation, not Victor's official OptChat.

MIT licensed. See LICENSE and third-party notices.

pi-optchat (jonaslsaa/pi-optchat)

Searching Database…

What is this?pi-optchat is an extension for the Pi coding agent that gives it persistent, endless memory per profile using a summary tree instead of context compaction, plus background subagents and the ability to import history from other agents.
Is this a standalone app or does it need Pi installed first?It is a plugin that runs inside the existing Pi chat tool, not a separate program; there is no fork or separate launcher.
What do I need before installing it?You need Pi 1.0.2 or a compatible version, Node.js 22.19 or newer, and Git.
Does it come with web browsing for the agent?No, web access is not bundled; you need to separately install the pi-web-access extension to give the main agent and subagents web tools.
Does it work on Linux, or only macOS?It is tested on macOS, and the offline test suite also runs on Linux.
What are profiles used for?Profiles keep separate memories and instructions for different contexts, for example a 'work' profile versus a 'personal' one, and memory follows the active profile across directories and sessions.
What can subagents do?Subagents are background agents the main agent can spawn to investigate or work on tasks; you can watch them live in a tree view, send them guidance mid-run, and they report back when finished.
Can I bring in my existing chat history?Yes, the /optchat import command can pull in conversations and memories from Claude Code, Codex, or ChatGPT.
What is a 'connected window'?Opening a second Pi window on the same profile turns it into a subagent you can talk to directly, which can hand off or message back to the main agent.
Creator
jonaslsaa
Size
2 MB
Stars
267
Age
13d
Commits · 90 Days