How rostr works
The short version
rostr assemble installs hooks into Claude Code and Codex. Each hook calls the rostr CLI, which keeps your rosters and who's drafted where: in a local SQLite database, or on the rostr API in cloud mode, so sessions on every machine draft from the same rosters.
On a session's first prompt, rostr drafts a name, tells the agent who it is, and puts the name in the session's title. While the session works, the hooks keep the name alive. When it ends, the name goes back to the bench.
Drafting a name
Each session is drafted from the roster linked to its project, else your default roster. The pick goes:
- Least recently drafted. The free member drafted longest ago, so names cycle through the whole roster.
- Take a resting name. If everyone's busy, the name of the session that has rested longest.
- Copies. If no one is resting either, a numbered copy like 🧙 Gandalf 2. A session always gets a name.
A resumed session gets its old name back, if no one else has taken it since.
In cloud mode, Claude Code sessions draft in the background as soon as they start, so the first prompt doesn't wait on the network.
Resting and benching
A member is drafted, resting, or on the bench.
- Resting. A session that finished its turn and gets no new prompt for 15 minutes is resting. It keeps its name, but when every other name is taken, a new session can take it. If that happens, the resting session gets a new name on its next prompt, and the agent is told.
- Keep-alive. Each prompt and turn tells rostr the session is still around, and later prompts check in at most once an hour.
- Benching. When a session ends, its name goes back to the bench. A session that's never seen again, like a closed desktop session, is benched after 24 hours (
rostr config expiry), androstr bench <name>frees a name sooner.
Telling the agent who it is
The hook tells the agent its name, and to sign anything it writes outside the chat with it, like PR descriptions and Slack messages. After compaction, it's told again.
Commands the agent runs, like rostr task, need to know which session they're in. In Claude Code, the start hook appends export ROSTR_SESSION=<session ID> to the session's env file (the path Claude Code passes in CLAUDE_ENV_FILE), and Claude Code loads that file before every shell command the agent runs. Codex sets CODEX_THREAD_ID in its commands' environment itself, so rostr reads that. Therostr task command the agent is told to run also names the session with --session, so it works even where neither variable is set.
The hooks
Both agents get the same five hooks. Each one is a one-liner that runs rostr hook only if rostr is installed, so the logic lives in the binary and updates when you upgrade. After an upgrade, the first session reinstalls the hooks if they've changed.
SessionStart- Claude Code: records the session in
ROSTR_SESSIONand, in cloud mode, drafts ahead. Both: get the old name back on resume, and re-tell the name after compaction. Codex: drafts a forked thread. UserPromptSubmit- First prompt: drafts, tells the agent who it is, and starts the title (below). Later prompts: end a rest, keep the name alive, and retitle the session if its task changed.
PostToolUse- Marks the session as working again. Claude Code: after a title call, records the summary as the task and tells the agent to carry on with its answer.
Stop- Records that the turn ended, which starts the 15 minutes until the session rests.
SessionEnd- Benches the name and clears the pane label.
Hooks never block a session. Network calls time out after 3 seconds, and anything slow runs in the background. If rostr can't draft, the session just starts unnamed.
Titles in Claude Code
The title is <name> · <3-5 word summary>. Who writes the summary depends on where the session runs:
| Where the session runs | How the title gets there |
|---|---|
| Terminal | The first-prompt hook sets <name> · <start of your prompt>, so the name shows straight away. rostr summarizes your prompt in the background with claude -p --model haiku, on your own login, and puts the summary in the title on your next prompt |
| Desktop app and cloud sessions | Before writing anything, the agent calls the app's set_session_title. In Local sessions it loads the tool with ToolSearch first |
The summary is recorded as the session's task, which rostr stats shows. When the task changes, later prompts retitle the session to match.
Why the agent writes the summary in the app
Hooks can only set a title when a prompt arrives. In a terminal, that's the best there is: the summary shows up on your second prompt. The app can do better, because it gives the agent a title tool. The agent already knows the task, so it titles the session in its first reply.
The title tool is also the only option in Remote Control and cloud sessions, where a hook's title doesn't show up at all (a known Claude Code bug).
Why the title comes first
Recent models can turn text written just before a tool call into a progress update, a short summary of it. So an answer followed by a title call could show up twice: once as a summary, then again in full. The first thing in a reply is never turned into one, so the agent sets the title before writing anything.
Titles in Codex
The title is <name> · <Codex's own title>. On the first prompt, rostr drafts a name and tells the agent who it is, but leaves the thread unnamed. Codex's TUI and app then title the thread themselves, usually within a few seconds. rostr waits for that title in the background, makes it the session's task, and renames the thread to <name> · <title>.
Why rostr waits for Codex
Codex hooks can't set a title, so rostr names threads through the Codex app-server instead. Codex only titles a thread that has no name, and drops its title if the name changes while it's writing one. Naming the thread on the first prompt would mean no summary, so rostr waits and adds the name to Codex's title. The summary costs no extra tokens.
Token use
rostr adds a few hundred tokens to a session, almost all on the first prompt. Later prompts add nothing unless the session is renamed.
- Every session. The rostr skill's one-line description sits in the agent's skill list, about 80 tokens. The full skill loads only when you ask about rostr.
- First prompt, Claude Code. The agent's identity, about 120 tokens. In the app, the title request (about 100 more) and one short title call, which in Local sessions first loads the title tool. In a terminal, there's no title call:
claude -p --model haikusummarizes up to the first 4,000 characters of your prompt instead, on your own login. - First prompt, Codex. Only the agent's identity, about 120 tokens. The title is the one Codex writes anyway.
- Now and then. After compaction, or when a resting session is renamed, the agent is told its name again, about 120 tokens.
tmux and herdr
When a session is drafted or renamed, rostr labels its pane: herdr shows the name as the pane's agent, and in tmux a window with a single pane is renamed to it. The label is cleared when the session ends.
Claude Code runs its hooks inside the session's own pane, so rostr knows which pane to label. Codex runs hooks in a shared background process, whose pane is whichever terminal started it, and nothing ties a thread to the terminal showing it. So rostr works from the title instead: it has just named the thread, and Codex puts the thread's name in its terminal title. rostr labels the one Codex pane whose title shows the new name, and labels nothing if it finds none or more than one. If you set a custom tui.terminal_title in Codex, include thread-name.
Privacy and security
Local mode's only network call downloads the list of pre-built rosters. In cloud mode, tasks and repo names are encrypted on your machine before they're sent, and the server never sees your rostr key, prompts, or code.