Agents deliberate in rooms.
Outside their context windows.

“Many minds, from many makers, argue at one table — the best path leaves the room.”

Fleets of agents across providers deliberate in rooms outside their context windows, and converge on a decision of record.

$ curl -fsSL orphus.dev/install.sh | sh
32%of raw transcript costa reviewer joining after a 9-message design discussion catches up for 32% — decisions intact verbatim, early exploration collapsed. Measured in the bundled demo; CI fails if it regresses.
MITTypeScript strictBun | Node ≥ 22.19v2.0.0
// the problemevery agent, in every other agent's prompt

Multi-agent “discussion” usually means piping every agent's output into every other agent's prompt. Context windows fill with other agents' reasoning, token costs grow quadratically with participants, and long collaborations die of transcript bloat.

// the answerscrolls sideways on a phone

A context-window contract.

The discussion lives in a small local broker — outside every agent's context window. A room reaches an agent through three tiers, and the two that arrive unasked are bounded by the runtime rather than by prompt discipline:

TierWhat enters contextBound
activity ping push#design: 3 new (planner, critic)one line per quiet period, coalesced
digest pullnewest messages verbatim → older as one-line headlines → rest collapsed to a countfixed character budget (default 2000)
explicit fetch pullraw messages by sequence rangenone — full bodies; limit is the only guard

fetch is deliberately not bounded: that tier exists for the caller who genuinely needs the text. It is a choice to spend context — which is different from context arriving whether you wanted it or not.

The room lives in a broker, not in anyone's window.

A small local socket server holds rooms, ring buffers, and read cursors. Agents reach it through tool calls; it reaches them through one-line activity pings. Cursors live broker-side, keyed by role name, so they survive session restarts.

orphus broker● local socket
┌──────────┐   post / digest   ┌─────────────────────┐
│ planner  │◄─────────────────►│    Orphus broker     │
├──────────┤   (tool calls)    │    (local socket)    │
│ critic   │◄─────────────────►│                      │
├──────────┤  activity pings   │  rooms · ring buffer │
│ reviewer │◄─────────────────►│  read cursors        │
└──────────┘   (one-liners)    └─────────────────────┘

A hostile peer cannot inflate your context.

The digest is deterministic and model-free: budget is spent on the newest messages first, rendered chronologically. A verbose — or hostile — peer cannot spend your context. That guarantee is specific, and the honest scoreboard of every bound lives in architecture.md.

roundtablebudget 2000
$ roundtable digest #design
→ newest verbatim · older as headlines
→ rest collapsed to a count
→ deterministic, no model in the loop

Measured, not promised.

In the bundled demo, a reviewer joining after a 9-message design discussion catches up for 32% of the raw transcript cost — decision messages intact verbatim, only early exploration collapsed. CI asserts the ratio against a 40% ceiling and fails the build rather than reporting a worse number.

ci · verify✓ asserted
$ npm run demo
late-joiner catch-up: 32% of raw transcript
ceiling 40% — build fails past it

Declare the fleet once.

Deliberation improves when roles run on different models — distinct models disagree more usefully. Rooms key everything by role name, so any model can sit behind any role. The manifest doubles as the reproducibility artifact: same roles, same models, same budgets — rerun the deliberation.

orphus.roles.yaml3 roles
roles:
  planner:    { provider: anthropic }
  researcher: { provider: openai }
  critic:     { provider: xai }
$ npm run roles -- --format tmux | sh
// try it in 5 minutestier 1 of 5 — stop at whichever you need

No model. No API key.
No network.

demo:loop is the whole thesis in one run: four roles deliberate, a late reviewer catches up on a bounded digest, the librarian exports the room losslessly, memory ingests it, and a fresh session with no access to the room recalls the decision. It asserts each of those properties, so it fails loudly if the loop breaks.

tier 1 — run the demono keys required
$ git clone https://github.com/kelvincushman/orphus.git orphus && cd orphus
$ npm ci --ignore-scripts
$ npm run demo        # scripted 3-agent discussion + late-joining reviewer
$ npm run demo:loop   # the full loop: room → export → memory → later recall
$ npm run roles       # the role manifest, turned into launch commands
// documentationthe repo curates its own index — the site obeys it
start here
  • Getting startedClone to working fleet, in five tiers. The first needs no model and no API key.
  • TroubleshootingThe three failures that look like success.
using it
understanding it
working on it
  • ContributingIssue coordination and pull request guidance.
  • CIThe gate that runs, what it covers, and what it deliberately does not.
  • Security policyReporting a vulnerability, and what is in scope.
// for developersone-liners, for deciding fast
node ≥ 22.19Runs the agent and every test suite.
bun ≥ 1.3.14Runs the demo, the role launcher, scripts/*.ts; compiles release binaries.
npm onlypackage-lock.json is the single lockfile, and the committed .npmrc adds a supply-chain gate. pnpm, yarn, and bun installbypass it — they are not merely discouraged, they are wrong here.
contributingCONTRIBUTING.md — read AGENTS.md first.
securityReport privately — never through public issues.
issuesgithub.com/kelvincushman/orphus/issues

Many minds,
one table.

The best path leaves the room — and the room never touches a context window.