Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yakka

A terminal multiplexer with one opinion: the screen is split down the middle, Claude Code lives on the left, Codex lives on the right. Each side keeps its own list of sessions in its own sidebar, and either side can be split horizontally so you can work on two Claude sessions and two Codex sessions at once.

┌─CLAUDE────┬──────────────────╥──────────────────┬─CODEX─────┐
│▸ atlas    │  claude · atlas  ║  codex · atlas   │▸ atlas    │
│ ·mobile   │                  ║                  │  checkout │
│  checkout*│  > implementing  ║  > reviewing …   │ ·mobile   │
│           ├──────────────────╫──────────────────┤           │
│           │  claude · mobile ║  codex · mobile  │           │
└───────────┴──────────────────╨──────────────────┴───────────┘

Both sidebars are the same width, so the divider falls on the true centre of the window. In the sidebar, marks the session in the focused pane and · one that is on screen elsewhere. After the name:

working — it said something recently
wants you — it went quiet, or rang the bell, while off screen
the process exited

is the one to watch. It appears when an agent stops, not when it speaks, so it means "this one is waiting on you" rather than "this one is busy".

Install

Download a prebuilt binary from Releasesyakka-macos-universal.tar.gz runs on both Apple Silicon and Intel:

tar xzf yakka-macos-universal.tar.gz
chmod +x yakka
xattr -d com.apple.quarantine yakka   # macOS Gatekeeper; the binary is unsigned
mv yakka ~/.local/bin/                # or anywhere on your PATH

Each release also ships a .sha256 next to the archive:

shasum -a 256 -c yakka-macos-universal.tar.gz.sha256

Or build it yourself:

cargo install --git https://github.com/romankhadka/yakka --root ~/.local

Needs claude and codex on your PATH. Run yakka.

Keys

Ctrl-a is the prefix, configurable via prefix. It is a leader, not a chord: press and release Ctrl-a, then press the command key on its own. Everything else goes straight to the focused agent, so the agents keep all their own bindings.

Key Action
Ctrl-a h / l Focus the left / right half
Ctrl-a j / k Focus the pane below / above
Ctrl-a Tab / S-Tab Next / previous session on this side
Ctrl-a 19 Show the nth session of this side
Ctrl-a n New session (directory picker)
Ctrl-a s Split this half horizontally
Ctrl-a w Close this pane, leave the session running
Ctrl-a x Kill this session
Ctrl-a z Zoom this pane to the whole window
Ctrl-a b Show or hide the sidebars
Ctrl-a r Restart the process in this pane
Ctrl-a [ Scroll back through history
Ctrl-a d Show what this session changed
Ctrl-a * Broadcast keys to every visible pane
Ctrl-a m Move this session to the other side
Ctrl-a , Rename this session
Ctrl-a ? Help
Ctrl-a q Detach — leave, with the agents still running
Ctrl-a Q Quit and stop every agent
Ctrl-a Ctrl-a Send a literal Ctrl-a to the agent

In scroll mode: j/k by line, Ctrl-d/Ctrl-u by half page, g/G for the ends, / to search back through history, q back to live.

The picker offers recently used directories first; typing filters by fuzzy match, and recency only breaks ties between equally good matches.

Selecting a session that's already in this side's other pane swaps the two rather than showing it twice, so Ctrl-a Tab with a split is a quick way to trade places.

Sessions

Ctrl-a n lists your scan roots and their immediate children, filtered as you type. Choosing one starts that side's default agent there.

If the highlighted directory is inside a git repository, Tab switches to worktree mode: yakka branches yakka/<agent>-N off the default branch, creates a worktree beside the repository, and runs the agent there. Two agents working at once then cannot edit the same files — which is the point of running them at once.

Killing a session removes its worktree, unless it has uncommitted changes, in which case it is left alone and says so.

Quitting saves the layout to state.json, so the next launch rebuilds the same panes: reattaching to any agent the session host still has, and otherwise resuming the conversation with claude --continue or codex resume --last — both scoped to the session's directory, so nothing picks up an unrelated conversation from another repo. yakka --fresh starts empty.

If a resumed session dies immediately because there was nothing to resume, it is restarted once without the flag. A process that exits keeps its final screen and offers Ctrl-a r; one that never started explains why in its pane.

Detaching

The agents do not run inside the yakka you are looking at. They run in a per-user session host that yakka starts on first use and talks to over a unix socket, so leaving is a detach rather than a kill:

Ctrl-a q Leave. The agents keep working.
yakka Come back to them, screens and scrollback intact.
Ctrl-a Q Stop every agent and close the host.
yakka kill The same, from outside.

This is the thing --continue cannot do: a resumed conversation replays what was said, while reattaching finds the same process still running — mid-task, mid-output, with everything it had printed still on screen.

The host keeps the last couple of megabytes of each session's output. Beyond that the scrollback is dropped and reattaching restores the visible screen only.

If yakka cannot reach the host it says so and runs the agents itself, so a broken socket costs you detaching rather than the session. --no-server asks for that on purpose, and server = false makes it the default; either way quitting stops the agents, and yakka asks before it does.

Configuration

~/.config/yakka/config.toml, all optional:

scan_roots = ["~/code"]   # directories whose children fill the picker
sidebar_width = 22        # columns per sidebar
sidebars = true           # show them on startup

prefix = "ctrl-a"         # leader key: ctrl-/alt-/shift- plus a key, or f1..f20
max_panes = 2             # panes a side can be split into, up to 4
mouse = true              # capture the mouse (see Notes)
idle_after = 2.0          # seconds of silence before an agent counts as idle
server = true             # run the agents in a session host (see Detaching)

left_agent = "claude"     # which agent new sessions on each side start with
right_agent = "codex"

A side has a default agent, not a fixed one — any session can run any agent. Adding one takes no code:

right_agent = "gemini"

[[agents]]
name = "gemini"
command = "gemini"
resume = ["--continue"]   # omit if it cannot resume; it will start fresh

An [[agents]] entry named claude or codex replaces that builtin, which is how you point yakka at a wrapper or a project-local build.

Environment overrides:

Variable Effect
YAKKA_CLAUDE_BIN Binary to run for the claude agent
YAKKA_CODEX_BIN Binary to run for the codex agent
YAKKA_<NAME>_BIN Same, for any agent you define
YAKKA_CONFIG_DIR Where config.toml and state.json live

Notes

The mouse is captured: clicking focuses a pane, clicking a sidebar row shows that session, and the wheel scrolls a pane's history. An agent that asks for mouse reports gets them instead — without capture the agents would never see the mouse at all, so their own scrolling would be dead.

Hold Option (macOS) or Shift for your terminal's native selection and copy while capture is on. Set mouse = false to hand the mouse back entirely.

Where the terminal supports the Kitty keyboard protocol (Ghostty, Kitty, WezTerm) yakka enables key disambiguation so Shift+Enter reaches Claude Code as a soft newline. Elsewhere it behaves as it always has.

Sidebars hide themselves below 100 columns. Below 60x20 yakka says so rather than drawing something unusable.

Development

cargo test                                              # unit + end-to-end
cargo test --test real_agents -- --ignored --nocapture  # against the real CLIs
cargo clippy --all-targets -- -D warnings

The end-to-end tests run the real binary inside a PTY, press real keys, and read the rendered screen back, with stub agents substituted via YAKKA_CLAUDE_BIN and YAKKA_CODEX_BIN.

Design notes are in docs/superpowers/specs/2026-07-24-yakka-design.md.

Releases are cut by tagging: git tag v0.2.0 && git push --tags builds a universal macOS binary and a Linux x86_64 binary and publishes both with checksums.

Licence

MIT — see LICENSE.

About

Terminal multiplexer for coding agents: Claude Code and Codex side by side, each session in its own git worktree, running in a detachable host

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages