Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 76 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ It helps you:
- show the current pane state plus a background session summary in the status line
- use local plugin and hook state instead of relying only on sqlite or pane heuristics

Today the strongest runtime support is still for `opencode`, and the project also supports `codex` and `pi` panes for discovery, switching, popup navigation, and status summaries.
Today the strongest runtime support is still for `opencode`, and the project also supports `codex`, `pi`, and `claude` panes for discovery, switching, popup navigation, and status summaries.

## Rename status

Expand All @@ -34,6 +34,7 @@ Recommended settings:

```tmux
set -g @coding-agents-tmux-provider 'plugin'
set -g @coding-agents-tmux-auto-install 'opencode,pi,codex,claude'
set -g @coding-agents-tmux-menu-key 'O'
set -g @coding-agents-tmux-popup-key 'P'
set -g @coding-agents-tmux-waiting-menu-key 'W'
Expand All @@ -44,7 +45,7 @@ set -g @coding-agents-tmux-status-position 'right'
set -g @coding-agents-tmux-status-interval '0'
```

Those defaults favor the bundled plugin provider and event-driven status redraws so tmux stops polling Node in the background.
Those settings favor the bundled plugin provider, explicitly enable tmux-managed installs for the bundled OpenCode plugin plus the Pi extension and Codex/Claude hooks, and use event-driven status redraws so tmux stops polling Node in the background.

To match your tmux theme, you can also override the status colors:

Expand Down Expand Up @@ -72,10 +73,13 @@ Requirements:
- `opencode` sessions must be restarted after first install so the bundled plugin is loaded
- `codex` sessions must be restarted after first install so newly installed hooks are loaded
- `pi` sessions must be restarted after first install so the bundled extension is loaded
- `claude` sessions must be restarted after Claude hook installation so new hooks are loaded

## What TPM sets up

By default, the TPM plugin also installs the bundled `opencode` plugin by creating these symlinks:
With the recommended settings above, the tmux plugin manages the bundled `opencode` plugin, the Pi extension, and the Codex and Claude hook installs for you.

It installs the bundled `opencode` plugin by creating these symlinks:

```text
~/.config/opencode/plugins/coding-agents-tmux.ts
Expand Down Expand Up @@ -133,6 +137,12 @@ It also installs or updates Codex hook integration under:
~/.codex/hooks.json
```

With the recommended `@coding-agents-tmux-auto-install 'opencode,pi,codex,claude'` setting, it also installs or updates Claude Code hook integration under:

```text
~/.claude/settings.json
```

You can disable the automatic symlink step with:

```tmux
Expand All @@ -151,6 +161,22 @@ You can disable the automatic Codex hook setup with:
set -g @coding-agents-tmux-install-codex-hooks 'off'
```

You can disable the automatic Claude Code hook setup with:

```tmux
set -g @coding-agents-tmux-install-claude-hooks 'off'
```

You can also control all tmux-managed installs together:

```tmux
set -g @coding-agents-tmux-auto-install 'auto'
set -g @coding-agents-tmux-auto-install 'off'
set -g @coding-agents-tmux-auto-install 'opencode,pi,codex,claude'
```

The explicit `opencode,pi,codex,claude` list is the recommended README setting because it makes the intended managed installs obvious in your tmux config. When `@coding-agents-tmux-auto-install` is set, it takes precedence over the individual install toggles.

## Usage

Default key bindings:
Expand Down Expand Up @@ -277,6 +303,8 @@ Available tmux options:
- `@coding-agents-tmux-install-opencode-plugin` `on` or `off`, default `on`
- `@coding-agents-tmux-install-pi-extension` `on` or `off`, default `on`
- `@coding-agents-tmux-install-codex-hooks` `on` or `off`, default `on`
- `@coding-agents-tmux-install-claude-hooks` `on` or `off`, default `off`
- `@coding-agents-tmux-auto-install` `auto`, `off`, or a comma-separated list like `opencode,pi,codex,claude`; when set, it overrides the individual install toggles
- `@coding-agents-tmux-provider` `auto`, `plugin`, `sqlite`, or `server`, default `plugin`
- `@coding-agents-tmux-server-map` JSON object or JSON file path for explicit server endpoints
- `@coding-agents-tmux-popup-filter` one of `all`, `busy`, `waiting`, `running`, `active`
Expand Down Expand Up @@ -318,9 +346,9 @@ set -g @coding-agents-tmux-provider 'plugin'

## Pi

`pi` panes are detected from the live tmux pane command and common title patterns, so they show up in `list`, `switch`, `popup`, and `status` alongside `opencode` and `codex` panes.
`pi` panes are detected from the live tmux pane command and common title patterns, so they show up in `list`, `switch`, `popup`, and `status` alongside `opencode`, `codex`, and `claude` panes.

