Skip to content

Joining a Jam

Roy Padina edited this page Aug 30, 2026 · 6 revisions

Joining a Jam

You need node ≥ 22 and claude-jam (Install). You do not need tmux, and you do not need Claude Code — the session runs on the host's machine.

Finding the jam in the first place

If you are on the same network as the host, you do not need a URL from anybody:

claude-jam find          # what is announcing itself on this network
claude-jam join          # no argument: pick one off that list, or paste a link
# jam             host access view address
1 reeco debugging Roy  knock  no   roys-mac.local:7777
2 the other one   Dana token  no   roys-mac.local:7779

  reeco debugging: claude-jam join ws://roys-mac.local:7777 --name <you>
  the other one: claude-jam join ws://roys-mac.local:7779 --name <you> --token <token>

finding a jam is not being let into it: a knock still waits for the host, a token jam
still wants its token, and an invite-only jam still wants a link.

claude-jam join with no argument opens the launcher's Join screen on that same list. Pick a jam and it fills in the address and asks for what is still genuinely missing — your name always, the token only if it is a token jam. The last row is always "paste a link or URL", and it never disappears: a link is still how you join a jam that is not on your LAN, or one the host deliberately kept quiet.

Finding a jam is not being let into one. The access column tells you which door it is, not that the door is open:

what you found what still has to happen
knock you connect, the host sees ⚑ <you> wants to join and accepts you. You wait
token you need the token. Ask the host for it — it is not in the advertisement
invite invite-only. A knock is refused; ask the host for a cjam1_… link and paste it
? the jam did not say. Try a knock — the daemon decides, and it will say no if it means no

Not there? Three ordinary reasons, none of them a fault:

  • the host used --no-announce (or turned it off in /menu → Access), so the jam is running and deliberately silent — ask them for a link;
  • you are not on the same network. mDNS is link-local by design, so a jam across the internet (behind --tunnel or --funnel) is never discoverable — it is reached by its URL;
  • this machine has no mDNS tool, in which case claude-jam find says so and names the fix.

claude-jam find --json is the same facts with no layout, and claude-jam discover is the same command under the other name people reach for.

Three ways in

# an invite link — the whole command. No name to type, no token, no approval to wait for.
claude-jam join cjam1_eyJ2IjoxLCJqYW0iOiJhYmMx…

# the host runs knock-only: you connect, then wait to be accepted
claude-jam join ws://<host-ip>:7777 --name Dana

# the host handed you a shared token: straight in
claude-jam join ws://<host-ip>:7777 --name Dana --token abc123…

A knock shows waiting for host approval… and expires after 2 minutes. A link that is expired, revoked, used up, or whose name is already connected says so out loud and then falls through to a knock — you are never silently rejected.

flag what it does
--name <X> who you are. 1–24 characters of letters, digits, space, _ or -. Two live participants can never share a name: with a token or an invite link a clash is refused at once, and if you are knocking you simply join as Dana-2 and are told so (see Security Model)
--token <v> the shared token, when the host uses one
--basic the plain readline client: transcript only, no live view, no F2/F3/PgUp, no command list. Chosen automatically when stdin is not a tty. /history still works
--host a label the host's own client passes; it decides what is rendered, never what is allowed

What you land on

The host's real Claude Code screen, streamed live, plus the backlog of what happened before you arrived — up to the host's --replay events, with a ── history above · live from here ── divider under it.

Two views, and F2 swaps between them (/mirror does the same):

  • live TUI — the host's actual screen, at up to 25 frames a second while something is moving. It is drawn in your terminal's alternate screen buffer, the same trick less and vim use.
  • transcript — the full history: every message, every reply, tool calls and results. It owns the normal buffer, so its lines are your terminal's own scrollback: flipping F2 either way loses nothing, and nothing is reprinted.

Scrolling back

In the live TUI, PgUp and PgDn scroll back through the host's REAL pane history — the actual scrollback, colours and all, up to 2000 lines. Shift+↑/↓ moves one line at a time. End, G or Esc returns to live. You get this as a guest exactly as the host does: it is a read of a screen you are already watching, and there is no way back from it into the host's pane.

While you are scrolled back, live frames are held rather than painted over what you are reading, and the status row says how many are waiting:

⧉ mirror · scrolled back 40 lines · 3 live frames waiting — End/G returns to live

The mouse wheel works too, but only if your terminal is already sending wheel events — claude-jam never turns mouse reporting on, because that would take text selection away from you.

In the transcript, /history [n|all] re-prints further back than the replay you were given, a page at a time, under a dim divider that says what is still behind it.

Three different limits sit behind "I can only see a little of this", and they are separate:

limit what it is how to get past it
--replay how much of the transcript you were SHOWN on arrival (300 events by default) /history [n|all]
--history how much the jam still KEEPS (2000 events by default, 20000 at most) /export — the complete record
2000 lines how far the live TUI can scroll back — the host pane's own scrollback nothing; those lines are gone from the pane too

The client tells you which one you hit, once, the first time you scroll to the very top:

— that is as far back as this jam kept (1200 events · host pane 2000 lines) · /export for the full transcript

A plain line goes to the agent as [Dana]: …. Attribution is symmetric — the host is a [Name] too. Typing / raises a dim list of claude-jam's own commands.

Multi-line input: Shift+Enter (kitty/CSI-u terminals), Option/Alt+Enter, or a trailing \ — the last one works everywhere.

