Terminal UI to navigate, resume, and start Claude Code and Codex sessions
Project description
Railmux — session manager for Claude Code & Codex
A terminal UI to navigate, resume, and start Claude Code and Codex sessions across all your projects. railmux lives in the left pane of a tmux window; the right pane shows the active agent. Each session runs as its own detached tmux session in the background — switching preserves all in-progress work, no responses or tool calls are interrupted.
- Claude Code mode — reads
~/.claude/projects/*, lists sessions by project, resume withclaude --resume - Codex mode — reads
~/.codex/sessions/*, same sidebar workflow for Codex sessions - Press
mto toggle between modes
Why Railmux?
Without Railmux, managing multiple agent sessions means manually tracking tmux windows, remembering which session lives where, and copy-pasting session IDs. Sessions pile up across projects, context gets lost, and switching between them is friction.
Railmux replaces all of that with a single keystroke:
- One sidebar, all sessions — browse every Claude Code and Codex session across every project, filter by name, star favourites
- Instant switching — press Enter and the right pane attaches to a different background tmux session; every agent keeps running, no responses lost
- Zero manual bookkeeping — no more
tmux ls | grep cc-or hunting through~/.claude/projects/
Install
pip install railmux
# or: pip3 install railmux
Requires Python 3.9+, tmux, and less on PATH.
Run
railmux
If you're not already inside a tmux session, railmux will launch one automatically. The most recent project is auto-selected on startup.
Keys
Navigation
| Key | Action |
|---|---|
↑ / ↓ |
Move selection within the focused pane |
Tab / Shift-Tab |
Cycle focus through Projects, Sessions, Running panes |
Esc |
Move focus up: Running → Sessions → Projects |
/ |
Filter the focused pane by name |
Session actions
| Key | Action |
|---|---|
Enter |
Resume or start the selected session |
n |
Start a fresh session in the current project |
i |
Popup with session details |
r |
Rename the focused session |
s |
Toggle star — starred sessions pinned to top with ⭐ |
k |
Kill the running agent process (keeps session file) |
d |
Delete the focused session (prompts for confirmation) |
t |
Open a terminal in the active project directory |
m |
Toggle between Claude Code and Codex modes |
F9 |
Fullscreen the agent pane (toggle) for clean text selection |
? |
Full help popup with all keybindings |
q or Ctrl-C |
Quit with confirmation |
+ New project works in both Claude Code and Codex modes. Browse to an
existing directory and choose . (use this path), or type a new relative,
absolute, or ~-based path. When no existing entry matches, select the
explicit + create … row (it is focused automatically) and press Enter;
railmux creates the directory before starting the agent.
Mouse
| Action | Effect |
|---|---|
| Left-click (non-running) | Preview session history in the right pane |
| Left-click (running) | Attach to the running session (focus stays left) |
| Double-click | Open/attach and move focus to the right pane |
| Right-click | Context menu (Open, Info, Rename, Star, Kill, Term, Delete) |
History preview
Left-click a non-running session to view its conversation history in the right pane without starting or resuming the agent. The preview reads the saved JSONL directly, so it cannot send a message or mutate the session. It follows the providers' conversation structure as closely as their saved data allows: user/assistant messages, tool calls and abbreviated tool output are colour-coded, while internal system context and encrypted reasoning are hidden. Plaintext Codex reasoning summaries are shown when present.
The viewer uses less, the standard pager available on both Linux and macOS,
because neither provider currently exposes a native read-only history view.
It opens at the latest activity and streams at most the latest 2,000 JSONL
records for fast previews of large sessions. Press / to search, n/N to
move between matches, and q to exit; the right pane restores whatever was
there before. Shell/editor commands and pager history are disabled in preview
mode. Double-click to skip the preview and open the session directly.
Clicking a running session attaches to it immediately (focus stays left so you can keep browsing). Double-clicking steals focus to the right pane for both running and non-running sessions.
Status indicators
Each session shows a coloured ● reflecting its current state:
- Green — idle (assistant last responded normally)
- Yellow — busy (assistant is processing)
- Red — blocked (waiting for tool approval)
For Codex rollouts with lifecycle events, only task_complete, turn_aborted,
or thread_rolled_back ends an active turn; intermediate assistant messages and
tool results remain busy. Older rollouts without lifecycle records fall back to
their last user/assistant message. Because Codex has no reliable approval-wait
signal, a pending tool must remain unchanged for two minutes before it turns
red, reducing false alerts from normal long-running commands.
How it works
railmux reads agent session files from ~/.claude/projects/* (Claude Code) or ~/.codex/sessions/* (Codex) and lists everything. Pressing Enter on a session does two things: (1) if a detached tmux session for that session doesn't already exist, railmux creates one with tmux new-session -d; (2) railmux's right pane attaches to it so you see and interact with the agent. Switching sessions just respawns the right pane — the detached sessions keep running with all their state intact.
Configuration
Optional config at ~/.config/railmux/config.toml:
[claude]
# Path to the claude binary (default: "claude")
binary = "claude"
[codex]
# Path to the codex binary (default: "codex")
binary = "codex"
home = "~/.codex"
[projects]
# Show projects with no resumable sessions (default: false)
show_empty_projects = false
[live]
# How often to refresh the session list (ms)
poll_interval_ms = 1000
FAQ
1. How do I copy text from the agent pane?
Under tmux the sidebar and agent share the screen, and over SSH your clipboard lives on the local machine.
OSC 52 (iTerm2, kitty, WezTerm, Alacritty, foot, Windows Terminal): drag-select in the agent pane copies to the local clipboard automatically, even over SSH, no Shift needed. (iTerm2: enable Settings → General → Selection → "Applications in terminal may access clipboard".)
Without OSC 52 (Terminal.app, etc.): press F9 to fullscreen the agent →
Shift‑drag to select → Cmd+C / Ctrl+C to copy → F9 to return.
Ctrl-B zalso toggles fullscreen (built into tmux) but zooms whichever pane has focus — it may fullscreen the sidebar instead of the agent.
2. Mouse clicks or F9 don't work — what's wrong?
These are usually terminal‑side settings, not tmux or railmux.
Mouse: your terminal must forward mouse events to tmux. Check your terminal's
profile settings for "Report mouse events" or "Mouse reporting" and make sure
it's enabled. tmux's set -g mouse on should already be in place (railmux
sets it for its own session).
F9 (fullscreen): on macOS, F9 is often captured by Mission Control.
Fix: System Settings → Keyboard → "Use F1, F2, etc. keys as standard function
keys". On Windows laptops the Fn‑lock key (Fn+Esc) toggles function‑key
behaviour. If your terminal has a "Pass function keys to terminal" option,
enable it.
3. Using railmux over SSH
railmux works over SSH out of the box — the scroll‑agent integration is SSH‑transparent, so mouse scrolling in the agent pane works the same as locally. These tweaks improve responsiveness and scrollback:
Server (~/.tmux.conf on the remote machine):
set -sg escape-time 0 # eliminate delay after Escape key
set -g history-limit 10000 # generous scrollback per pane
Client (~/.ssh/config on your local machine):
Host your-server
Compression yes # smoother tmux pane scrolling over SSH
If the connection is so slow that the sidebar can't refresh one frame per
second, skip the mouse and use keyboard navigation — ↑↓ / Tab / Enter
cover every operation and don't depend on a fast redraw.
4. Will automated review sessions pollute my session list?
Codex: sessions created by codex exec (headless automation, pre‑commit
hooks, CI) are filtered automatically — railmux only shows interactive
sessions (codex-tui, codex_cli_rs).
Claude Code: for one-shot automated reviews, disable session persistence so
the consultation never appears in /resume:
# Print mode only; the review is not saved as a resumable session
claude -p --no-session-persistence "review this diff"
(--no-session-persistence is a Claude Code print-mode option.)
5. pip reports "externally-managed-environment"
Create a virtual environment, then install Railmux with that environment's
pip. This works on macOS, Linux, and WSL without modifying the system Python:
python3 -m venv ~/.venvs/railmux
source ~/.venvs/railmux/bin/activate
pip install railmux
pipx install railmux is an optional convenience for a globally available CLI;
it is not required on macOS or any other platform.
Acknowledgements
The tmux sidebar idea and initial architecture came from regmi-saugat/ccmgr. railmux extends it with Codex support, session history preview, starring, in-app renaming, mouse interaction, and a status bar integrated into the tmux status line.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file railmux-0.1.1.tar.gz.
File metadata
- Download URL: railmux-0.1.1.tar.gz
- Upload date:
- Size: 186.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ac4552484bf4034c5e567d8237576661e2b50103f4f52af9fcc7169f8ebb75e
|
|
| MD5 |
cd2a0115e37a84427530cfc2351954bb
|
|
| BLAKE2b-256 |
879c90d78c401865123ff300059b5d8337f4e14f4b05500f9917e97255275374
|
Provenance
The following attestation bundles were made for railmux-0.1.1.tar.gz:
Publisher:
release.yml on Rightglow/Railmux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
railmux-0.1.1.tar.gz -
Subject digest:
6ac4552484bf4034c5e567d8237576661e2b50103f4f52af9fcc7169f8ebb75e - Sigstore transparency entry: 2172759155
- Sigstore integration time:
-
Permalink:
Rightglow/Railmux@491cc9e40537b379406b661571ea7b8d93c13357 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Rightglow
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@491cc9e40537b379406b661571ea7b8d93c13357 -
Trigger Event:
push
-
Statement type:
File details
Details for the file railmux-0.1.1-py3-none-any.whl.
File metadata
- Download URL: railmux-0.1.1-py3-none-any.whl
- Upload date:
- Size: 123.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fee74043a0931e2db37577ff158bd799ec9e16c30367101fe44b23e0a85ab37
|
|
| MD5 |
a0b490c8a68275087864b750a25fc7c2
|
|
| BLAKE2b-256 |
f3b24a074610be825aedb7bd6cb9f224e93ee56af7121e91d664d506429bc1c1
|
Provenance
The following attestation bundles were made for railmux-0.1.1-py3-none-any.whl:
Publisher:
release.yml on Rightglow/Railmux
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
railmux-0.1.1-py3-none-any.whl -
Subject digest:
6fee74043a0931e2db37577ff158bd799ec9e16c30367101fe44b23e0a85ab37 - Sigstore transparency entry: 2172759169
- Sigstore integration time:
-
Permalink:
Rightglow/Railmux@491cc9e40537b379406b661571ea7b8d93c13357 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/Rightglow
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@491cc9e40537b379406b661571ea7b8d93c13357 -
Trigger Event:
push
-
Statement type: