-
Notifications
You must be signed in to change notification settings - Fork 0
Agent Install
This page is written for an agent. Every step is non-interactive and copy-pasteable, and every step says what to check before moving on. If you are a human, Install is shorter.
If you were sent here to change the claude-jam source, this is the wrong page — read
AGENTS.md in the repo instead.
Not as a cleanup, not as a recovery, not "just this once". Each one destroys work that is not yours, and no later step can undo it.
| never | why |
|---|---|
tmux kill-server |
ends every tmux session on the machine, including the human's |
pkill, killall, kill $(pgrep …), any name- or pattern-matched kill |
you cannot tell your process from someone else's by its name |
tmux kill-session with a bare or pattern target |
tmux prefix-matches, so -t jam also matches jamboree. Always -t =exact-name
|
| ending a jam you did not start |
claude-jam sessions may list somebody's live work. Read it; do not end it |
brew upgrade with no argument, or any global config edit |
you were asked to install one thing |
A jam may already be running on this machine — commonly on port 7777, tmux session jam,
on the default tmux socket. Treat it as read-only.
node --version && tmux -V && claude --versionVerify: node is v22 or higher, tmux prints a version, claude prints a version.
If claude is missing, stop — claude-jam hosts the real Claude Code CLI and cannot substitute
for it. This step needs a human if Claude Code is not installed or not logged in.
Optional tools, each unlocking exactly one feature. Missing ones are not an error:
command -v ttyd cloudflared tailscale git pngpastebrew install roypadina/tap/claude-jamVerify:
command -v claude-jamExpected: a path (typically /opt/homebrew/bin/claude-jam or /usr/local/bin/claude-jam).
If Homebrew is not available, install from source instead:
git clone https://github.com/roypadina/claude-jam ~/claude-jam
cd ~/claude-jam && npm installVerify: node --check ~/claude-jam/host.mjs exits 0, and run everything below as
~/claude-jam/claude-jam … rather than claude-jam ….
claude-jam --helpExpected: a usage block beginning
usage: claude-jam (no arguments) the launcher menu: host, join,
listing host, join, invite, invites, sessions, ls, end, kill, clean, remote.
jam is installed as a deprecated alias of the same executable. Never use it in anything you
write down.
Do not run claude-jam with no arguments. With no arguments it opens an interactive
launcher menu and waits for a keypress you cannot give it. Always pass a subcommand, or
--no-menu for the usage text.
claude-jam sessionsExpected, on a machine with no jam:
no jams — `claude-jam host` starts one, and this list only ever shows claude-jam's own sessions
If it lists rows, read them and change nothing. A live row is somebody's running session.
A row marked ! orphan is a dead session's leftover directory — it is still not yours to clean
unless you were asked to. claude-jam sessions --json is the same facts for a script.
claude-jam host --name <YourHumanName> --cwd "$PWD" --no-attach --no-promptFlags that matter for a non-interactive run:
| flag | why you want it here |
|---|---|
--no-attach |
do not open a client of its own. Without it the launcher takes over the terminal |
--no-prompt |
never ask "keep it running or end it?" — a prompt you cannot answer is a hang |
--cwd <dir> |
the directory claude runs in. Use an already-trusted one (see below) |
--port N |
pick a free port if 7777 is taken. The state dir and tmux socket follow the port |
--tmux <name> |
name the tmux session. Default claude-jam; a second one auto-names claude-jam-2
|
--token <value> |
8–64 chars of [A-Za-z0-9_-]. Without it the jam is knock-only and every join waits for a human |
-- <claude args> |
everything after -- goes to claude verbatim, e.g. -- --model haiku
|
Verify: the command prints claude-jam up., a session UUID, the tmux session name and its
socket, then a Send this to a friend: block. Then:
claude-jam sessions --jsonExpected: one object whose "name" is your tmux session and whose "state" is "live".
This step can need a human: in a directory Claude Code has never run in, claude shows a
"do you trust the files in this folder?" dialog. The daemon answers it automatically before its
first injection, but if you see nothing happening, attach and look:
tmux -L claude-jam-<port> attach -t <name>:claude.
Pick one. An invite link is the recommended one — it is per person, revocable and expiring.
claude-jam invite Dana # multi-use, 24 h
claude-jam invite Dana --uses 1 --expires 30m # one shot
claude-jam invites # list them (never reprints a link)
claude-jam invite revoke Dana # take one backVerify: claude-jam invite Dana prints a line beginning claude-jam join cjam1_…. That
whole line is the guest's entire command.
An invite link is a credential. Give it to the human to send over a private channel. Do not put it in a commit, an issue, a log, a pull request, or anything else that persists.
claude-jam join cjam1_… # an invite link: nothing else needed
claude-jam join ws://<host>:7777 --name Dana --token <tok> # a shared token
claude-jam join ws://<host>:7777 --name Dana # no token: a knock, a human accepts youVerify: the client opens on the host's live TUI. With a knock it prints
waiting for host approval… and stays there until a human answers — that is a human step,
and it times out after 2 minutes.
The client is a full-screen terminal app. Under an agent with no real terminal, add --basic
(it is also chosen automatically when stdin is not a tty): transcript only, no live view, no
F2/F3, no command list.
claude-jam end <name>Expected:
ending jam "<name>" (port <port>, session <first-8-of-uuid>)
daemon told everyone the jam is ending
tmux session <name> is gone
Exit code 0. Every connected client prints <Host> ended the jam and exits 0 as well.
claude-jam end refuses anything it did not create: a session is endable only when it carries
claude-jam's ownership marker and that marker points at a state directory whose
session.json names that exact session back. If it refuses, the message says what did not line
up. Do not work around it with tmux kill-session — that is the human's call.
Runs end to end, spends no tokens (no message is ever sent), touches nothing that already
exists. It uses port 7788 and the session name agentcheck so it cannot collide with a default
jam on 7777.
set -e
claude-jam --help | head -1
claude-jam host --tmux agentcheck --port 7788 --view-port 7789 \
--name Check --token agentchecktoken0 --cwd "$PWD" --no-attach --no-prompt -- --model haiku
claude-jam sessions --json
claude-jam end agentcheckExpected output, in order:
usage: claude-jam (no arguments) the launcher menu: host, join,
claude binary: /…/claude
claude-jam up. session <uuid>
tmux: agentcheck on socket claude-jam-7788 (windows: daemon, claude) — detached;
`tmux -L claude-jam-7788 attach -t agentcheck:claude` for the raw TUI
Send this to a friend:
invite: … ws://<your-ip>:7788 --name <You> --token agentchecktoken0
then a JSON array containing an object with
{ "name": "agentcheck", "state": "live", "port": 7788, "socket": "claude-jam-7788" }(other rows may be present — they are other jams, and the test says nothing about them) and finally
ending jam "agentcheck" (port 7788, session <first 8>)
daemon told everyone the jam is ending
tmux session agentcheck is gone
with exit code 0. Verified 2026-08-29 on node 24.15 / tmux 3.7c / claude 2.1.251, macOS.
If step 2 hangs, claude is probably showing the trust dialog for --cwd: attach with
tmux -L claude-jam-7788 attach -t agentcheck:claude, answer it, Ctrl-b d to detach, and
finish with claude-jam end agentcheck.
If anything fails, clean up only what this test made, by exact name:
claude-jam end agentcheck || tmux -L claude-jam-7788 kill-session -t =agentcheck
rm -rf "${TMPDIR:-/tmp}/claude-jam-7788"Never tmux kill-server, and never a pattern.
Hosting a Jam · Joining a Jam · Remote Access · Security Model · Troubleshooting