# Tabs, worktrees and sessions
`ctrl+t` — or `/new` — opens a second conversation in a tab. A tab is a whole
session: its own agent, its own history, its own approvals, its own subagents
and its own file under `~/.config/chats/<repo>/`. Nothing crosses between them but the
model you are on and the terminal they share, so a turn running in one tab is
not interrupted, approved or compacted by anything you do in another.
1 ◍ fix the parser 2 ● read the spec 3 new session
The strip appears when there is more than one tab and goes away when there is
not: a single session looks exactly as it did before, down to the row count. A
tab is named after the first thing asked of it. `◍` means something is running
in there; `●` means it said something while you were somewhere else.
A new tab starts in the working root of the one you opened it from, so a
second conversation about a worktree is in that worktree. `alt+w` or `/close`
closes a tab — it refuses while something is still running there, and closing
the last one leaves Codey.
`/worktree` branches the work off into a git worktree under
`~/.config/codey/worktrees`. It reads its argument three ways, and which one
you get is visible in what you typed:
/worktree dark-mode a name — made and moved into, nothing else
/worktree add a dark mode toggle a task — named for you, then started on
/worktree resume a chooser of the trees that already exist
One word is a name and is used as typed, so the quick case never waits on a
network call. A phrase is a description of the work: a small model turns it
into a name, the tree is made, and the agent is then set to work on it in the
new directory. Whatever the model answers is slugified and bounded before it
reaches the filesystem, and if the naming call fails the task's own opening
words are used instead — a name is not worth failing the command over.
The tree is made by `~/.config/codey/worktree.sh`, which is written once with a
default and is yours to edit afterwards. Codey never overwrites it, so a script
taught to copy a `.env` or install dependencies keeps doing so. The contract is
two lines wide: the name arrives on stdin, and the absolute path of the tree is
the last line of stdout. The script decides where the tree lands, so moving
them somewhere else is an edit to that file and nothing more.
What moves is the work — what the tools read and write, where `!` commands run,
and where subagents are spawned. What stays is the session: the conversation is
still filed in the checkout you started in, alongside the event log, so one
directory holds the whole history of what was done from it rather than a trail
scattered across worktrees. The tree is recorded in the session, so reopening
that conversation — with `/resume` or `-resume` — puts the work back in it. If
the tree has since been deleted, Codey says so and carries on in the main
checkout.
`/worktree resume` goes the other way: into a tree that already exists, with a
new chat in it. Bare, it opens a chooser of every worktree this repository has
— git is asked, so a tree the script put somewhere unusual is still found —
most recently touched first, with the branch checked out in each. Typing
narrows the list: the match is fuzzy, so `dkmd` finds `dark-mode`, and a
branch name finds its tree too. `/worktree resume <name>` skips the chooser.
The checkout you started Codey in is offered alongside the trees, marked as
such, because once the work has moved there has to be a way back. What you get
in the tree is a *new* conversation, not the old one: the chat on screen is
saved first and stays where it is, and the next turn is filed under a new
session that records the tree — so `/resume` can go back to either. Reach for
`/worktree resume` when you want to work in a tree again, and for `/resume`
when you want a particular conversation back.
`/resume` switches to an earlier conversation without leaving Codey. Bare, it
opens a chooser: one row per saved session, named by the first thing you asked
it, newest first, with how long ago it was and what it ran on. `/resume <id>`
goes straight there. Either way the conversation on screen is written out
first, the chosen one is replayed into the transcript, and the next turn saves
into it.
The list is scoped to the working root, and so is `-resume`: a session recorded
in `/home/joni/test` cannot be opened from `/home/joni/test2`. Sessions are
filed under the root they were made in to begin with, and the root each one
records is checked again on the way out, so a session file copied between
checkouts is refused rather than resumed into a tree where none of the paths it
discusses exist.