gangline

Many harnesses. One line.

A harness harness. Gangline unifies any CLI coding agent it can get its hands on — Claude Code, Codex, opencode, Pi, whatever ships next — into a tmux-powered team, using each for its strengths, with minimal harness-specific integration.

A gangline is the single rope that hitches many dogs, each in its own harness, to one sled and one musher. The integration point is the attachment clip — never surgery inside the dog.

There is no server, no bus, and no database. tmux already holds the state, so gang is a CLI you run and it exits.

One message to a Claude Code lead: it hires a Codex worker, waits for the work, then hires an opencode reviewer to check it. Real harnesses, real subscriptions, unedited except for cuts through the waiting.

$ cd ~/my/repo && gang up
$ gang spawn worker -p codex -r worker
spawned worker (codex) in ~/my/repo — watch: gang attach
briefed worker as worker
$ gang send worker --from lead "read the failing test in ci and fix it"
delivered to worker as [gang:lead] (verified in pane, submitted)
$ gang roster
lead             claude-code  idle (slack tug)   142k/1000k (14%)
worker           codex        busy (tight tug)   31k/272k (11%)

Install

$ curl -fsSL https://raw.githubusercontent.com/adambiggs/gangline/main/install.sh | sh

Needs git and tmux ≥ 3.2. Clones to ~/.local/share/gangline, links gang into ~/.local/bin, re-run to update. Piping a stranger's script into a shell is your call to make — read it first, or clone and symlink bin/gang yourself; the installer does nothing more.

How it works

Agents are tmux windows.
Spawning is new-window, killing is kill-window, watching is capture-pane, and the window name is the agent's identity. Attach and you are looking at your team — the pane is the transcript, and you can type into it yourself at any time.
Every message is attributed and verified.
A send carries a [gang:<sender>] prefix, is confirmed by capturing the pane, and only then submitted. No sender means no send. Unverified means a loud failure, never a shrug.
Agents manage their own context.
A model cannot feel its own token count, so the substrate measures it and warns at configurable bands. The agent compacts itself at the next clean seam, queuing a resume directive behind the compaction so work continues unattended.
A new harness costs a profile, not an integration.
Launch command, busy marker, compact command — about ten lines. Everything else is universal. Profiles scrape the stock TUI: a theme or UI extension that repaints it takes a shadow profile of your own (GANG_PROFILES), re-verified against what you actually run.
Batteries included, every one replaceable.
Agents spawn with a role brief — lead, worker, reviewer. Point GANG_ROLES at a directory of your own and any brief becomes yours.

Delivery is measured, not assumed

A send is three reads of the target's input box, not a spray of keystrokes. gang reads the box, pastes, and reads again — the box must have changed. Enter goes in as its own keystroke, and a third read confirms the submit.

Matching the text somewhere on screen would verify against an identical earlier send still sitting in the transcript; a box that changed is the harness-independent fact underneath every TUI's rendering, whether it echoes a paste literally or collapses it into [Pasted text #2]. And the separate Enter matters: batch text and newline into one burst and a TUI reads the newline as part of the paste, parking your message in the box as an unsent draft that scrollback renders exactly like a sent one. If any read disagrees, the send dies loudly — and nothing was submitted.

Context is measured, not felt

Measure, warn, act — the substrate does the first two, the agent does the third. Usage is read through each harness's own introspection: a statusline beacon, a painted readout, or the session file the harness itself writes. Two warning legs run the same band ladder over that one readout — an in-turn hook where the harness has hooks, an ambient cron patrol where it doesn't — and share one band memory, so an agent is warned once per band, not once per leg.

[gang:patrol] [context-usage] 187k/272k (69%) in context — crossed the
180000-token band. At the next checkpoint (arc boundary), run:
gang compact worker --from worker --resume '<where you are, what is next>'
— it queues behind the turn you are in, and the resume is delivered once
compaction settles.

The agent then compacts itself at the next clean seam — tests green, a commit made — without being idle first and without anyone watching. The --resume never rides the input queue behind its own compaction, where the turn about to be compacted could swallow it; a detached waiter delivers it at the first moment it cannot be overtaken, and the agent picks it up the instant it has a context to pick it up into.

Loud refusals, never guesses

gangline's failure mode is a refusal you can read, not a guess you can't.

$ gang send reviewer --from lead "ship it"
gang: refusing to deliver 'ship it': reviewer is gated (hook set) — a
permission prompt only the operator can answer owns the screen (gang attach)

The verbs

commandwhat it does
gang up the whole setup, no arguments: spawns lead in the current repo and puts you in the session
gang spawn <name> -p <profile> -r <role> start an agent — the name becomes its tmux window, its identity, and its handle
gang send <name> --from <you> "…" attributed, pane-verified message; delivered mid-turn where the harness takes input during one
gang roster everyone, with harness, state, and context usage
gang status / context / capture one agent's state, window usage, or screen
gang compact <name> --resume "…" trigger the harness's own compaction; the resume lands once it settles. Naming yourself is the ordinary case
gang patrol ambient roster sweep from cron: band warnings in, gate reports out
gang doctor strategy-rot check: installed harness versions against each profile's verified pins
gang attach / kill / down watch the team live; end an agent; end the session

Extend it

A profile says how to talk to a harness; a role says what an agent is for. They are the same kind of extension point, and neither is an integration.

The trail

The vocabulary is mushing, and every term names something real in the system — the musher's field guide maps all of it. A sample:

on the trailon the team
tight tug / slack tug busy / idle — a pulling dog keeps its tugline taut
hook set gated — the snow hook is dug in, and only the musher pulls it
checkpoint the clean seam an arc ends on — tests green, a commit made — where compaction and releases happen
dropped a released agent — deliberate, routine, the musher's call; health, not failure
dog in the basket an idle-parked agent still burning a context window — the anti-pattern dropped exists to prevent
intelligent disobedience a good lead refuses the command onto thin ice — once, short, specific; the musher's word is then final

Of the 1925 serum run's lead dogs, Togo ran the long, dangerous leg while Balto got the statue — credit your working dogs.

One bash script. Profiles and roles are files you can replace. tmux is not a hack under it — tmux is the substrate, and when the metaphor stops carrying weight, every command still reads literally without it.