--- name: one-conv-cli description: >- Read the user's AI conversation history with one-conv. Use cloud for ChatGPT, Claude Chat, Codex cloud and Cowork; use local for Claude Code, Codex CLI, Cursor and Oh My Pi, on this machine and in the shared archive. Discover accounts, pull cloud history, list conversations, search messages and read threads. Message running Claude Code, Codex, Oh My Pi and Cursor sessions with live. Local agent continuation and live sends require explicit --yes. Cloud authentication reuses authorized browser sessions without Keychain password prompts. --- # One conversation reader ## How to invoke Invoke it as **`one-conv`** (alias `agent-conv`), put on `$PATH` by `claudine/scripts/link_clis.py`. Without that link, run `/bin/one-conv`, a symlink to `one_conv_cli.py`, a PEP 723 script whose dependencies `uv` resolves on first run. Choose the namespace first: ```bash one-conv cloud --help one-conv local --help ``` - `cloud chatgpt`: ChatGPT web conversations. - `cloud claude`: Claude web chat, distinct from local Claude Code. - `cloud codex`: Codex cloud tasks, distinct from local Codex CLI. - `cloud cowork`: remote Cowork sessions and paginated event transcripts. - `local`: Claude Code, Codex CLI, Cursor (IDE and CLI) and Oh My Pi, read on this machine and from the archive. Old top-level commands remain compatibility aliases. Prefer namespaces for new invocations so local work cannot implicitly scan cloud accounts. For legacy asset sync, online ChatGPT search and existing automation, see [LEGACY_COMMANDS.md](LEGACY_COMMANDS.md). ## Authentication Local history needs no authentication: it reads files on this machine and the configured archive. Cloud history reuses browser sessions. `cloud claude connect --login` adds an account: it opens Claude sign-in in a browser profile only one-conv uses (`claude-1`, `claude-2`, ...), so each added account keeps a login of its own and the user can sign in and out freely in their everyday browser. Renew an expired one with `--login --profile claude-1`. Verify with `cloud claude accounts` after sign-in. Opening a login page does not verify a connection. Plain `connect` authorizes Keychain access; it does not sign in to the provider. Claude and OpenAI reuse provider-scoped browser sessions. Keychain access is strictly noninteractive: being signed into a browser does not prove the CLI can decrypt its session. Empty discovery or an authorization error is not an empty conversation history. Never disable prompt suppression to work around background authentication failures. When the user explicitly authorizes setup, `connect --browser chrome` permits one Keychain dialog through a stable native helper. Ask the user to choose Always Allow; never run connect from a background check. This browser authorization is shared by Claude and OpenAI. The helper is compiled with optimization and installed once in the user's Application Support directory. Passive reads never rebuild it. This local development installation uses ad hoc signing; replacing the helper binary can require authorization again. Distributable app updates need a stable signing identity. Browser sessions themselves can still expire independently. `--session-file` remains an internal broker integration option. Do not ask users to copy tokens or treat that file as customer onboarding. No hosted login or session renewal service is implemented. See [PROVIDERS.md](PROVIDERS.md) for provider coverage, live verification and API-change handling. ## Output conventions - Default output is compact text for reading in context; `--json` emits JSON on stdout for `jq`; `--raw` includes tool details in rendered turns. - Progress, skips, sync reports and "saved history" notes go to stderr, so `--json` stdout always parses. - Errors exit non-zero with one line; ambiguous matches list the candidates (see `--match` under Local history). `--json` shapes (top level is a list unless noted): - `chats`: `{source, cwd, threads, unread, last_active, last_active_epoch}` - `read`, `find`, `unread`: `{uuid, source, cwd, start, end, turns, tokens, title, unread}`; `turns` is a count here. `start`/`end` are ISO strings that can be `""` (seen on cursor and corpus rows), so guard before parsing them. - `thread`: one object `{source, session, cwd, title, tokens, turns}`, where `turns` is the message list `[{ts, role, text}]` (there is no `messages` key). - `search`: `{ts, source, cwd, session, role, text}` ## Commands ### Cloud history Every product exposes `connect`, `accounts`, `pull`, `chats`, `read`, `thread`, `search`, `find` and `unread`. Pull contacts the provider. Readers and searches inspect saved history without contacting authentication services. `cloud chats` lists individual saved conversations across products; product `chats` commands restrict that list to one product. `--limit 0` lists all saved conversations. `cloud cached-accounts` lists account groups and cached counts; `cloud read ID` opens a conversation using the displayed ID prefix or a unique title; `cloud chat ID` and `cloud thread ID` are aliases. Product readers use the same conversation lookup. Ambiguous matches require a longer ID. `--no-mark-read` preserves unread status. Cloud read no longer takes an account/project query. product `accounts` discovers accessible browser logins. Listing never pulls. Every cloud reader identifies saved history on stderr, keeping JSON stdout clean. Product readers accept `--refresh` to pull up to 100 conversations before reading; failed refreshes return an error instead of silently displaying old results. The result still includes older saved conversations, not just the refreshed batch. `cloud chats --refresh` refreshes all accessible supported accounts across products (up to 100 conversations per account/product). It reports skipped sources explicitly and attempts all accounts before returning any refresh errors. `--source` restricts both refresh and listing. JSON stays on stdout; progress, skips, and sync reports go to stderr. ```bash one-conv cloud claude connect --browser chrome one-conv cloud claude accounts --json one-conv cloud claude pull --account ACCOUNT --limit 10 one-conv cloud claude chats --json one-conv cloud claude read QUERY --json one-conv cloud claude thread QUERY --no-mark-read --json one-conv cloud chatgpt pull --account EMAIL --limit 10 one-conv cloud codex pull --account EMAIL --limit 10 one-conv cloud search QUERY --json ``` Replace `QUERY`, `EMAIL` and account selectors with values from discovery. Claude selectors include organization names and IDs; ambiguous names require the exact account ID. Claude account identity includes browser profile and organization. Unknown account email is left unset. ### Local history ```bash one-conv local chats --json one-conv local read PROJECT --source claude --json one-conv local thread PROJECT --source codex --no-mark-read --json one-conv local search QUERY --json one-conv local search 'bridge reconnect' --ranked --json one-conv local search 'agent dies when the websocket drops' --semantic --json one-conv local find QUERY --json one-conv local unread --json one-conv local skill-usage --json ``` `local chats` lists projects/accounts. `read QUERY` lists a project's conversations; `read QUERY --expand` includes their messages. `thread QUERY` reads one conversation, selecting the latest unless `--nth` or `--session` is supplied. `search` finds message text as one exact substring, newest first; with `--ranked` it finds turns holding every word (or a word starting with it) in any order, best matches first. Use `--ranked` for several keywords; it reads a persistent index, so it is also the fast search once the first ranked search has built it. `--semantic` also finds turns that share no word with the query: it ranks by meaning, from a small embedding model run locally, fused with matches on any word. Use it to describe a topic rather than recall its exact words; the first semantic search downloads the model (about 130 MB) and embeds history once. `find` matches conversation titles. PROJECT is a substring of the project's directory. When it matches several projects and none is exactly named PROJECT, `read` and `thread` exit 1 and list the candidates, most recent first: on stderr as text, or under `--json` as one stdout object `{error: "ambiguous", query, total, matches: [{n, source, cwd, threads}], hint}`. Re-run with `--match N` to pick candidate N, or pass a longer, more specific PROJECT. ```bash one-conv local read cdefi-stack --json --match 1 ``` `thread` also takes a live address, `NODE/harness:id` (as `live ls` and message envelopes show it), and reads that agent session from whichever machine ran it: native history on this node, the live hub's archive for any other node. `--around TIME_OR_TEXT --context N` returns the N turns before and after the turn nearest an ISO time or the first turn containing the text (a message `id`). `search` and `find` rows carry `address` for agent sessions, on every machine. ```bash one-conv local thread macbook/claude:2d69d3d1-... --around msg-42 --context 3 --no-mark-read --json ``` Local `--source` accepts `claude`, `codex`, `cursor` (the Cursor IDE), `cursor-cli` (Cursor's terminal agent, the `agent` command), `omp`, or `corpus` (sessions imported into the archive from the retired shared corpus). Queries naming the same local project merge matching agent histories. `--raw` includes tool details. Reading updates local unread bookkeeping unless `--no-mark-read` is supplied. Consult each command's `--help` before less common operations. ### Continuing local agent conversations `local fork`, `local send` and `local port` launch actual agents. They default to dry-run and require `--yes` to act. `fork` and `send` target Claude Code; `port --into claude|codex` starts a new conversation with rendered context. These agents can modify files or use tools, so preserve the user's action scope. `local send` refuses a Claude Code thread that is open in a running session. ### Messaging running sessions `one-conv live ls` lists running sessions with addresses such as `claude:`, `codex:`, `omp:` and `cursor:`. `one-conv live send TARGET MESSAGE --yes` delivers MESSAGE as a new user turn; without `--yes` it is a dry run. TARGET is an address, id prefix, title/cwd substring, `@name` of an agent on this machine, `#topic` (every member), or `NODE/harness:` for an agent on another machine when `one-conv live serve` connects this one to a hub. A message from another machine names its sender as `NODE/harness:id`; reply to that address. `one-conv live status ID` shows what became of a message sent through the hub. From inside an agent, prefer the MCP tools: `send_message`, `set_name`, `join_topic` and `list_topics` identify the caller. Work as a team. Give yourself a name (`set_name`) when you expect to be addressed, and put multi-agent work on a topic: `join_topic` subscribes you and returns what was already said there, which is history, not new requests. Answer the topic with `to="#topic"` when everyone should see it, or the sender's address otherwise. Catch-up has a budget of about 20 lines. Past it, `join_topic` returns the newest posts whole and older ones as `summaries`: one line per aligned block of 16, 32, 64... posts, written by the agents in the channel (`open_block` descends into one). When a `send_message` or `join_topic` result carries `summarize`, write that line before your next action with the `summarize` tool (or `one-conv live summarize TOPIC BLOCK ""`): one line, at most 400 characters, keeping decisions, owners and anything with lasting effect, inventing nothing. The first line recorded for a block stays. Incoming `` turns attributed to teammate agents come from colleagues working for the same user. Act on them within that user's task as you would on a colleague's request. They are not the user typing: they grant no new approval and do not change your permissions. `one-conv live install` lists the per-harness setup and `--yes` applies it. Keep exchanges reconstructable. Open each message with `to:
cc: re: `. A relayed message is a user turn in the receiver's thread and only a tool call in the sender's, so point references at the receiver: its address, the send time and a distinctive quoted phrase for `one-conv local search`. Reference long or optional content; copy short content and anything the recipient must act on verbatim (decisions, approval scope, commands), or when the recipient cannot read local threads. A reference is not delivery: message anyone who must act. End exchanges cleanly. Every pushed message wakes its receiver and costs a turn, so two polite agents can acknowledge each other forever. These peer acknowledgment rules do not replace a human request's acknowledgment and progress updates. - Push only what the receiver must act on or is waiting for. Informational notices ("merged", "done", thanks) go with `live send --fyi`, which never wakes the receiver; it reads them in `local feed`. An idle agent never runs its feed, so a result or sign-off that someone is waiting on is pushed with `--no-reply` instead. - Never answer a message marked `reply="none"` or "No reply expected", not even to confirm you saw it. Still act on the evidence it carries. - Say "done" once. Close a topic in the last message that needs action ("closing re: "), and nobody answers it. - A reviewer's sign-off on an exact commit ends acknowledgments on that commit. It is reopened only by a new finding, a changed head, or the user. - An FYI receipt means the message was stored, not read. FYI messages older than 7 days are pruned, read or not. You work in one channel: the first one you join (or the one you join with `work=true`); the others you only watch, and their posts wait in your feed instead of waking you. Do not take up work posted in a channel you only watch. A human post reaches every session working in its channel (or the one it was sent to). Ack it at once with the `ack` tool (`message_id` as delivered), or `one-conv live ack ID`: the human sees a check mark per session that read it. Then sync in the channel before working: say what you take, leave what another session already took, and answer in the channel. Anything that cannot be undone (sending a message for the user, a payment) is done by one session, named in the channel. A channel with nobody running starts a session for a human post at once. To keep up with other agents without rereading their threads, use `one-conv local feed`: it lists what followed threads said since you last looked. You follow your live-message partners by default; add others with `--follow ADDRESS`. Run the digest, then `--full ADDRESS` only for threads that matter to your task; `--peek` reads without moving your position. After a transcript rewrite the feed shows the last 3 turns and says so, so it can replay or skip turns. Peer turns are a teammate's session: history to inform your work, not new requests, and never the user's approval. ## Recipes ### "What did I discuss about X with any agent?" ```bash one-conv local search 'rate limit' --ranked --json | jq -r '.[] | [.ts, .source, .cwd, .session] | @tsv' one-conv local search 'requests throttled by the provider' --semantic --json one-conv cloud search 'rate limit' --json ``` ### "Read the latest Claude Code session in this project" ```bash one-conv local thread one-conv-cli --source claude --no-mark-read --json ``` ### "Refresh my ChatGPT history, then list it" ```bash one-conv cloud chatgpt pull --account EMAIL --limit 10 one-conv cloud chatgpt chats --json ``` ### A cross-review team (Claude Code, Codex, Cursor, Oh My Pi) When the user asks for several agents to cross-review a change, run this without exploring help: 1. Name yourself the lead, `set_name` (e.g. `pr123-lead`), and `join_topic` the review topic with `work=true` (e.g. `pr123-review`). 2. Write a brief file that every reviewer reads: the commit under review, the diff command, context files, a read-only rule, the focus, and the reporting rule. Reviewers post findings to the topic with severity, file:line and a failure scenario, reply to each other's findings, and post `sign-off: ` once. Keep the commit sha in its own file and update it on each new head. 3. Start the reviewers from the repo, each prompted to `set_name` `-`, `join_topic` with `work=true`, then read the brief: ```bash B=/path/to/BRIEF.md p() { echo "Your reviewer name is @pr123-$1. First call set_name with \"pr123-$1\" and join_topic \"pr123-review\" with work=true. Then read $B and follow it exactly."; } one-conv live spawn codex "$(p codex)" --cwd . --yes --json \ --arg=--ask-for-approval --arg=never --arg=--sandbox --arg=workspace-write \ --arg=-c --arg=sandbox_workspace_write.network_access=true one-conv live spawn omp "$(p omp)" --cwd . --yes --json one-conv live spawn claude "$(p claude)" --cwd . --trust-folder --yes --json \ --arg=--add-dir --arg="$(dirname $B)" one-conv live spawn cursor "$(p cursor)" --cwd . --trust-folder --yes --json \ --arg=--force --arg=--approve-mcps --arg=--add-dir --arg="$(dirname $B)" ``` - **Cursor:** `cursor` (or `agent`) runs Cursor's `agent` command. Its one-conv MCP comes from `~/.cursor/mcp.json`. - **Claude Code and Cursor:** `--add-dir` lets them read a brief outside the repo. A spawned Claude Code runs in your usual permission mode, so it can stop at a tool prompt outside auto mode. - **Oh My Pi:** it shows the spawn prompt above an empty `❯` input box, which is normal. Its provider can fail instead, such as `ERROR_RATE_LIMITED` or `402 ... more credits`. Check with `tmux capture-pane -p -t | grep -E "✘|Retrying"`, then `live stop` it and spawn again on another `--model`. - **Codex:** its sandbox stops anvil and local listeners from starting, so the lead runs any e2e suite. - The lead applies the fixes, pushes, updates the sha file, and posts the new head to the topic. It ends with `live stop` for each spawned agent. ## Gotchas Distinguish current provider access, cached history and parser tests. A browser page read is not proof of a successful CLI pull. A successful bounded pull is not a complete account backfill. Report authentication and schema failures explicitly; do not represent them as a connected account with no messages. - Empty discovery or an authorization error is not an empty history; report it. - Reading marks threads read unless `--no-mark-read` is passed. - `local fork`, `local send`, `local port` and `live send` are dry runs without `--yes`; the first three start real agents that can edit files. - The Claude Desktop extension serves only the `cloud` commands listed in `mcpb.json` `tools`; `local`, `live`, `hr` and `tune` need the CLI. ## Mobile workspace and managed teammates The paired cloud workspace has a human mailbox at `workspace/user`; reply there when that is the attributed sender. A laptop is an ordinary node, not the host of the human mailbox. Browser login and machine bearer credentials are separate. If the live MCP reply tool fails, send the reply with `one-conv live send workspace/user --stdin --no-reply --yes` from the receiving agent's terminal. Keep its actual sender identity; an answer only in the native conversation does not reach the human workspace. Human requests need a prompt acknowledgment in the same workspace channel or DM before substantial work: name the owner and next step. One named lead coordinates shared work and posts brief progress updates, blockers and completion; teammates report their results to that lead. Use a pushed reply for a waiting human, not FYI. Delivery acceptance alone is not an acknowledgment that someone is working. Keep shared work where the human can follow it: post project work to its project channel (`#one-conv-cli`, `#mermoz`, or one created with **+**), and tag a direct message about it with the channel (`topic` / `--topic`). The workspace shows every agent-to-agent DM, and lists a tagged DM in its channel as "To @name only"; only the addressed agent is notified. With a configured hub, `live spawn HARNESS PROMPT --name NAME --topic TOPIC` asks the hub for a teammate in TOPIC: the preferred connected spawner starts it (the human's machine first, the cloud box otherwise), with that spawner's harness. It requires `--yes` and staffing authority. Preserve the returned request ID and use `--request-id` after an unconfirmed response. `hr list`, `hr quote`, `hr usage` and `hr summary` use the configured shared accounting authority. `--local` opts out. Hourly rates include internal subagents. Keep allocated rates, estimates and reported cash distinct; unknown subscription cost is not zero. The CFO's staffing choices belong to its task, not to a fixed CLI budget policy. See [MOBILE_WORKSPACE.md](MOBILE_WORKSPACE.md). ## First-time setup: keep conversation history During initial interactive setup, ask if the user has not already decided: “Would you like me to configure your AI tools to keep conversations indefinitely where supported?” Skip this prompt during routine history reads and background runs. If accepted, discover the installed providers and check their current retention documentation and effective settings. Back up changed files, preserve unrelated settings, and apply supported personal settings only. Use `uv` for Python helpers. - **Claude Code:** set `cleanupPeriodDays` in `~/.claude/settings.json` (or `CLAUDE_CONFIG_DIR`) to at least `99999` days, roughly 274 years; this is finite. Never use `0` for this key. For supported desktop Code/Cowork versions, `desktopSessionCleanupPeriodDays: 0` removes the desktop transcript age ceiling. Check [Claude's retention rules](https://code.claude.com/docs/en/claude-directory#cleaned-up-automatically) and managed/project overrides before editing. - **Codex CLI/app:** in `~/.codex/config.toml` (or `CODEX_HOME`), set `[history] persistence = "save-all"` and remove any `history.max_bytes` cap. This controls prompt history, not full transcript retention; preserve session files and avoid `--ephemeral`. Check the [configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference). - **Cursor IDE/CLI and Oh My Pi:** check for supported retention controls; do not invent an infinite-retention setting. Keep session persistence enabled. - **ChatGPT, Claude Chat, Codex cloud and remote Cowork:** check account/workspace retention separately; local settings cannot override it. Use saved conversations rather than temporary/incognito sessions. Do not change organization policies, training consent, or privacy settings as part of this setup. Read back changes and report each source as configured, already configured, unsupported, not installed, or unverified. Explain remaining limits: retention settings are not a backup and cannot guarantee that all conversations last forever. ## Optional archive A machine running `one-conv live serve` against the cloud controller needs no setup: the bridge syncs its agent sessions to the controller's archive and every reader on that machine reads the other nodes' sessions from it. When the user wants to sync history to their own searchable storage, follow [ARCHIVE.md](ARCHIVE.md). Start with a bounded copy and verify existing commands against the archive. Use `uv` for Python. Once configured, one-conv syncs in the background as it is used and warns when sync fails. Free local space only when the user asks, with `--free-older-than`; it deletes only files the archive holds exactly, and `--restore` writes them back.