Use `--agent opencode`, `--agent codex`, `--agent pi`, or `--agent all` on `list`, `switch`, `popup`, `popup-ui`, and `status` when you want to narrow mixed tmux environments.
Use `--agent opencode`, `--agent codex`, `--agent pi`, `--agent claude`, or `--agent all` on `list`, `switch`, `popup`, `popup-ui`, and `status` when you want to narrow mixed tmux environments.

For the best Pi runtime fidelity, let the tmux plugin install the bundled Pi extension automatically. It is linked into:

Expand All @@ -345,9 +373,9 @@ After first install or update, restart Pi sessions in tmux so they load the bund

## Codex

`codex` panes are detected from the live tmux pane command, so they show up in `list`, `switch`, `popup`, and `status` alongside `opencode` and `pi` panes.
`codex` panes are detected from the live tmux pane command, so they show up in `list`, `switch`, `popup`, and `status` alongside `opencode`, `pi`, and `claude` panes.

Use `--agent opencode`, `--agent codex`, `--agent pi`, or `--agent all` on `list`, `switch`, `popup`, `popup-ui`, and `status` when you want to narrow mixed tmux environments.
Use `--agent opencode`, `--agent codex`, `--agent pi`, `--agent claude`, or `--agent all` on `list`, `switch`, `popup`, `popup-ui`, and `status` when you want to narrow mixed tmux environments.

Default Codex runtime support is intentionally coarse:

Expand All @@ -373,6 +401,45 @@ mkdir -p .codex

With hooks enabled, `coding-agents-tmux` can mark Codex panes as `idle` or `waiting-input` between turns instead of showing every Codex pane as continuously `running`.

## Claude Code

`claude` panes are detected from the live tmux pane command and common title patterns, so they show up in `list`, `switch`, `popup`, and `status` alongside `opencode`, `codex`, and `pi` panes.

Default Claude Code runtime support is intentionally coarse:

- if a tmux pane is running a `claude` process, it is classified as `running`
- waiting, question, and idle distinctions become higher fidelity when Claude hooks are installed

To enable higher-fidelity Claude Code state with hooks:

1. Install or update the global Claude hook config manually:

```bash
./bin/coding-agents-tmux install-claude
```

2. Or let the tmux plugin manage it by setting either:

```tmux
set -g @coding-agents-tmux-install-claude-hooks 'on'
```

or the shared selector:

```tmux
set -g @coding-agents-tmux-auto-install 'opencode,pi,codex,claude'
```

3. Optionally inspect the managed hook template before merging it into project or user Claude settings:

```bash
./bin/coding-agents-tmux claude-hooks-template
```

4. Restart `claude` sessions in tmux so they begin publishing hook-backed state.

With hooks enabled, `coding-agents-tmux` can mark Claude panes as `idle`, `waiting-question`, or `waiting-input` between turns instead of showing every Claude pane as continuously `running`.

## Troubleshooting

