A tmux workspace dashboard for AI coding agents — run Claude Code, Codex, Kimi (or anything with a CLI) across your projects, fork an in-flight session to a different provider in an isolated git worktree, give forks lanes, sync them as your side moves, and hand their work back as a reviewable branch.
One Python file, stdlib only. No daemon, no API keys, no config to write — your agents' own CLIs do the auth.
forklane :: workspaces | 5 total · 3 running · 1 stopped · 1 candidate
CC: webapp, docs-site Codex: importer
[Enter] attach [s] start [f] fork [y] sync [F] hand back [?] more keys
┌── WORKSPACES ───────────────────────────────────────────────────────────────┐
│ > webapp ● running CC active 2m ~/projects/webapp │
│ importer ● running Codex 1h ~/projects/importer │
│ docs-site ● running CC active 1d ~/projects/docs-site │
│ api ○ stopped claude — ~/projects/api │
│ landing · candidate — — ~/projects/landing │
└─────────────────────────────────────────────────────────────────────────────┘
git clone https://github.com/pointvis/forklane
cd forklane && ./install.sh
forklaneRequirements: python3 ≥ 3.10, tmux, git. That's the whole dashboard — the
first run bootstraps a registry from your live tmux sessions and scans
~/projects for candidates. Agent features use whatever CLIs you already have
installed and logged in (claude, codex, kimi, …).
forklane <name> from the shell attaches straight to a workspace — the
dashboard is optional once you know your names.
Mid-session, you want a second opinion — or a second pair of hands — from a different model, without losing your own context or letting two agents fight over one working tree:
f(fork) — briefs your current session into aHANDOFF.md(goal, decisions and why, current state, gotchas — distilled from the actual transcript), creates a git worktree onfork/<provider>/<stamp>, and launches the target provider there, pointed at the brief. Fork worktrees live in.forklane-forks/next to your repo (in its parent directory), so both agents work at once without touching each other's files.--lane 'docs/,README.md'(CLI) — scopes the fork's territory. The kickoff prompt tells it to stay inside;syncwarns if its commits stray.y(sync) — as your original session keeps moving, merge its new commits into the fork (merge, never rebase), drop aSYNC.mdthere with the delta and an overlap report (files both sides touched), and nudge the fork's live session to read it. Conflicts are left for the fork to resolve — it knows its own side best.F(hand back) — writesRETURN.mdinto your original directory: commits, diffstat, leftovers, and the exact review/merge/cleanup commands — then delivers it to your original session (typed into it if alive, resumed otherwise). Nothing is ever merged for you.
forklane fork webapp --to codex --lane 'tests/' # or press f in the dashboard
forklane sync webapp--codex # after your side commits more
forklane return webapp--codex # when the fork is doneWhy a written brief instead of a transcript transplant? Providers keep sessions
in their own stores — there is no portable transcript. A brief is also just
better: a 50 MB transcript is ~98% tool output, and the 2% that matters is what
you'd tell a colleague. forklane-digest does that reduction deterministically
and free (2% of input bytes, under a second); $0.05–0.15 —
the one optional feature that shells out to the Claude Code CLI).forklane-brief turns the
digest into HANDOFF.md with one metered claude -p pass (
| Key | Action |
|---|---|
Enter/a |
attach (or start) selected workspace |
s / x |
start in background / kill tmux session |
N / n / d |
new session form / save ad-hoc row / drop registration |
R |
resume — Claude Code conversation picker, or the provider's own resume |
f / y / F |
fork to another provider / sync a fork forward / hand back |
P |
provider manager — add (auto-probes), login, health, remove |
c |
capture pane snapshot |
e |
edit the registry in $EDITOR |
/ |
type-to-filter · ? help · q quit |
Claude Code and Codex are built in. Add anything else without touching code:
forklane provider add kimi --argv kimi --resume 'kimi --resume' --prompt-flag=-p \
--login 'kimi login' --auth-probe 'send /login to login'
forklane provider doctor # installed → detected → logged in?
forklane provider login kimi # opens the vendor's interactive login in tmuxadd probes the binary in a throwaway tmux session to learn what
pane_current_command reports — the guess is wrong more often than not
(npm-wrapped codex shows up truncated; kimi sets its own process title).
Subscription CLIs need no API key anywhere: auth is the vendor's own login,
and doctor detects the logged-out state from the welcome screen.
Three common shapes (see providers.example.json for paste-ready entries):
| Shape | Example | How |
|---|---|---|
| Anthropic-compatible endpoint | Moonshot/Kimi, GLM coding plans | env ANTHROPIC_BASE_URL=… ANTHROPIC_AUTH_TOKEN=… claude |
| OpenAI-compatible endpoint | Grok, DeepSeek | env CODEX_HOME=~/.codex-grok codex (one CODEX_HOME per provider — never mix API keys into your default ~/.codex, Codex will log you out of ChatGPT mode) |
| Own harness | Kimi CLI | its own binary + family: kimi so resume uses its own store |
Everything lives in ~/.config/forklane/ (an existing ~/.config/cmux/ from
older installs is picked up automatically; FORKLANE_CONFIG_DIR — or the
legacy CMUX_CONFIG_DIR — overrides):
workspaces.json— the registry: workspaces (cwd,command,description),scan_pathsfor candidate discovery, optionaldescriptionsmap that labels known dir names,aliases.providers.json— provider overlay (see above).provider-health.json—doctor's cache.
These config files are code. A workspace's command and a provider's
argv are executed verbatim when you start a session — that's the point of a
launcher — so don't paste registry or provider entries you don't understand.
- Claude Code awareness reads
~/.claude/projects/*transcripts to list and resume conversations per workspace; other providers resume via their own CLIs. - Forking without a git repo falls back to sharing the directory — the kickoff prompt warns both agents in plain terms.
- forklane types text into tmux sessions (kickoff prompts, sync/return notes). It never merges, pushes, or deletes anything on its own.
MIT — see LICENSE.