/ recall your own last 50 submissions. They are yours, per client, kept in ~/.config/claude-jam/history (mode 0600), and they survive a restart.

Commands anyone can run

command effect
(a plain line) goes to claude as [Name]: …
/c <text> human-only chat. The agent never sees it, and never claims to have
/who the roster, and how long since each person last touched a key — Roy (active), Dana (idle 4m), Yossi (away 20m+)
/help reprint the onboarding block
/menu the live control panel — a guest's /menu lists exactly what a guest may do
/ping <Name|all> [message] (alias /nudge) get somebody to look at their screen — see below
/sound [on|off] your own client's sounds. Bare /sound reports all three tiers
/mirror, F2 swap live TUI ⇄ transcript
PgUp / PgDn in the live TUI: scroll back through the host's real pane history (Shift+↑/↓ a line, the wheel if your terminal sends it)
End / G / Esc back to the live screen
/history [n|all] re-print further back than the replay you were given
/tools, /tools on|off reprint the last turn's full tool log · stop or resume collapsing tool lines
/files every path this session read, wrote or edited — newest first
/diff [path] git diff --stat of the host's working tree, or the real hunks for one path
/answer, /answer <n> show what claude is asking · answer it
/answer <q> <n> one question of a multi-question form — only the one on screen
/outbox, /retry what was kept when a message could not be confirmed · send the newest again
/send <path>, /paste [caption] upload a file to the host (they approve)
/get [name] save a file the host offered into ./jam-downloads/
/export take the transcript home (the host approves)
/peer [on|off|never] whether the host's claude may ask your Claude Code to do work, on your machine and your quota. Off until you turn it on, every task still needs your approval, and never settles it for the session — see Peer Tasks
/peers, /peers log who has opted in · the audit trail, which both sides can read
/quit leave. The jam keeps running

Three of claude's own commands run for you with no round trip at all: /cost, /status and /context — exactly those three, and exactly bare. /cost --json is an argument the allowlist has not read, so it asks like anything else. Their output lands on the shared screen.

Every other /command belongs to claude and becomes a request the host approves once (or always, for this jam). /exit, /clear and /resume are refused outright — they would end or wipe the session for everybody.

Getting somebody's attention (/ping)

A bell only helps somebody who is looking at that terminal. A nudge is an explicit, addressed "look at your screen", and anyone may send one — you do not need the host's permission to ask a colleague a question.

/ping Roy    can you look at line 40?
/ping all    standup in 5
/ping Roy !                              # repeat it once after a minute if they are still away
  • The person addressed gets a highlighted 👋 Dana is asking for you: can you look at line 40? — not a chat line — plus their own bell, sound and notification, according to their toggles. How loud a nudge is, is the recipient's decision and never the sender's.
  • A nudge is never secret. Everybody else sees a dim * Dana nudged Roy.
  • Never queued. Nudging somebody who is not connected is refused right there — Yossi is not connected — because an attention-getter that arrives an hour late is worse than one that never arrives.
  • One per person per 30 seconds (one to everyone per 60), and the refusal says how long is left.
  • ! at the end repeats it once after a minute, and only if they still have not become active. Once. Never a loop.

Who is idle. Your client reports one number: whole seconds since you last typed or submitted. Nothing about what you typed is ever reported — there is no key, no text and no window title in that path. /who and /menu → Notifications show active / idle 4m / away 20m+, and the confirmation after a nudge tells you which state the person was in, so you can decide whether to nudge at all.

Your phone, if you want it. Entirely opt-in, and set up on your own machine — put this in your ~/.config/claude-jam/config.json:

{ "ntfy": { "server": "https://ntfy.sh", "topic": "a-long-random-word-only-you-know" } }

Then a nudge addressed to you is POSTed to that topic by your own client. The topic is a password for your phone, and it stays yours: it is never sent to the host, never put in an invite link, never in the protocol and never in a log — see Security Model. Restart your client after editing the file.

Answering what claude is asking

claude-jam classifies the host's current screen two and a half times a second, and the in your status row says what is really there.

  • A question — claude's own AskUserQuestion picker — is a product decision, so anyone may /answer <n>. No approval, first answer wins, and the room is told who answered what. (A host who started with --answers host keeps it to themselves.)
  • A permission — a tool asking to be allowed — is a security grant. You can still /answer <n>, but it becomes a request: the host approves that digit, and the daemon types that one digit, only while the prompt is still really up and still says the same thing. You never get raw keys.
  • The free-text option (Type something.) is raw keyboard access, so it stays the host's in every mode.
  • A dialog with nothing numbered on it is nobody's to relay — the host takes the keyboard.

What is never yours

  • F3 (attach the real TUI) is host and loopback only. If you need to answer a prompt, /answer is the way.
  • The single-key approval bar (a/d/i) is the host's.
  • Everything in Hosting a Jam's host-only list.

Your message is never lost

Every message is written to the host's outbox (0600) before it is pasted, and deleted only once the input box is seen to empty. If it cannot be confirmed you get

couldn't confirm your message reached claude — kept at <path> · /retry to send it again

Nothing is retyped or wiped behind your back, and /outbox, /retry and / are three different ways to get it back.

Leaving

/quit (or closing the client) leaves the jam running for everybody else. If the host ends it, your client prints <Host> ended the jam and exits 0 — an orderly end is not a failure, and there is nothing to reconnect to.

Next

Files and Export · Remote Access · Security Model · Troubleshooting

Clone this wiki locally