Skip to content

About

One terminal inbox for every coding-agent session waiting on you: Claude Code, Codex and OpenCode in tmux.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

349 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

gate-inbox

A terminal board for running and triaging many AI coding-agent sessions in tmux.

Spawning two agents, watching their status, then answering the one that is waiting from the triage queue

Spawn two agents, watch their status, answer the waiting one from the triage queue, and it hands over the next.

Gate Inbox puts every coding agent on your machine in one list with live status, so the session that is blocked on you is visible without hunting through terminal tabs. Claude Code, Codex and OpenCode v2 work out of the box and run side by side, each in its own tmux session. Any other CLI can be added as a [tools.<name>] block in the config.

It is a thin layer over the CLIs you already have. Each session launches your installed tool as-is, so your login, config files, MCP servers and every feature the tool ships carry over unchanged. Gate Inbox reads the panes; it does not sit between you and the model.

Your first 5 minutes

  1. Install. You need tmux 3.1+, git and at least one agent CLI (Claude Code, Codex or OpenCode). Then run go install github.com/usestring/gate-inbox@latest, or see Install below.
  2. Start it. Run gate-inbox, inside tmux or outside it. The welcome card lists which of your agent CLIs are ready, the five keys that matter, and any agents you already have running in tmux. n on the card starts your first session.
  3. Agents you already had. Anything you started by hand in tmux shows up on the board as-is, and stays where it is: the board never ends your process unasked. a on its row (or on the toast that names a pane started while the board is up) brings it in: once it is idle, it is relaunched on the same conversation as a board session. o leaves it off the board. What a pane kept as-is misses is below; settings (s) has "outside panes" to take them over once idle without asking.
  4. The loop. n starts an agent, enter focuses it, ctrl+q comes back to the list, i walks everything waiting on you, and h shows every key.
  5. Leaving and coming back. q quits and the agents keep running. When you start it again, the board offers back only the sessions that died (a reboot, tmux restarting, a crash), never the ones you ended yourself. Stop using it covers stopping for good.

Kept as-is or relaunched?

An agent pane you started by hand, kept as-is (the default)... Brought into the board (a), it...
keeps running where it is, in its own window is ended once idle and resumed on the same conversation as a board session
gets the board's MCP tools (spawn, message, tasks) through the relay the board registers in your Claude Code user config (Claude Code only; other CLIs get none) gets them
is reached by other sessions and the CLI from its row (send, read, wait, kill, and answer from the session that tracks it) is reached the same way
reports status through the hooks the board registers in your Claude Code user settings (Claude Code only) reports status through the hooks it is launched with
lacks the GATE_INBOX_* environment, extension settings and a fresh account token gets all three
can't be forked, migrated, restarted or revived without a conversation id can, on its own conversation
gets the back-to-board keys when the board attaches it (A), not its title and colours gets them all
keeps the flags and --model it was started with is started from your config, so it doesn't keep them

Install

Gate Inbox runs on Linux and macOS, and on Windows inside WSL2. It needs tmux 3.1+ and git on PATH, plus at least one agent CLI. Building needs Go 1.27.2+.

git clone https://github.com/usestring/gate-inbox.git
cd gate-inbox
go build -o gate-inbox .

Or go install github.com/usestring/gate-inbox@latest, which puts gate-inbox in $(go env GOPATH)/bin. docs/install.md covers optional dependencies, WSL and updating.

Quick start

gate-inbox
  1. n starts an agent in the group under the cursor and focuses it. Type the task.
  2. ctrl+q goes back to the list. Each row shows its status as the agent works.
  3. i opens the triage queue, starting with the session that has waited longest.
  4. Answer it. The queue hands you the next one.
  5. h shows every key for the current screen, and s opens settings.

Sessions live in tmux, so quitting the board leaves them running. Start gate-inbox again and it picks them back up.

The core loop

Spawn. n starts a session in the selected group. ctrl+n opens the full form (tool, name, directory, first prompt, group). Agents name their own sessions after the task.

Reuse prompts (experimental). Enable Prompt suggestions under Settings → Experimental (default off). In the New Session form's prompt field, matching suggestions appear as you type. ctrl+n / ctrl+p choose among them and ctrl+y inserts the chosen text for editing; accepting does not launch the session. Suggestions come from the newest 16 MiB of each CLI's submission log within the past 30 days. A whole prompt or a line in a multi-line prompt must occur at least four times to qualify. Counting ignores case and repeated whitespace, and each submission counts once per candidate. The logs are reread in the background every minute. History and matching stay local; this feature makes no network requests. The hotkey-only snippet menu is unchanged.

See status. Every row shows whether its agent is working, waiting on you, finished or idle, read from the pane itself. The preview beside the list shows the conversation as You and Assistant messages, without the tool noise. w filters the list to what needs attention, and / searches names, groups, statuses and what the sessions have said.

Triage. i flattens the groups into one queue ordered by what needs a person: waiting first, then finished, then errored, longest-blocked first inside each. Picking an option in a dialog, or sending a reply, hands that session back to its agent and opens the next one. ctrl+q moves on without answering, and ctrl+\ stops triage. alt+\ puts the list away for a full-width drain, and alt+, hides the key hints.

Triage draining four agents full-width: each answer hands the session back and the next one that needs input comes up on its own

Triage with the list put away. Answer one session and the next that needs you comes up on its own.

Focus. enter focuses a session in place: keys go to the agent while the list stays beside it, and ctrl+q comes back. alt+\ hides the list so the pane gets the full width, and alt+pgup / alt+end scroll back through its output and return to the live bottom. space opens the hotkey menu, which sends one of your snippets to the selected session without focusing it; a lettered snippet also sends on option+<key> in one press, no menu. T opens a shell tab under the selected agent for builds and one-off commands.

Focusing a session full-width, typing a three-line instruction, watching the agent answer, and scrolling back through the reply

Focus a session, give it the full width, type a multi-line instruction, scroll back through the reply, and ctrl+q out.

Key Action
n / ctrl+n New session, quick or with the full form
space Hotkey menu: send a snippet to the selected session
enter Focus the session; ctrl+q returns to the list
i Triage queue; \ hides the list for a full-width drain
w Show only what needs attention
Y Show only one CLI's sessions, cycling through the harnesses on the board
/ Fuzzy search; esc closes the field, deleting the text clears it
ctrl+p / p Priority tier for a session or group; each press steps urgent → high → medium → low → none. ctrl+p also works from a focused session, and the row flashes its new tier
M Mute / unmute: keep a session out of triage until unmuted; the row reads muted
T Shell tab under the selected agent
x / v Kill a session to free its RAM / revive it on its own conversation
: / ctrl+k Quick actions: type what you want, enter runs it, and each row shows its key
h / s Key map for the current screen / settings

Priority defaults to 0 with no marker. Positive levels use green ▲, ▲▲, and ▲▲▲; the negative level (-1) uses a red ▼. Set a level with gate-inbox priority <level> using a number from -1 to 3 or its tier name.

Every binding is a default, and h is where you rebind one. docs/usage.md is the complete reference.

Agents working with agents

Every MCP-capable session launches with the Gate Inbox MCP server, so an agent can list the other sessions, spawn a child, send it a message, read its screen and wait for it to finish. The same actions are gate-inbox subcommands for a shell inside any session (gate-inbox help). A spawned child is drawn under its parent, and its questions go to the parent first.

Configuration

Config lives at ~/.config/gate-inbox/config.toml on Linux and ~/Library/Application Support/gate-inbox/config.toml on macOS, and is created on first run. GATE_INBOX_HOME points the board at another directory, which then holds the config, the state.db store and the logs.

Adding a CLI takes a tool block with the patterns its pane shows in each state:

[tools.mytool]
command = "mytool"
default_status = "idle"
rules = [
  { state = "waiting", pattern = "(?m)^\\s*❯\\s+\\d+\\." },
  { state = "working", pattern = "esc to interrupt" },
]

Sessions run on tmux's default server as gi_* sessions, and the board never changes a server-global option. Set tmux_socket to keep them on a server of their own. docs/configuration.md covers every field: status detection, revive and fork commands, prompts and MCP registration.

Optional integrations

They talk only to services you run or already use.

Pull requests and tickets. Gate Inbox finds the pull requests and tickets a session is working on from its branch and its output, and hangs them under the session with their CI and review state. GitHub goes through your logged-in gh CLI; Linear reads LINEAR_API_KEY from the environment. A missing credential is not a failure: without LINEAR_API_KEY tickets are still listed, just without their state. Either source can be turned off outright, which hides its rows:

[integrations.github]
enabled = false

[integrations.linear]
enabled = false

Extensions. Extensions are Go code compiled into the binary against the public extension package; the app package runs the board with whichever extensions a build carries. This build carries none, so an [extensions.artifacts] section left from an earlier version is ignored. A build of your own lists its extensions in app.Options. A section an extension refuses switches off that extension alone, and a section no extension in the build owns is ignored; the board's ? key map and each session's MCP instructions say which and why. A disabled extension that has a say in which sessions spawn fails closed: every spawn it would have been asked about is refused, with the reason, until its section is fixed.

Skill priority hook

Claude Code can rank a session from an optional skill frontmatter field:

gate-inbox-priority: high

The accepted tiers are urgent, high, medium, and low. The last invoked skill with a tier wins. The hook reads skills from $CLAUDE_PROJECT_DIR/skills first, then ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills. It runs for the Skill tool and a prompt beginning with /<skill>. Skills without a valid tier leave priority unchanged.

The reusable hook lives in hooks/skill-gate-inbox-priority.sh. It needs Bash and jq, and a session launched by Gate Inbox (GATE_INBOX_BIN, or AGENT_MANAGER_BIN for older launchers). Without a board binary it exits successfully without changing anything. A launcher that owns the session's tier can set GATE_INBOX_PRIORITY_LOCKED=1 to keep skills from replacing it.

To use it in another project, link to your Gate Inbox checkout instead of copying the script. From that project's root, with Gate Inbox checked out in a sibling directory:

mkdir -p hooks
ln -s ../../gate-inbox/hooks/skill-gate-inbox-priority.sh hooks/skill-gate-inbox-priority.sh

Keep that checkout available at the linked path. Merge these entries into the project's .claude/settings.json hooks, preserving any existing registrations:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Skill",
        "hooks": [{"type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/hooks/skill-gate-inbox-priority.sh\""}]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [{"type": "command", "command": "bash \"$CLAUDE_PROJECT_DIR/hooks/skill-gate-inbox-priority.sh\""}]
      }
    ]
  }
}

Run bash hooks/skill-gate-inbox-priority.test.sh from the Gate Inbox checkout to test the hook.

Development

go build -o gate-inbox .
scripts/ci-test.sh       # the test suite exactly as CI runs it

CONTRIBUTING.md covers sending a change, and SECURITY.md how to report a vulnerability privately. The recordings above come from tools/demo/record.sh, which drives vhs against a throwaway board whose sessions run a scripted stand-in CLI, so no model or account is involved.

License and provenance

Apache-2.0. Gate Inbox is derived from an Apache-2.0 upstream project, where its session model, tmux passthrough and TUI began. NOTICE names that project, its authors and the commit this fork started from. LICENSES/MODIFIED-FILES.txt lists the files changed since, and LICENSES/THIRD-PARTY.md covers third-party licences.

Stop using it

Quit. q quits the board. Its agents keep running in tmux as gi_<id> sessions and are picked back up next time.

