butmux
v0.4.6
Published
butmux - Terminal workspace manager for GitButler, tmux, and Kitty
Readme
butmux
butmux is a terminal UI for managing GitButler branches as real tmux and terminal work contexts.
It gives you one place to:
- add and switch project directories
- create independent or dependent GitButler branches from the TUI
- sync GitButler branches into managed tmux sessions and terminal tabs
- focus a context, workspace session, or agent pane
- rename contexts across GitButler, tmux, and the selected terminal backend
- reorder managed contexts from the keyboard
- remove orphan tmux and terminal state
- inspect Codex and Claude panes per context
Requirements
- macOS or Linux
- Node.js
tmuxbut(GitButler CLI)kittywith remote control enabled, orwezterm
butmux assumes working contexts are backed by:
- GitButler branch state
- tmux sessions
- terminal tabs in Kitty or WezTerm
Install
npm install
npm run buildDuring local development, run the built command directly:
./dist/cli.jsTo expose butmux on PATH, use your preferred Node/package workflow, for example:
npm linkRun
Start the terminal UI:
butmuxAdd the current directory from a shell:
butmux addKeyboard
j/k or Up/Down move selection
Enter focus selected workspace, branch, or agent
r refresh
s sync selected row's project
a add project path
b create independent branch in selected row's project
B create dependent branch from selected branch
n rename selected managed branch
g run suggested GitButler setup or teardown
x remove selected project or orphan branch after confirmation
c create selected row's project workspace session
[ / ] reorder selected managed branch
, cycle terminal backend
? show help
q or Ctrl+C quitBranch Creation
Use b to create a new independent GitButler branch for the selected row's
project.
butmux runs:
but branch new <name>Use B from a managed branch row to create a dependent branch anchored to the
selected branch. butmux uses the selected GitButler branch id when available and
falls back to the branch name. It runs:
but branch new <name> -a <anchor>After creation, butmux syncs the project so the new branch gets its managed context, tmux session, and terminal tab.
Configuration
butmux stores user settings under XDG config:
${XDG_CONFIG_HOME:-~/.config}/butmux/config.jsonExample:
{
"terminalBackend": "kitty"
}Supported terminal backends:
kittywezterm
If the config file is missing, butmux defaults to kitty.
State
butmux stores projects, contexts, and ordering under XDG state:
${XDG_STATE_HOME:-~/.local/state}/butmux/registry.jsonExample shape:
{
"projects": [],
"contexts": []
}How butmux Works
For each GitButler branch in a registered project, butmux manages:
- one tmux session
- one terminal tab
- one registry entry for ordering and persistence
Managed names use this shape:
bm_<project-slug>_<branch-key>Examples:
git-butler-practice+butmux-parser-test->bm_gbp_butmux-parser-testbutmux+kn-branch-1->bm_butmux_kn-branch-1
Each project can also have a workspace session. Its tmux session name is the project directory basename, for example /repo/butmux -> butmux.
Agent Integration
butmux supports Codex and Claude status updates through tmux pane options.
The intended flow is:
Agent hook -> butmux hook <agent> <event> -> tmux pane options -> butmux TUI refreshSupported Codex Events
SessionStartUserPromptSubmitStop
These map to:
session-startuser-prompt-submitstop
Supported Claude Events
SessionStartUserPromptSubmitNotificationStopStopFailurePostToolUseSessionEnd
tmux Pane Options
butmux writes and reads these pane options:
@butmux_agent@butmux_status@butmux_prompt@butmux_cwd@butmux_started_at@butmux_attention@butmux_wait_reason
Pane status values:
idlerunningwaitingerror
Plugin Hook Setup
butmux provides Codex and Claude Code plugins in this repository. The plugins
install lifecycle hooks that call butmux hook <agent> <event> without butmux
editing your personal ~/.codex or ~/.claude settings files directly.
Install the butmux CLI first:
npm install -g butmuxFor local development, npm link is also fine as long as butmux resolves on
PATH:
command -v butmuxIf butmux is not on PATH, set BUTMUX_BIN to an executable path before
starting Codex or Claude Code:
export BUTMUX_BIN=/absolute/path/to/butmuxCodex Plugin
The Codex marketplace file is:
.agents/plugins/marketplace.jsonAdd the GitHub marketplace and install the plugin with the Codex CLI:
codex plugin marketplace add kdnk/butmux
codex plugin add codex-butmux@butmuxFor local plugin development from a cloned checkout, use
codex plugin marketplace add . from the repository root instead.
Then start a new Codex session. Use /hooks in Codex to review and trust the
plugin hooks if Codex asks for hook review.
The plugin provides:
SessionStart -> butmux hook codex session-start
UserPromptSubmit -> butmux hook codex user-prompt-submit
Stop -> butmux hook codex stopClaude Code Plugin
The Claude Code marketplace file is:
.claude-plugin/marketplace.jsonAdd the GitHub marketplace and install the plugin with the Claude Code CLI:
claude plugin marketplace add kdnk/butmux
claude plugin install claude-butmux@butmuxFor local plugin development from a cloned checkout, use
claude plugin marketplace add . from the repository root instead.
Then run /reload-plugins or start a new Claude Code session. Use /hooks in
Claude Code to inspect the installed hook definitions.
The plugin provides:
SessionStart -> butmux hook claude session-start
UserPromptSubmit -> butmux hook claude user-prompt-submit
Notification -> butmux hook claude notification
Stop -> butmux hook claude stop
StopFailure -> butmux hook claude stop-failure
PostToolUse -> butmux hook claude post-tool-use
SessionEnd -> butmux hook claude session-endVerify Hook Status
Run Codex or Claude Code inside a tmux pane, then start or resume a session. The
plugin hooks intentionally no-op when TMUX_PANE is missing, so sessions outside
tmux will not update butmux pane state.
In another pane, open:
butmuxThe selected context should show the active Codex or Claude pane after the first hook event fires.
Troubleshooting Hooks
- Check
command -v butmux, or setBUTMUX_BIN. - Confirm the agent session is running inside tmux so
TMUX_PANEis present. - Open
/hooksin Codex or Claude Code and confirm the plugin hooks are enabled and trusted. - Check whether hooks are disabled by user, project, or managed policy.
- Confirm the plugin is installed and enabled.
Manual Hook Reference
The plugin setup above is preferred. Manual hook configuration is still possible if you do not want to use plugins.
Codex commands:
butmux hook codex session-start
butmux hook codex user-prompt-submit
butmux hook codex stopClaude Code commands:
butmux hook claude session-start
butmux hook claude user-prompt-submit
butmux hook claude notification
butmux hook claude stop
butmux hook claude stop-failure
butmux hook claude post-tool-use
butmux hook claude session-endManual Notifications
Use butmux notify inside a tmux pane when you need to raise a waiting state manually:
butmux notify "implementation finished"Build
npm run buildThis typechecks the project and builds:
dist/cli.jsTest
npm testOperational Notes
- If
but status -fvreportsSetup required: No GitButler project found, butmux runsbut setupand retries. - If a project warning says
but setuporbut teardownis needed, select that project's row and pressgto run the suggested GitButler command. - If a terminal tab is missing during focus, butmux creates one.
- If a tmux session is missing during focus, butmux creates one.
- If a target pane lives in another tmux window, butmux switches to that window before selecting the pane.
- Orphan cleanup removes both the tmux session and matching terminal tab.
Development Notes
Important files:
Specs and plans:
