Conductor, but it lives in your terminal.
A small worktree manager that never loses a conversation. You name a task; t
gives that task a git worktree, a branch, and a permanent link to every chat any
agent has ever had inside it — Claude, Codex, Grok, Gemini, in any mix.
Delete the worktree six months later. The conversation still resumes.
And it stays out of your way. tmux, herdr, Zellij, iTerm splits, plain terminal
tabs — whatever you already use, keep using it. t never splits, spawns, or
rearranges a single pane. It has one job and does not want yours.
$ t new "fix vault sync" # worktree + branch, cds this pane into it
<prefix+v> # you split, however you like
$ t claude # launches here, linked to the task
<prefix+v>
$ t codex # same worktree, same task, different agent
Why t
It is short for task. It is also the entire name, which is the design in miniature: you will type it fifty times a day, so it costs one keystroke and asks nothing of you.
The working title was task-centric-agentic-worktree-orchestrator. It did not
survive first contact with the keyboard.
The problem
Every agent decides where to put your transcript based on the working
directory — and each one does it differently. Claude Code bakes the path into
a directory name, so deleting a worktree orphans the conversation: it is still
on disk, but claude --resume can never see it again.
On the machine this was built against, 55 of 109 Claude conversations were already unreachable that way. Every byte intact. The link gone.
t stops deriving the link and writes it down instead:
~/work/myrepo/fix-vault-sync/.agent/
task.json repo, branch, base, worktree, created
sessions/
claude-f546376a….json provider, session id, transcript path, pane
codex-019cd415….json
grok-019fd204….json
One file per session, and a session only ever touches its own — ten agents starting at once produce ten files and zero races.
For Claude and Grok the id is assigned before launch (--session-id), so
the link exists before the conversation does. Codex and Gemini have no such
flag, so t stamps the launch time and matches the session whose recorded cwd
is this worktree.
If you know Conductor
I really liked the Conductor experience. I just love my own setup more.
That is the whole reason t exists. Conductor showed that the link between a
worktree and a conversation should be written down rather than re-derived from
a path — that is the insight, and t takes it wholesale. What it does not take
is your terminal: no app window, no managed layout, no separate place you have
to go to read your own history.
| Conductor | t |
|
|---|---|---|
| interface | a Mac app | your terminal, unchanged |
| storage | its own database | the vendor transcript, verbatim |
| resuming | in the app | hands the id back to the real CLI |
| pane layout | manages it for you | never touches it |
Same idea, different room.
Commands
t new "short description" |
worktree + branch, cd this pane into it |
t claude | codex | grok | gemini |
launch an agent here, linked to this task |
t |
status of the task this pane is in |
t sessions |
pick a past conversation and resume it |
t resume <# | id> |
resume without the picker |
t ls |
every task, with git and session state |
t open <task> |
cd this pane into another task |
t find <query> |
search every conversation, every provider |
t done [task] |
archive this task's conversations to the vault |
t doctor |
check the environment |
t import |
(deferred) pull Conductor's history into the vault |
Picking a conversation
t claude always starts a new chat. To go back to an old one:
t sessions # arrow-key picker, enter resumes
t sessions --all # every session on the machine, not just this task
t sessions --list # plain output, for scripting
8 session(s)
▸ claude fix-vault-sync 2026-08-05 the sync drops every record with a null tenant
codex redesign-page 2026-08-04 the build broke after the upgrade
claude old-migration 2026-07-21 how do I restrict this to a subset of repos
That third one is three weeks old and its worktree is long gone. It still resumes.
↑↓/jk to move, / to filter, enter to resume, q to quit. The picker is
stdlib curses — no fzf needed.
Sessions whose worktree no longer exists are listed too. Choosing one copies
its transcript into the current worktree (with subagents/ and
tool-results/) and then hands the id back to the CLI that wrote it, so the
conversation genuinely continues instead of being replayed read-only. It is
then linked to the task you resumed it in.
Same thing without the picker:
t resume 3 # by row number from the last listing
t resume dead1111 # by session id prefix
t claude -c # continue this task's most recent claude session
Install
git clone https://github.com/PiemonteF/t.git ~/.local/share/t/src
cd ~/.local/share/t/src
./install.sh # config + work root, prints the .zshrc line
./install.sh --shell # also append the wrapper to ~/.zshrc
./install.sh --hooks # also register the capture hook (see below)
Clone it wherever you like — the installer records that path as T_HOME, so
t keeps working from there. Nothing is copied outside ~/.config/t and your
.zshrc.
The shell wrapper exists because a child process cannot change its parent's
working directory. t new and t open write the cd they want to a temp file
and the wrapper sources it.
The --hooks step is optional and merges into your existing hook config —
hooks it did not write are left alone, and the file it edits is backed up first.
It covers the case where you split a pane and just type claude out of habit:
the agent hands its session id to the hook, so the link is recorded anyway.
With it installed, there is no way to run an agent inside a task worktree
without it being written down.
Config
~/.config/t/config.json
{
"work_root": "~/work",
"vault": "~/.local/share/t/vault",
"repos": {
"myrepo": { "base": "origin/dev", "copy": [".env"], "setup": "npm i" }
}
}copy are the files git will never carry across; setup runs once in the new
worktree.
Bring your own multiplexer
There is nothing to configure here. t is a plain CLI that acts on the current
directory, so tmux, Zellij, herdr, iTerm splits, WezTerm, or four bare terminal
tabs all work identically. Split however you like; run t claude in whichever
pane you landed in.
The only thing worth doing is making new panes inherit the current directory —
tmux split-window -c "#{pane_current_path}", or the equivalent in your tool —
so a fresh pane is already inside the worktree.
herdr
If herdr — a terminal pane manager — happens to be on PATH, t also:
- reads
HERDR_PANE_ID/HERDR_WORKSPACE_IDand records which pane a session is running in - calls
herdr pane report-agent-session --agent-session-id --agent-session-pathso herdr's own sidebar andherdr agent listknow the session too - renames the pane to the task name
With new_cwd = "follow" in the herdr config, every pane you split is already
inside the worktree. All of it is best-effort; t behaves the same without it.
Requirements
git, python3, ripgrep (for t find), and at least one agent CLI. No
multiplexer, no daemon, no database.
See DESIGN.md for the storage layout of each provider and why the design is shaped this way.