Sixteen agents.
One screen.
Nothing waiting unnoticed.
tring.chat is a focus-centred terminal deck for agentic work. The session you're typing in fills the centre. Up to sixteen more run in live thumbnails around it — and the second one finishes and needs you, its tile turns green. Every project gets its own tab, its own ring of sixteen.
The problem
Parallel agents don't fail loudly.
They just sit there, done, in a window you can't see.
Fan work out to eight coding agents and you've traded one bottleneck for another: you become the scheduler. Alt-tab, check, nothing yet, alt-tab, check. tring.chat gives every session a fixed place on screen and a colour you can read at a glance.
Window roulette
Twelve terminal tabs with identical titles. The only way to know which agent is finished is to open each one and look.
Layouts that shuffle
Tiling panes move when you focus them. The session that was bottom-right is now top-left, and your muscle memory is worthless.
Fixed slots, one glance
Sixteen numbered slots that never move. Amber means working, green means waiting for you. Ctrl+Space then one key to jump.
What it does
Built for the way agents actually run
Long stretches of unattended work, punctuated by a moment where something needs a human. tring.chat is engineered around detecting that moment.
Projects are tabs
A project is a directory and a ring of its own — sixteen slots for the API, sixteen more for the web app, nothing bleeding between them. Tabs run across the top and keep reporting while you're not looking at them: the tab dot goes amber while anything inside is working and green with a count the moment one finishes, so the project you left an hour ago still tells you it's waiting.
Green means "your turn"
Four independent signals feed one state machine: idle detection, OSC 133 shell prompt markers, a terminal bell, and an optional Claude Code Stop hook. Whichever fires first turns the tile green.
Live thumbnails, cheap
The daemon keeps a headless terminal per session and streams throttled snapshots. Thumbnails are plain 2D canvases — sixteen busy sessions cost at most 64 small repaints a second.
Slots never shuffle
Focusing a session shows it in the centre without moving it out of its slot. Slot 7 is slot 7 forever, so Ctrl+Space 7 becomes reflex.
Reload loses nothing
The Node daemon owns every PTY and its scrollback, not the browser. Close the tab, reopen it, and every session replays exactly where it was.
Tool-agnostic
Claude Code, any other coding agent, a build watcher, a plain shell — if it runs in a terminal it runs in a slot. Claude Code gets optional extras, never a dependency.
Read it before you clear it
Focusing a green tile doesn't clear it. It stays green until you actually type into it, so you can read the result first and still see what's unhandled.
The picker
Two keystrokes to anywhere
Ctrl+Space opens an overlay over the ring. One more key and that session is in the centre.
| Ctrl + Space | Open the picker |
| 1–9, 0 | Focus slot 1–10 |
| Shift+1–6 | Focus slot 11–16 |
| n | Next finished session, clockwise |
| Space | Back to the previous session |
| c / r / x | New session / rename / kill |
| m | Mark seen — green back to grey |
| Alt+1–9 | Switch project |
| p | Next project with a finished session |
| Esc | Close the picker |
The done count also goes in the document title — (3) tring — so you can see it from another browser tab.
Architecture
A local daemon, one real terminal, sixteen cheap ones
TypeScript end to end. The browser is a view; the daemon is the truth.
Owns every PTY
node-pty spawns each session and pipes its output into a headless xterm with 5,000 lines of scrollback. Prompt markers, titles and bells are parsed out of the same stream.
One socket per tab
Binary frames carry output for the focused session; JSON carries state, status and snapshots. Snapshots are capped at four a second and only sent when the screen actually changed.
No UI framework
A 5×5 CSS grid. One xterm.js instance with WebGL for the centre, sixteen 2D canvases for the ring. Vanilla TypeScript, because a deck of terminals doesn't need a virtual DOM.
Claude Code
Optional, exact
Idle detection already turns the tile green a few seconds after Claude stops.
Add one Stop hook and it turns green the instant the turn ends instead.
The env vars are injected into every session's PTY, so the same config is correct everywhere.
{
"hooks": {
"Stop": [
{ "hooks": [ { "type": "command",
"command": "curl -s -X POST \
\"$TRING_URL/api/sessions/$TRING_SESSION_ID/done\"" } ] }
]
}
}
Install
One package. Either runtime.
tring is a single npm package. It starts the daemon, binds to 127.0.0.1 and opens the deck in your browser. Node 20+ or Bun 1.1+ — nothing else to configure.
# install the CLI $ npm install -g tring-chat # start the deck $ tring # or run it once, without installing $ npx tring-chat
# install the CLI $ bun add -g tring-chat # start the deck $ tring # or run it once, without installing $ bunx tring-chat
Then hit Ctrl+Space and a number to jump to any session.
macOS and Windows install with no compiler step. On Linux and WSL the terminal backend is built from source, so build-essential and python3 need to be present first.
Stop hunting for the agent that's done.
It's open source. Read it, fork it, tell us where the design is wrong.