{"id":51905272,"url":"https://github.com/craftzdog/tmux-claude-session-manager","last_synced_at":"2026-07-26T21:01:31.710Z","repository":{"id":365130399,"uuid":"1266977227","full_name":"craftzdog/tmux-claude-session-manager","owner":"craftzdog","description":"Run many Claude Code sessions across your projects, each in its own tmux session — then list them, see which are done vs. still working, and jump to one from a single popup.","archived":false,"fork":false,"pushed_at":"2026-07-08T14:53:43.000Z","size":1299,"stargazers_count":252,"open_issues_count":2,"forks_count":33,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-07-08T16:18:23.686Z","etag":null,"topics":["claude-code","tmux"],"latest_commit_sha":null,"homepage":"https://www.devas.life/i-made-a-claude-code-session-manager-for-tmux/","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/craftzdog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T05:46:11.000Z","updated_at":"2026-07-08T16:14:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/craftzdog/tmux-claude-session-manager","commit_stats":null,"previous_names":["craftzdog/tmux-claude-session-manager"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/craftzdog/tmux-claude-session-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftzdog%2Ftmux-claude-session-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftzdog%2Ftmux-claude-session-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftzdog%2Ftmux-claude-session-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftzdog%2Ftmux-claude-session-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/craftzdog","download_url":"https://codeload.github.com/craftzdog/tmux-claude-session-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftzdog%2Ftmux-claude-session-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35928365,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-26T02:00:06.503Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","tmux"],"created_at":"2026-07-26T21:01:31.236Z","updated_at":"2026-07-26T21:01:31.700Z","avatar_url":"https://github.com/craftzdog.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tmux-claude-session-manager\n\n[![screenshot](./docs/screenshot.jpg)](https://youtu.be/NnTV6r4l5D0)\n\nRun many [Claude Code](https://claude.com/claude-code) sessions across your\nprojects, each in its own tmux session — then **list them, see which are done\nvs. still working, and jump to one** from a single popup.\n\nIf you launch Claude per-directory (one nested session per project), you quickly\nend up with a dozen of them and no way to tell which are finished without opening\neach one. This plugin gives you:\n\n- 🔢 **A central picker** (`prefix` + `u`) listing every running Claude agent —\n  several in one project, and any running loose in an ordinary pane.\n- 🟢 **Live status** per agent — `working` / `waiting` / `idle` — read straight\n  from `claude agents --json`, so you instantly see which need you. No setup.\n- 👁️ **A live preview** of each agent's screen right in the picker.\n- 🎯 **Smart jump** — selecting an agent switches your client to the window it\n  was launched from, then resumes it in a popup over it.\n- 🚀 **A launcher** (`prefix` + `y`) that opens/attaches a Claude session for the\n  current directory.\n- ❌ **Quick kill** (`ctrl-x`) of a finished agent from the picker.\n\nStatus needs no configuration. Claude Code publishes each agent's own state and\nthe picker reads it — there are no hooks to install.\n\n## Prerequisites\n\n- **tmux ≥ 3.2** (for `display-popup`)\n- **[fzf](https://github.com/junegunn/fzf)** — the picker UI\n- **[jq](https://jqlang.org/)** — parses `claude agents --json`\n- **[Claude Code](https://claude.com/claude-code)** ≥ 2.1.139 — for the\n  `claude agents` command (`claude --version` to check)\n- bash; macOS or Linux\n\n## Install (tpm)\n\nAdd to `~/.tmux.conf` (or `~/.config/tmux/tmux.conf`):\n\n```tmux\nset -g @plugin 'craftzdog/tmux-claude-session-manager'\n```\n\nThen hit `prefix` + \u003ckbd\u003eI\u003c/kbd\u003e to install.\n\n\u003e **Keybinding note:** by default the plugin binds `prefix` + `y` (launch) and\n\u003e `prefix` + `u` (list). If your config binds those elsewhere, either change the\n\u003e options below, or make sure the plugin loads **after** your own bindings (put\n\u003e `run '~/.tmux/plugins/tpm/tpm'` _after_ them) so the one you want wins.\n\n### Manual install\n\n```sh\ngit clone https://github.com/craftzdog/tmux-claude-session-manager ~/clone/path\n```\n\nAdd to `~/.tmux.conf`, then reload (`prefix` + \u003ckbd\u003er\u003c/kbd\u003e or `tmux source ~/.tmux.conf`):\n\n```tmux\nrun-shell ~/clone/path/claude_session_manager.tmux\n```\n\n## Usage\n\n| Key            | Action                                                                          |\n| -------------- | ------------------------------------------------------------------------------- |\n| `prefix` + `y` | Launch (or re-attach to) a Claude session for the current directory, in a popup |\n| `prefix` + `u` | Open the agent picker                                                           |\n\nInside the picker:\n\n| Key                       | Action                                                |\n| ------------------------- | ----------------------------------------------------- |\n| `enter`                   | Jump to the agent (see [How it works](#how-it-works)) |\n| `ctrl-x`                  | Kill the highlighted agent                            |\n| `↑` / `↓`, type to filter | fzf navigation                                        |\n\nAgents needing your attention (`waiting`, `idle`) sort to the top.\n\nEvery running Claude gets its own row — the picker identifies each by its process,\nnot by its tmux session. So several agents in one project all show up separately,\nas does a Claude you started by hand in an ordinary pane.\n\n## Options\n\nSet any of these before the plugin loads (defaults shown):\n\n```tmux\nset -g @claude_launch_key     'y'        # prefix key: launch/open for current dir\nset -g @claude_list_key       'u'        # prefix key: open the picker\nset -g @claude_command        'claude'   # command run in new sessions\nset -g @claude_args           ''         # extra args appended to the command\nset -g @claude_session_prefix 'claude-'  # tmux session name prefix\nset -g @claude_popup_width     '90%'     # popup width\nset -g @claude_popup_height    '90%'     # popup height\nset -g @claude_fzf_options    ''         # extra options passed to the fzf picker\n```\n\nFor example, to skip permission prompts in launched sessions:\n\n```tmux\nset -g @claude_args '--dangerously-skip-permissions'\n```\n\n### Customizing the fzf picker\n\n`@claude_fzf_options` is passed straight to `fzf`, so you can add your own bindings.\n\nHere is a vim keybinding example:\n\n```tmux\nset -g @claude_fzf_options \"\\\n  --prompt 'nav\u003e ' \\\n  --bind 'j:down' \\\n  --bind 'k:up' \\\n  --bind 'q:abort' \\\n  --bind 'x:execute-silent(kill {3})+reload(sleep 0.3; \\$CLAUDE_PICKER --list)' \\\n  --bind 'i:unbind(j,k,q,i,a,x)+change-prompt(filter\u003e )' \\\n  --bind 'a:unbind(j,k,q,i,a,x)+change-prompt(filter\u003e )' \\\n  --bind 'esc:rebind(j,k,q,i,a,x)+change-prompt(nav\u003e )'\"\n```\n\nThe picker opens in **nav** mode:\n\n| Key       | Action                                                  |\n| --------- | ------------------------------------------------------- |\n| `j` / `k` | move down / up                                          |\n| `i` / `a` | switch to **filter** mode — type to fuzzy-match         |\n| `x`       | kill the highlighted agent (like the built-in `ctrl-x`) |\n| `q`       | close the picker                                        |\n| `enter`   | jump to the agent (both modes)                          |\n| `esc`     | filter mode → back to nav                               |\n\nOnly the bound keys are special in nav mode; any other key still filters as you\ntype. `x` reloads the list through `$CLAUDE_PICKER`, a path the picker exports for\nexactly this — write it as `\\$CLAUDE_PICKER` inside the double-quoted value above\nso tmux stores a literal `$` (in a single-quoted value, use a bare\n`$CLAUDE_PICKER`).\n\n## How it works\n\n- The **launcher** creates a detached `claude-\u003chash-of-dir\u003e` tmux session running\n  `claude`, records the window it came from in `@claude_origin`, and attaches to\n  it in a popup.\n- **`claude agents --json`** is the source of truth for what is running and how it\n  is doing. Each Claude session self-reports its state (`busy` / `waiting` /\n  `idle`) to a supervisor daemon, which that command publishes. Nothing here scans\n  processes for a `claude` command name — on macOS a pane reports its parent shell,\n  never the `claude` child running inside it.\n- **`agents.sh`** pairs each running Claude with the tmux pane it occupies by\n  joining `pid` → `tty` → pane. That join is why identity is the Claude _process_\n  rather than the tmux session, and therefore why several agents in one project\n  each get their own row. It costs three subprocesses per render, whatever the\n  number of sessions or panes.\n- The **age column** is the mtime of the agent's transcript — its last sign of\n  life. `claude agents --json` reports only `startedAt`, never a last-activity\n  time. A brand-new agent that has yet to take a turn shows `-`.\n- The **picker** renders those rows with a live `capture-pane` preview. On `enter`\n  a **dedicated** agent (in a `claude-*` session) resumes in the popup over the\n  window it was launched from, while a **loose** one (any other pane) is focused in\n  place. `ctrl-x` kills the Claude process itself: a dedicated session dies with\n  its last window, and a loose pane keeps the shell that hosted it.\n- Pressing `prefix` + `u` **from inside a session popup** detaches that popup\n  first (closing it), then reopens the picker full-size on the outer host client —\n  so you never end up with a cramped popup-in-popup.\n\n## License\n\n[MIT](LICENSE) © Takuya Matsuyama\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcraftzdog%2Ftmux-claude-session-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcraftzdog%2Ftmux-claude-session-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcraftzdog%2Ftmux-claude-session-manager/lists"}