- `prefix + O` or `prefix + P` does nothing: make sure `node` and `npm` are installed and reload tmux
Expand All @@ -381,6 +448,7 @@ With hooks enabled, `coding-agents-tmux` can mark Codex panes as `idle` or `wait
- waiting detection seems wrong: use the `plugin` provider and confirm the bundled plugin symlink exists at `~/.config/opencode/plugins/coding-agents-tmux.ts`
- Pi still looks busy or unknown: confirm the bundled extension exists at `~/.pi/agent/extensions/coding-agents-tmux/index.ts` and restart the Pi session so it loads the extension
- Codex still always looks busy: confirm `~/.codex/config.toml` has `codex_hooks = true`, `~/.codex/hooks.json` exists, and restart the Codex session
- Claude still always looks busy: confirm `~/.claude/settings.json` contains the managed `claude-hook-state` hook command and restart the Claude Code session
- status looks stale with `sqlite` or `server`: set `@coding-agents-tmux-status-interval` to a positive value because event-driven refreshes are centered on the bundled plugin provider
- TPM install changed but tmux still looks old: run `prefix + I` or `tmux source-file ~/.tmux.conf`

Expand Down Expand Up @@ -410,6 +478,7 @@ Useful commands:
./bin/coding-agents-tmux list --provider plugin
./bin/coding-agents-tmux list --agent codex
./bin/coding-agents-tmux list --agent pi
./bin/coding-agents-tmux list --agent claude
./bin/coding-agents-tmux list --provider plugin --waiting
./bin/coding-agents-tmux inspect <target> --provider plugin
./bin/coding-agents-tmux status --provider plugin --style tmux
Expand Down
107 changes: 103 additions & 4 deletions coding-agents-tmux.tmux
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,53 @@ normalize_toggle() {
esac
}

tmux_option_alias_is_set() {
local preferred_option="$1"
local legacy_option="$2"
local value

value="$(tmux show-option -gqv "$preferred_option")"
if [ -n "$value" ]; then
return 0
fi

value="$(tmux show-option -gqv "$legacy_option")"
[ -n "$value" ]
}

normalize_auto_install_value() {
local value lowered
value="${1// /}"
lowered="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')"

case "$lowered" in
auto|all)
printf '%s' 'auto'
;;
off|none|disabled|false|0)
printf '%s' 'off'
;;
*)
printf '%s' "$lowered"
;;
esac
}

auto_install_includes() {
local csv="$1"
local wanted="$2"
local item

IFS=',' read -r -a items <<< "$csv"
for item in "${items[@]}"; do
if [ "$item" = "$wanted" ]; then
return 0
fi
done

return 1
}

unbind_key_if_set() {
local key="$1"

Expand Down Expand Up @@ -371,6 +418,12 @@ install_codex_hooks() {
fi
}

install_claude_hooks() {
if ! "$CURRENT_DIR/bin/coding-agents-tmux" install-claude >/dev/null 2>&1; then
tmux display-message "coding-agents-tmux: failed to install Claude Code hook configuration"
fi
}

install_pi_extension() {
local extension_source pi_dir extension_dir extension_target legacy_extension_dir legacy_extension_target existing_target installed_changed

Expand Down Expand Up @@ -405,7 +458,7 @@ install_pi_extension() {
}

main() {
local menu_key popup_key waiting_menu_key waiting_popup_key provider server_map popup_filter popup_width popup_height popup_title status_enabled status_style status_position status_option status_interval status_mode install_plugin install_codex install_pi status_text_segment status_inline_segment status_tone_segment status_refresh_command
local menu_key popup_key waiting_menu_key waiting_popup_key provider server_map popup_filter popup_width popup_height popup_title status_enabled status_style status_position status_option status_interval status_mode install_plugin install_codex install_pi install_claude auto_install_value status_text_segment status_inline_segment status_tone_segment status_refresh_command
local status_prefix status_color_neutral status_color_busy status_color_waiting status_color_idle status_color_unknown
local previous_status_segment previous_status_option previous_menu_key previous_popup_key previous_waiting_menu_key previous_waiting_popup_key
menu_key="$(normalize_binding_key "$(get_tmux_option_alias '@coding-agents-tmux-menu-key' '@opencode-tmux-menu-key' 'O')")"
Expand All @@ -418,9 +471,51 @@ main() {
popup_width="$(get_tmux_option_alias '@coding-agents-tmux-popup-width' '@opencode-tmux-popup-width' '100%')"
popup_height="$(get_tmux_option_alias '@coding-agents-tmux-popup-height' '@opencode-tmux-popup-height' '100%')"
popup_title="$(get_tmux_option_alias '@coding-agents-tmux-popup-title' '@opencode-tmux-popup-title' 'Coding Agent Sessions')"
install_plugin="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-opencode-plugin' '@opencode-tmux-install-opencode-plugin' 'on')")"
install_codex="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-codex-hooks' '@opencode-tmux-install-codex-hooks' 'on')")"
install_pi="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-pi-extension' '@opencode-tmux-install-pi-extension' 'on')")"
if tmux_option_alias_is_set '@coding-agents-tmux-auto-install' '@opencode-tmux-auto-install'; then
auto_install_value="$(normalize_auto_install_value "$(get_tmux_option_alias '@coding-agents-tmux-auto-install' '@opencode-tmux-auto-install' '')")"

case "$auto_install_value" in
auto)
install_plugin='on'
install_codex='on'
install_pi='on'
install_claude='on'
;;
off|"")
install_plugin='off'
install_codex='off'
install_pi='off'
install_claude='off'
;;
*)
install_plugin='off'
install_codex='off'
install_pi='off'
install_claude='off'

if auto_install_includes "$auto_install_value" 'opencode'; then
install_plugin='on'
fi

if auto_install_includes "$auto_install_value" 'codex'; then
install_codex='on'
fi

if auto_install_includes "$auto_install_value" 'pi'; then
install_pi='on'
fi

if auto_install_includes "$auto_install_value" 'claude'; then
install_claude='on'
fi
;;
esac
else
install_plugin="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-opencode-plugin' '@opencode-tmux-install-opencode-plugin' 'on')")"
install_codex="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-codex-hooks' '@opencode-tmux-install-codex-hooks' 'on')")"
install_pi="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-pi-extension' '@opencode-tmux-install-pi-extension' 'on')")"
install_claude="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-claude-hooks' '@opencode-tmux-install-claude-hooks' 'off')")"
fi
status_enabled="$(get_tmux_option_alias '@coding-agents-tmux-status' '@opencode-tmux-status' 'on')"
status_style="$(get_tmux_option_alias '@coding-agents-tmux-status-style' '@opencode-tmux-status-style' 'tmux')"
status_position="$(get_tmux_option_alias '@coding-agents-tmux-status-position' '@opencode-tmux-status-position' 'right')"
Expand Down Expand Up @@ -461,6 +556,10 @@ main() {
install_pi_extension
fi

if [ "$install_claude" = "on" ]; then
install_claude_hooks
fi

local popup_filter_arg=""
case "$popup_filter" in
busy|waiting|running|active)
Expand Down
Loading
Loading