A tmux layout for running the pipeline: pane 0 is the lead (claude when
installed, otherwise codex), pane
1 is opencode serve (what scripts/oc.sh attaches to), pane 2 tails
.agents/ for activity, pane 3 is free.
scripts/team.sh [session-name] start, or attach if it's already running
scripts/team.sh --fresh start a NEW lead conversation, not a resume
scripts/team.sh --lead <name> auto (default), claude, or codex
scripts/team.sh --port <N> opencode server port (default 4096)
scripts/team.sh --kill [session-name]
Flags can combine with a session name in any order:
scripts/team.sh --port 4097 my-second-project.
--lead auto prefers Claude when claude is installed and falls back to Codex
when it is not. Use --lead claude or --lead codex to override that choice;
TEAM_LEAD provides the same default as an environment variable. When creating
a session, the script fails before creating panes if the selected CLI is
unavailable; attaching an already-running session does not require the CLI to
remain discoverable.
In a Codex pane, invoke $feature <request>. The generated repository skill
drives the same pipeline as Claude's /feature command.
Pane 0 resumes the lead's own conversation — not a fresh one — but it does
so by pinning to a stored UUID (.agents/.claude-session-id.<session-name>,
written the first time that session name runs) rather than
claude --continue. --continue only means "the most recent conversation
in this directory," with no notion of which tmux session started it, so
running a second scripts/team.sh session name against the same repo (or
just running a one-off claude there for something unrelated) could make
the next --continue resume the wrong thread entirely. The pinned id
removes that ambiguity: each session name always resumes its own
conversation via claude --resume <uuid>, however many other Claude
conversations have happened in the same directory since.
This exists because killing the tmux session (the usual way to free up a
port, or just closing the terminal) used to also throw away the lead's
context, with no way back into the same conversation. Now: kill it, come
back later, run scripts/team.sh again, the lead is where you left it.
Pass --fresh on the rare run where you actually want a clean slate
instead — this mints a new pinned id, so later resumes follow the new
conversation, not the old one.
Codex has no create-with-session-id equivalent. Without --fresh, the launcher
uses codex resume --last, whose lookup is scoped to the current repository;
if no saved session exists it starts codex. With --fresh, it starts a new
Codex conversation directly.
opencode serve binds one port per process. Two projects both defaulting
to port 4096 collide — the second one's server fails to bind, and until
now the only fix was killing the first project's session. Instead, give
the second project its own port:
scripts/team.sh --port 4097
That port gets written to .agents/.oc-port in this repo. scripts/oc.sh
reads it automatically (when OC_SERVER isn't already set), so every
oc.sh call in this project just uses the right port — you don't export
OC_SERVER by hand for every call.
.agents/.oc-port is gitignored automatically by bin/init.sh when
the target is a git repo — it's local machine state (which port happened
to be free on your laptop today), not something to commit. If your project
predates that, or ignores it differently, add it by hand.
scripts/team-completion.bash completes --fresh, --lead, --port, --kill,
and -h/--help. It's not installed automatically — source it from your
shell rc file if you want it:
# ~/.bashrc or ~/.zshrc (zsh needs `autoload -U +X bashcompinit && bashcompinit` first)
source /path/to/this/repo/scripts/team-completion.bash