migrate-to-pane · diff
git:20261027.06b2daa to git:20261030.0da9f8f
132 added, 11 removed. Audit A to A.
---
name: migrate-to-pane
- description: Bring the agent sessions a person already has (Claude Code, Codex, OpenCode, Cursor, Conductor, or any similar tool) into Pane, each opened in a Pane tab with its own agent's resume, verified, and reported. Use for "migrate to Pane", "bring my sessions into Pane", "import my Claude/Codex/Cursor chats", or after the person says yes to Pane's first-run offer.
+ description: Bring the agent sessions a person already has (Claude Code, Codex, OpenCode, Cursor, Conductor, or any similar tool) into Pane, each opened in a Pane tab with its own agent's resume, verified, grouped into Sessions, and ending in a Start here page. Use for "migrate to Pane", "bring my sessions into Pane", "import my Claude/Codex/Cursor chats", when the Onboarding Session's first prompt says the person said Yes on Pane's first-run screen, or when it asks for a Start here page without a migration.
---
# Migrate to Pane
The person wants their work, exactly as it was: every conversation they have
going in other agent tools, opened in Pane, picking up where it left off. The
same native session, resumed by its own agent, in the same checkout when
possible. Not a summary, not a fresh agent told what happened.
It works with any agent tool that keeps resumable sessions. Claude Code, Codex,
OpenCode, the Cursor agent and Conductor are the common ones; if you find
another, treat it the same way.
The bar is the [continuity check](references/continuity.md). Read it before you
start. A session is reported as continued only when it passes.
+ ## Two ways in
+
+ - **First-run Yes.** The Onboarding Session's first prompt says the person said
+ Yes on Pane's first-run screen. That Yes is their confirmation of the
+ preselected set: sessions running now or active in the last 7 days. Start at
+ once, show no list and ask nothing before placing. Everything older is left
+ out and listed as such on the Start here page. Steps 1, 3, 4, 5 and 6 apply.
+ - **Asked in a chat** ("migrate to Pane"). Show the list and wait for the
+ person to confirm it (step 2) before placing anything. Steps 5 and 6 apply
+ when this chat is the Onboarding Session.
+
+ A first prompt that asks for a Start here page without a migration follows
+ [Start here without a migration](#start-here-without-a-migration).
+
+ ## How it reads in the chat
+
+ The person sees a few plain lines, not a log:
+
+ - "Found 18 sessions in 4 repos."
+ - "Opening lev-web, 5 of 18."
+ - "All 18 are open. Grouping them into Sessions."
+
+ No session ids, hashes, paths, commands or command output in any message. Keep
+ those in the migration record and the Start here page's details.
+
+ The first time you create a Session, a Pane and a tab in this conversation,
+ say in one sentence what it is, then carry on:
+
+ - Session: "A Session is one task's home: its chat and the Panes doing the work."
+ - Pane: "A Pane is one branch in its own folder."
+ - Tab: "A tab is one agent or page inside a Pane."
+ - The first time a Session gets Panes under it: "The Panes under a Session are
+ sub-agents its orchestrator agent runs for you."
+
+ In the Onboarding Session, every message calls the agents in Panes sub-agents,
+ never workers. Leave model choice and cost out of these explanations and the
+ Start here page.
+
## Ground rules
- **Never disturb live work.** Never write to, append to, stop, or send input
to an original session that is running elsewhere. Never delete, archive or
close anything in another tool's store. Writing new files into a tool's store
(a fork, or a session moved for a new folder) is allowed.
- **Learn on throwaways, never on the person's sessions.** To find out how a
tool resumes or forks, read its docs and `--help`. If you must try a command,
try it on a throwaway session you create for that purpose and then remove.
Never resume, fork, prompt or open one of the person's sessions to see what
- happens, and never touch a session before the person has confirmed the list.
+ happens, and never touch a session before the person has confirmed the list
+ or said Yes on the first-run screen.
- **Two agents never edit one folder.** A session still running elsewhere is
forked into a worktree of its own. When you can't tell whether a session is
still running, treat it as running: a wrong guess then costs a worktree, never
two agents in one checkout.
- **One copy of each id per store.** Never leave two copies of one session id in
one tool's store on one machine; some agents then can't find it.
- **The person's checkout stays theirs.** Adopted checkouts are never removed:
never pass `--remove-worktree` when archiving a Pane this skill created.
- **Prefer each tool's own features.** Resume and fork with the tool's own
commands. Edit store files only when the tool has no command for it.
- **Report failures; don't paper over them.** A session that can't be continued
is reported as not continued with the reason and the next step, never
replaced by a fresh agent.
## What you already know
The Pane data directory is in your runtime context (`runtime-context.md`). Pass
it as `--pane-dir` to every `runpane` command, as the runtime context says.
Keep a migration record at `<Pane data directory>/migrate-to-pane/record.json`,
one entry per session you placed:
```json
{ "sessions": [ { "tool": "codex", "id": "<source id>", "folder": "<source checkout>",
"paneId": "<pane>", "panelId": "<tab>", "forkId": "<fork id, or null>",
"result": "continued | continued as a fork | not continued", "at": "<ISO time>" } ] }
```
Read it at the start of every run. A session whose `tool` and `id` are in it
with any result other than "not continued" is "already in Pane", forks
included, so a rerun creates nothing twice; a "not continued" one can be tried
again. Pane's "Bring your sessions into Pane" card brings idle sessions in and
writes this same record, with `tool` set to the agent, a `source` naming the
tool, and `result: "pending"` for a tab that was still starting or waiting at
its trust prompt.
## Keep it fast
A run should feel like a few minutes, not half an hour. Almost all of the time
is waiting on agents to start, so never wait on one session at a time:
- **Discover in one pass.** One metadata script per tool (ids, folders,
branches, times, titles, running or not), not a command per session. Read a
tool's `--help` once, only for what you don't already know.
- **Start everything, then wait once.** Register all repositories, then start
every adopt, tab and fork Pane without `--wait-ready`, back to back. Run
independent commands concurrently in the shell (`cmd & cmd & wait`), and
create several fork Panes in one `runpane panes create --from-json`.
- **Fork in parallel.** Start all forks at the same time; each one is a short
agent turn.
- **Check all tabs together.** Wait for every tab at once (one background
`runpane panels wait --panel <id> --for ready` per tab, then `wait`), read
every screen in one pass, and probe only the tabs whose history is unclear,
all probes at once. When a wait reports a first-run dialog (a trust prompt,
for example), answer it with the command it suggests and keep going.
Pane sets up each new worktree Pane through its setup queue, two at a time, so
a repository with a slow setup script bounds how fast fork Panes can start.
Adopted checkouts need no setup.
## 1. Find the sessions
The person said yes, so start; don't ask for permission to read other tools'
files.
- Find every agent tool in use on this machine: the tools' own stores in the
home folder, tools inside each WSL distro Pane knows (on Windows), Conductor
workspaces, and agents running right now in other terminals, VS Code, or any
editor (the process list, and each tool's own live-session records). Work out
where each tool keeps its sessions, and how it resumes and forks them, from
that tool's own docs, `--help` and files. These formats are internal and
change, so look rather than remember.
- **Read metadata first**: ids, folders, branches, times, titles. Don't read
whole transcripts to build the list; open a transcript only to verify a
session the person chose.
- For each session, work out whether it is running now, its git checkout
(repository root, branch, whether it is a linked worktree), and when it was
last active.
- Leave out your own session (this Pane Chat). Mark as **already in Pane** every
session a Pane tab already runs (`resumeId` in `runpane panels list --pane
<id> --json` for each Pane in `runpane panes list --json`, or a launch command
naming its id) and every session the migration record holds in Pane (any
result other than "not continued").
- ## 2. Show the list and confirm
+ ## 2. Show the list and confirm (asked in a chat)
- Show one list, grouped by repository. For each session: tool, title, branch,
+ Skip this step on the first-run path. Show one list, grouped by repository. For each session: tool, title, branch,
last active, and "running" when it is. Preselect sessions that are running or
were active in the last 7 days. List older ones unselected, so the person can
add them. Show "already in Pane" ones without a way to select them, and list
sessions with no folder or outside any git repository so they can be reported.
Create nothing until the person confirms the selection: no repos, Panes,
tabs, forks or trial runs, and no change of any kind to a session's files.
## 3. Place each chosen session
Register each repository once with `runpane repos add --path <repo root>`
- (skip it when `runpane repos list --json` already has it). Then, per checkout:
+ (skip it when `runpane repos list --json` already has it). Name each Pane
+ "<project> · <branch>". From the Onboarding Session, pass `--no-associate` to
+ every adopt and create, so each Pane can join its own Session in step 5. Then,
+ per checkout:
- **Idle session, checkout is the repository's main checkout or one of its
worktrees**: adopt the checkout in place. The first session in a checkout
opens with `runpane panes adopt --repo <repo> --path <checkout> --name <name>
--agent <agent> --resume <id> --launch` (OpenCode: `--tool-command "opencode"`
with `--resume <ses_ id>`). Each later session in the same checkout becomes
another tab in that same Pane: `runpane panels create --pane <id>
--tool-command "<the agent's own resume-by-id command>" --agent <agent>
--yes`. Pane runs that command unchanged and runs it again after a restart.
Same folder, so nothing in the session needs rewriting.
- **Idle session in a clone that isn't a worktree of a registered repository**:
register that clone as its own repository, then adopt it in place.
- **Idle session that can't be adopted in place** (for example a detached copy of
a repository already registered from elsewhere): move the session so its
agent finds it from the new folder, leaving one copy of its id in the store,
then create a new Pane on the session's branch the same way as a fork below,
resuming the session's own id, and carry the uncommitted and untracked files
across. It gets the "moved" message.
- **Running session** (or not sure): fork it first, with the tool's own fork, so
the fork has its own id and the original is untouched. Some forks append to
the original (a fork command run inside the original chat, for example), so
pick one that doesn't. Then create a new Pane on a new branch from the
session's current commit, with the fork's resume as its tab: `runpane panes
create --repo <repo> --name <name> --branch <new branch> --base <commit>
--tool-command "<the agent's own resume-by-id command for the fork>"`. The
resumed agent waits for input, so next copy the checkout's uncommitted and
untracked files into the new worktree until `git status` and the file
contents match the source. The original keeps running in its own
checkout. Cursor has no fork command, and a copy of a Cursor chat still
writes to the original chat once it is used, so a running Cursor session
has no such fork. When a tool has no fork that leaves the
original untouched, don't fork: report the session as not continued
("still running elsewhere; close it there and say 'migrate to Pane' again").
Record each original's size, sha256 and modification time before you fork
it, and compare them once the fork's tab is open: check 4 of the continuity
check.
A fork with no turn of its own can lead its tool back to the original when
it is opened (an empty Codex fork, for example, made the tool write to the
original's file), so prefer a fork that carries one short turn of its own.
- **Several sessions in one checkout** become tabs in one Pane, each resumed by
its own id.
- **No folder, or outside any git repository**: create nothing for it; report it
as not continued, with why and what the person can do.
Run the fork command first and read the fork's id from its output or store; only
then run the command that opens the fork's Pane, so the tab resumes that id.
Write each session to the migration record as soon as its tab exists.
- ## 4. Check, then report
+ ## 4. Check
Run the [continuity check](references/continuity.md) on every tab you opened,
send any "moved" messages after it passes, and keep going when one session
fails: the rest of the run still completes.
- Finish with one report, grouped by repository: each session as **continued**,
- **continued as a fork**, or **not continued**, with its Pane and tab, and for
- anything not continued, what happened, why, and the next step. Mention the
- sessions you left unselected and how to bring them in later: say "migrate to
- Pane" again.
+ Outside the Onboarding Session, finish with one report, grouped by repository:
+ each session as **continued**, **continued as a fork**, or **not continued**,
+ with its Pane and tab, and for anything not continued, what happened, why, and
+ the next step. Mention the sessions you left unselected and how to bring them
+ in later: say "migrate to Pane" again. In the Onboarding Session, steps 5 and 6
+ replace that report.
+
+ ## 5. Group the work into Sessions
+
+ One Session per workstream: Panes on the same branch or the same topic belong
+ together. For each workstream:
+
+ - Read its transcripts' last turns and write a readable name, its goal, its
+ context, and its next action. Create it with `runpane sessions create`
+ (`name`, `goal`, `context`, `nextAction`); its result names the Session's
+ chat tab (`panelId`).
+ - Associate its Panes with `runpane sessions associate`, and pin the Sessions
+ with work in the last day with `runpane sessions pin`.
+ - Send its chat the catch-up, so the person finds it waiting there. A saved
+ next action is context only; the chat starts on it only when asked. Wait
+ for every new chat at once (`runpane panels wait --panel <panelId> --for
+ ready`, one per Session in the background, then `wait`), then send each
+ `runpane panels submit --panel <panelId> --text "Catch me up: in two or
+ three short lines, where does this work stand and what is the next step?
+ Use this Session's saved goal, context and next action, then wait for me."
+ --yes`.
+
+ Name every Pane "<project> · <branch>" (`runpane panes rename` for any that
+ already existed under another name).
+
+ ## 6. Make the Start here page
+
+ Copy the template [references/start-here.html](references/start-here.html) and
+ fill it as its comments say. Save it as
+ `<Pane data directory>/migrate-to-pane/start-here.html`, next to the record,
+ and open the rendered page beside this chat with
+ `runpane panels open --url <file URL of that path> --source agent --yes`. The
+ file URL is `file://` plus the absolute path with each path segment
+ percent-encoded, for example `file:///Users/ana/.pane/migrate-to-pane/start-here.html`
+ (on Windows, `file:///C:/Users/ana/.pane/...`). `--file` only opens files
+ inside this Session's folder, and as editable source.
+
+ - **Workstreams**: one row per Session from step 5, its name linked to the
+ link `runpane links create --session <id> --json` returns, then its goal and
+ next action in one line each.
+ - **Receipt**: every session from step 1, grouped by repository, with its
+ result, and every session left out, with why. It matches the migration
+ record exactly: same sessions, same results.
+ - **What to try next**: from the template's ladder, the 3 to 5 rungs that fit
+ what you saw, in ladder order. Each try-now prompt names one of the person's
+ real repos or branches.
+
+ End the chat with two or three plain lines: how many sessions came over, how
+ many Sessions hold them, that Start here is open beside the chat, and then
+ "Want me to do any of these now? Say the number." When the person answers with
+ a number, start that rung's try-now task in this chat.
+
+ ## New tasks after Start here
+
+ The Onboarding Session owns no work of its own. When the person asks it for new
+ work, give the task its own new Session, even when it touches a repository or
+ branch an existing Session already covers. Use an existing Session only when
+ the person names it.
+
+ 1. `runpane sessions create` with a readable name, the goal, the context you
+ have, and the next action.
+ 2. Create the work's Pane, named "<project> · <branch>", with `--no-associate`, then
+ `runpane sessions associate --session <new session> --pane <pane>`, and send
+ the task to the Pane's agent.
+
+ Onboarding and the other Sessions gain no Pane. Tell the person in one sentence
+ that the task now has its own Session in the sidebar, and that its chat picks up
+ from there.
+
+ ## Start here without a migration
+
+ When the first prompt says the person said Not now, or Pane found no sessions,
+ bring nothing in. Make the Start here page for the projects they opened: the
+ template without the receipt section, workstreams only for work already in
+ Pane (often none: say so in one line), and try-now prompts that name their
+ repositories. In section 4, keep the first and third answers and delete the
+ second ("Is my real chat the old one or the new one?"), which is about migrated
+ sessions. Renumber the section headings so they run 1 to 5. Save and open it as step 6 says, and end the chat the same way.
+ If they opened no project, the try-now prompts start with adding one.