Skip to content

Azhovan/Threadline

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Threadline

Let your AI agents talk to each other. Threadline is a tiny bridge that lets two agents — running in separate terminals — collaborate in real time: hand off work, ask each other questions, review one another's output, and coordinate to a shared goal.

Why

A single agent works alone in its own context. Threadline lets you run several and have them cooperate:

  • Divide and conquer — one agent writes code while another reviews it, or a planner delegates subtasks to workers and collects the results.
  • Specialize — give each agent a focused role (researcher, coder, critic) and let them confer instead of cramming everything into one prompt.
  • Coordinate anywhere — agents can run in any terminal, any directory, even different projects on the machine. They share nothing but a relay URL.
  • No wasted turns — an agent sleeps until a message actually arrives, so it spends a turn (and tokens) only when there's something to act on.
  • Zero infrastructure — no broker, no cloud, no accounts. One local process and two small scripts.

Requirements

Node.js (current LTS) and npm. The only runtime dependency is ws, installed in the next step.

How to use it

Start the relay once, from the repo directory:

make install     # one-time per clone
make start       # runs the relay in the background
make status

Then, in each agent's terminal (anywhere on the machine):

make send   FROM=A TEXT="hello B"
make listen FROM=A                       # blocks until a message arrives, then exits
make done   FROM=A TEXT="bye"            # sends a final message, ends the conversation

Stop the relay when you're done: make stop.

To watch it run without wiring up two real agents, use make demo — it starts its own relay and plays two mock agents through a full exchange.

The agent loop

With the relay running, each agent terminal repeats the same cycle:

  1. Run node wait.js --from <me> in the background.
  2. When it exits → read the new entries in inbox.<me>.md.
  3. If the exit code was 3, the peer ended the conversation — stop. Otherwise reply with node send.js --from <me> --text "..." and go back to step 1.

wait.js exits 3 when the peer sent --done, 1 on error, and 0 otherwise. Note that exit 0 covers both "a message arrived" and "idle timeout, nothing arrived" — tell them apart by wait.js's stdout ([wait] N new message(s) vs [wait] idle timeout), not by the exit code. The non-zero 3 is the signal to stop the loop instead of relaunching the listener — that's how a conversation ends cleanly instead of ping-ponging forever.

More commands

The Makefile wraps a few more targets (logs, restart, fresh-listen, clean, …). For the full list with descriptions:

make help

Each script also documents its own flags (--idle, --fresh, COMM_DIR, …) in a header comment at the top of the file — see send.js and wait.js.

Good to know:

  • Everything defaults to port 9000. To use another port, start the relay with make start PORT=9100 and export RELAY_URL=ws://127.0.0.1:9100 in every agent terminal (no flag overrides RELAY_URL).
  • A late joiner — an agent connecting after the conversation has started — should use make fresh-listen FROM=B (or node wait.js --from B --fresh) for its first listen, to join at the live head and skip replaying old backlog.
  • make start clears existing inboxes and cursors (inbox.*.md, .seq.*) when it launches a fresh relay, so don't make restart mid-conversation if you want to keep the history.

How it works

 Terminal A                  relay (one process)              Terminal B
 ┌──────────┐          ┌────────────────────────┐          ┌──────────┐
 │ Agent A  │  send.js │  ws://127.0.0.1:9000    │  send.js │ Agent B  │
 │          ├─────────►│  broadcasts + backlog   │◄─────────┤          │
 │          │  wait.js │                         │  wait.js │          │
 │  inbox ◄─┤◄─────────┤                         ├─────────►├─► inbox  │
 └──────────┘          └────────────────────────┘          └──────────┘

A small relay process sits in the middle and broadcasts each message to the other agents. The "wake up" is the trick: an agent runs in turns, not as a long-lived listener, so wait.js does the blocking. It connects, waits for a fresh message, appends it to inbox.<name>.md, and exits — and that exit is what re-invokes the agent for its next turn.

The relay is a standing service you start once. After that, any local process can join by pointing at the same relay URL, and each agent writes its inbox to its own working directory — so they share nothing but the URL.

Caveats

  • Near-real-time, not instant — there's wake + turn latency per message.
  • Each reply costs a turn. Always set a stop condition (the --done sentinel, a max-message count, or a human in the loop).
  • Localhost only as written — relay.js binds 127.0.0.1. For two machines, bind 0.0.0.0 and point RELAY_URL at the host, or use an SSH tunnel.
  • Messages are plain JSON over an unauthenticated local socket — fine for localhost, not for exposing to a network.

About

lightweight communication channel that lets independent ai coding agents coordinate with each other in real time.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors