I run multiple Claude Code instances in parallel — one per Jira ticket — each in its own tmux session with a dedicated git worktree. A custom attention system tracks which Claude needs me. Here's how it fits together.
-
Ctrl-i— pick a Jira issue, pick a repo, name a branch. A git worktree and tmux session are created. Claude Code launches in a split pane with the Jira ticket context, and we discuss the ticket first (no implementation). When done, Claude writes a YAML outcome file, updates Jira, then restarts in implementation mode. -
Work — Claude writes tests first, implements, runs checks, creates a PR. Meanwhile I'm already on another ticket in another session.
-
Ctrl-e— jump to whichever Claude has been waiting longest for input. A 🤖 in the status bar tells me someone needs me. -
Ctrl-m— pick a session to close out. Squash-merges the PR, walks the Jira issue through transitions to "Done", removes the worktree, deletes the branch, kills the session.
All root-table (no prefix needed), all open fzf in a tmux popup:
| Key | What |
|---|---|
Ctrl-i |
Start Jira issue → discuss → worktree → Claude |
Ctrl-m |
Merge PR → transition Jira → cleanup |
Ctrl-f |
Find/create tmux session |
Ctrl-n |
New branch + worktree |
Ctrl-g |
Switch git worktree |
Ctrl-j |
Find Claude instances (! = needs attention) |
Ctrl-e |
Jump to next Claude needing help |
Ctrl-b |
Broadcast message to multiple Claude instances |
Ctrl-x |
Kill sessions |
Ctrl-p |
Find processes across all panes |
Ctrl-h |
Searchable keybindings help |
Ctrl-_ |
Snippet picker (paste/add/edit/delete) |
The popup walks through fzf dialogs:
- Issue picker — your assigned issues with full preview
- Repo picker — all git repos under
~/projects - Base branch — fetch + branch picker
- Branch name — defaults to
feat/<key>-, or attach to existing session
Then it creates the worktree, launches a tmux session, and splits the window. The right pane runs Claude with a discussion-only prompt:
"This is a DISCUSSION ONLY. Do NOT implement anything. Discuss the ticket: ask clarifying questions, suggest an approach, refine requirements. Keep everything HIGH LEVEL and CONCEPTUAL. You SHOULD read the codebase to understand what exists, but keep responses conceptual."
When you say you're done discussing, Claude writes a YAML outcome:
proceed: true
refined_description: |
...
acceptance_criteria: |
...
implementation_notes: |
...The script pushes the refined description back to Jira, then execs a fresh Claude with the implementation prompt (write tests first → implement → run checks → create PR).
tmux-sessionizer sources a .tmux-sessionizer file in the project root. tmux-jira-start writes one to auto-setup the split layout:
tmux rename-window "repo-name"
tmux split-window -h -p 50 "tmux-jira-start --continue SUP-1234 /path/to/worktree /path/to/repo"- Session picker — sessions enriched with Jira key + summary
- PR check — verifies CI, option to override failures
- Squash merge — editable commit message (defaults to PR title)
- Jira transition — walks the issue through states until "Done"
- Cleanup — removes worktree, deletes branch, kills session
One popup, entire ticket lifecycle closed.
The problem: you have 5 Claude instances running. Which ones are waiting for you?
{
"hooks": {
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "mkdir -p /tmp/claude-attention && printf '%s' \"$(date +%s)\" > \"/tmp/claude-attention/${TMUX_PANE}\" && tmux set-option -t \"${TMUX_PANE}\" -p @claude_attention 1 2>/dev/null; tmux run-shell 'printf \"\\a\"' 2>/dev/null; true"
}]
}],
"PreToolUse": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "rm -f \"/tmp/claude-attention/${TMUX_PANE}\" && tmux set-option -t \"${TMUX_PANE}\" -p -u @claude_attention 2>/dev/null; true"
}]
}]
}
}When Claude sends a notification (waiting for input), a timestamp is written to /tmp/claude-attention/<pane_id>. When Claude resumes work (any tool use), it's cleared.
- tmux-claude-finder (
Ctrl-j) — fzf picker of all Claude instances. Attention ones show!with age (e.g.! session > window (3m ago)). Preview shows last 100 lines. - tmux-claude-next (
Ctrl-e) — jumps to the longest-waiting instance. No fzf, instant switch. - tmux-claude-broadcast (
Ctrl-b) — multi-select Claude instances, type one message sent to all. Remembers deselection state between invocations. - tmux-claude-status — status bar script, shows 🤖 when any instance needs you.
Shows in Claude's footer bar:
feat/sup-4530 │ ctx:45% │ $1.23 │ 5h:12% 7d:3% │ +150/-30 │ 14:30
Git branch, context window usage (color-coded red/yellow/green), session cost, rate limits, lines changed, time. Configured via ~/.claude/settings.json:
{ "statusLine": { "type": "command", "command": "~/.claude/statusline.sh" } }Every Claude tool call is logged:
{ "command": "jq -c '{ts: (now | todate), tool: .tool_name, input: .tool_input}' >> ~/.claude/permission-audit.jsonl; true" }- tmux-new-branch — repo picker → base branch → branch name → worktree → session. Like
tmux-jira-startwithout the Jira/Claude parts. - gwts — quick worktree switcher. Repo picker → branch picker → open existing or create worktree → session.
- tmux-session-kill — multi-select fzf to kill sessions (current excluded).
- tmux-fzf-processes — lists all processes across all tmux panes with descendant tree. Preview shows pane content. Select to switch.
- tmux-help — parses
~/.tmux.confinline comments + all active bindings into searchable fzf. - tmux-snippets — snippet manager. 4 modes cycled with Tab: paste, add, edit, delete. Stores in
~/.config/snippets/, loads into tmux paste buffer.
brew install tmux fzf jq yq zoxide
brew install go-jira # https://github.com/ankitpokhrel/jira-cli
brew install gh
npm install -g @anthropic-ai/claude-codegithub.com/markwallsgrove/dotfiles — scripts in .local/bin/, tmux config in .tmux.conf.