Stop every agent. gate-inbox park ends every live agent the board started and records the set. It runs from any shell, and --dry-run prints the plan first. gate-inbox unpark brings the same sessions back on their conversations. A single one: gate-inbox kill <id>, with the id from gate-inbox sessions. From inside a managed agent session, gate-inbox stop ends that session and preserves its row and conversation for an explicit revive. It records an intentional stop, so startup recovery does not offer it as a lost session. gate-inbox stop --archive also files the ended row out of the active list, where archive --restore can bring it back for 7 days. gate-inbox stop --dry-run verifies the current pane without ending it. Adopted callers with verified pane process ancestry can also stop themselves. Shared-daemon callers whose pane cannot be verified refuse shutdown. Other adopted panes can be stopped by id from another session or the board.

Carry on in the plain CLI. In a focused session, alt+/ copies the agent's own conversation id. From that session's working directory:

CLI Resume
Claude Code claude --resume <id>
Codex codex resume <id>
OpenCode opencode --session <id>

Without an id, Claude Code and Codex open their own session picker (claude --resume, codex resume) so you choose the conversation, and opencode --continue picks up the directory's most recent one.

Uninstall.

  1. gate-inbox park. In Settings (s), switch "claude code setup" off so the board takes its hooks and MCP relay back out of your Claude Code config, run gate-inbox codex-hooks uninstall to take its hooks out of your Codex config, set [opencode] setup = false in config.toml so it takes its plugin out of your OpenCode config, then quit the board with q.
  2. Remove the binary: rm "$(command -v gate-inbox)".
  3. Remove the config and state directory. That's $GATE_INBOX_HOME if you set it, otherwise ~/.config/gate-inbox on Linux ($XDG_CONFIG_HOME/gate-inbox if that's set) and ~/Library/Application Support/gate-inbox on macOS. It holds config.toml, state.db, the log, key bindings, snippets, hook and MCP registration files, and a copy of the binary under bin/.
  4. Remove the launch scripts and pasted images it left in your temp directory: rm -f "${TMPDIR:-/tmp}"/gi-launch-*.sh and rm -rf "${TMPDIR:-/tmp}/gate-inbox-pastes".
  5. Undo the tmux key bindings it added (ctrl+q and ctrl+\, plus alt+o from older releases, which act only inside gi_* sessions and adopted panes the board attached), on each tmux server it adopted a pane on: tmux unbind-key -n C-q \; unbind-key -n 'C-\' \; unbind-key -n M-o, or restart tmux. If the board didn't exit cleanly, tmux kill-session -t gi_poll-anchor removes its helper session. If you gave it a private tmux socket, tmux -L <name> kill-server does all of this at once.

Gate Inbox hands each session it launches its MCP server and hooks on the command line. The things it keeps in an agent CLI's own configuration are for panes it adopts: hook entries in ~/.claude/settings.json, silent outside an adopted pane, the two deny lists there that keep every Claude Code session out of Gate Inbox's sealing keys (permissions.deny and sandbox.filesystem.denyRead, naming only its own channel-keys directory), and an MCP server named gate-inbox in ~/.claude.json; two hook entries in ~/.codex/config.toml, silent outside the board's sessions; and a gate-inbox-<id>.js plugin in ~/.config/opencode/plugins, silent outside an adopted pane; all added automatically. Step 1 removes them, giving back the settings file as it was, and so do [claude_code] setup = false, [codex] setup = false and [opencode] setup = false in config.toml. Beyond that, migrate leaves a *.handover.jsonl file next to the transcript it moved, under ~/.claude/projects or ~/.codex/sessions.

Credits

Gate Inbox is derived from agent-manager, licensed under Apache-2.0. Thank you to Yoan Wai and the agent-manager contributors for the session model, tmux passthrough and TUI this project grew from. NOTICE carries the attribution and the upstream commit this fork started from.

About

One terminal inbox for every coding-agent session waiting on you: Claude Code, Codex and OpenCode in tmux.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages