OSS MIT-spirited · built in the open by Matogen

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.

Runs locally, binds to 127.0.0.1 TypeScript, no UI framework Any shell or agent
~/api claude
› refactoring the payments gateway…
✔ read 14 files
✔ 3 edits applied
~/api npm test

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.

01 / TODAY

Window roulette

Twelve terminal tabs with identical titles. The only way to know which agent is finished is to open each one and look.

02 / TODAY

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.

03 / TRING

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 + SpaceOpen the picker
19, 0Focus slot 1–10
Shift+16Focus slot 11–16
nNext finished session, clockwise
SpaceBack to the previous session
c / r / xNew session / rename / kill
mMark seen — green back to grey
Alt+19Switch project
pNext project with a finished session
EscClose the picker
api · SESSIONS(3) done
1api · refactor gatewayDONE
2web · vite devBUSY
3infra · terraform planDONE
4docs · claudeBUSY
5db · psqlIDLE
6mobile · test watchDONE
7scratch · shEXIT 1

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.

SERVER

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.

node-pty@xterm/headlessws
PROTOCOL

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.

WebSocketOSC 133REST hooks
WEB

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.

Vitexterm.jscanvas

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.

~/.claude/settings.json
{
  "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.

npm bun
terminal
# install the CLI
$ npm install -g tring-chat

# start the deck
$ tring

# or run it once, without installing
$ npx 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.