scaffold-jam (jam)
scaffold-jam is the Scaffold command-line client. It logs you into your Scaffold account,
registers Scaffold with your local coding agent (Claude Code today), and connects a real local
git worktree to a Scaffold multiplayer room so a local agent — running under your own
credentials — can work in that room while everyone else watches and chats from the web app.
Everything that touches your filesystem, your git history, or your agent's credentials runs on
your own machine; the hosted backend only relays chat and agent activity.
Install
Requires Python 3.11+.
uv tool install scaffold-jam # puts the `jam` command on your PATH
# or: pipx install scaffold-jam
# or, without installing: uvx --from scaffold-jam jam --help
Upgrade with uv tool upgrade scaffold-jam (or pipx upgrade scaffold-jam).
All local state lives under ~/.scaffold-ai/ (owner-only: the directory is 700, its files
600) — nothing is written inside the project you're working in besides the git worktree
itself. jam only ever talks to the hosted Scaffold service.
Quick start
jam login # email/password; sets your buddy nickname
jam setup claude # registers the Scaffold MCP server + steering hook with Claude Code
cd your-project && jam room create "<name>" --topic "<what to build>" # new room + agent on this repo
jam room connect <room-url> # or connect this repo to a room you own or have joined
From there, either drive the room from your terminal (jam room …) or just talk to Claude Code
about it — once jam setup claude has run, Claude Code can create, attach to, and connect rooms
on your behalf via the scaffold-multiplayer MCP server.
Command reference
| Command | What it does |
|---|---|
jam login [--nickname NAME] |
Log in with your Scaffold (Supabase) email/password and store a refresh token. Sets your buddy nickname (default: the part of your email before @). |
jam logout |
Remove locally stored credentials. |
jam connect [--custom-command CMD] |
Run the optional always-on connector as your logged-in account (run jam login first). |
jam mcp |
Run the Scaffold MCP server on stdio (for a coding agent to launch, not for humans to run directly). |
jam setup claude [--scope user|project] |
Register the scaffold-multiplayer MCP server and the Stop steering hook with Claude Code. |
jam room create NAME [--topic TEXT] [--invite BUDDY …] [--no-connect] [--folder .] [--provider …] [--model] [--effort] |
Create a room you own, connect a folder to it and start a local agent; --topic posts the first message for the agent, --no-connect only creates the room. |
jam room connect ROOM [--folder .] [--provider claude|gemini|codex|"<cmd>"] [--model] [--effort] [--description TEXT] [--skill "NAME[:TAG,TAG]"]... |
Connect a folder to a room (yours or one you've joined), attach your own agent (--name sets its display name the first time) and start it locally. --description and --skill (repeatable) set your agent's Agent Card, which the room's facilitator sees when deciding who should take a task. |
jam room pr ROOM [--branch NAME] [--base origin/main] [--title TEXT] [--no-push] |
Turn a room agent's work into one clean commit on a fresh branch off the base, without the room's plan/ files or agent config (.claude/, .mcp.json), and push it; prints the "open a pull request" link. Stops (creating nothing) if the changes conflict with the base. |
jam room fork ROOM [--at MESSAGE_ID] [--connect …] |
Fork someone else's (or your own) room into a new room you own, optionally connecting a folder to it immediately. |
jam room detach ROOM |
Stop your local agent for a room and remove it from the room. |
jam room facilitator ROOM [AGENT] |
Show or change which agent is the room's facilitator (room owner only to change). |
jam room disconnect ROOM |
Stop a local agent worker jam started for a room. |
jam room open ROOM |
Print (and open) a room's URL. |
jam buddy code |
Generate a single-use buddy invite code + link. |
jam buddy add CODE_OR_LINK |
Redeem a buddy code or link. |
jam buddy list [--ids] |
List your buddies, with online status. |
jam buddy remove NAME |
Remove a buddy. |
jam buddy invite NAME... ROOM_URL |
Invite one or more buddies (by nickname) into a room. |
jam inbox [--all] [--read] |
Show notifications (invites, forks, new buddies). |
jam status |
Show backend/account/connector status. |
jam doctor [--quick] |
Run diagnostics on this machine's Scaffold setup (--quick skips probing installed coding agents). |
jam --version |
Print the installed version. |
Claude Code integration
jam setup claude [--scope user|project] does two things:
- Registers the
scaffold-multiplayerMCP server with theclaudeCLI (claude mcp add …). Ifclaudeisn't on yourPATH, it prints the JSON snippet to add to your MCP config by hand instead. - Registers a Stop hook (
<python> -m collab_ai _hook steer) in Claude Code'ssettings.json, replacing any older hook entry that pointed at the legacyscaffold_room_steer.pyscript.
Once registered, the MCP server exposes these tools to Claude Code:
create_multiplayer_room(topic, room_name, context, model, effort, mode, provider="claude", invite)— create a new room from the current project and start a local agent worker in it.attach_multiplayer_room(room_name, topic)— attach the current Claude Code session to a room it (or a previous session in this worktree) already created.connect_multiplayer_room(room, provider="claude", model, effort, fork_first=False)— connect the current project folder to an existing room and start a local agent in it.
The MCP tools only accept the built-in providers (claude, gemini, codex). A custom ACP
agent command can only be given by you, on the command line (jam room connect --provider "<cmd>", jam connect --custom-command) or in ~/.scaffold-ai/config.json.
invite_buddies(room, buddies)— invite buddies (by nickname) into a room.
Example phrases that route to these tools:
- "Create a Scaffold room for this so my team can watch."
- "Connect to scaffold room
<url>." - "Connect to scaffold room
<url>, fork it first." (for a room you don't own) - "Invite alice and bob to this room."
Connecting to a room / forking
jam room connect ROOM works for rooms you own and rooms you've joined, inside a git repository with at
least one commit. It attaches your own agent to the room (named with --name, default "'s agent"; remove it later with jam room detach ROOM). It creates a worktree at <repo>/worktrees/<room_id> on a new branch
room/<id8>, writes the room's plan files and plan/transcript.md into it, commits, and starts
a detached local agent worker (logged at ~/.scaffold-ai/logs/worker-<room>.log) that reads the
conversation when you mention it in the room (@<agent-slug>).
To work in your own copy of someone else's room instead, fork it:
jam room fork <room-url> --connect
which forks the room into a new one you own (an ordinary room with a parent link, not a
server-side git operation) and immediately connects a folder to it. The same flow is available
from inside Claude Code by saying "connect to scaffold room <url>, fork it first" once
jam setup claude has run.
Bring your agent's memory
Claude Code keeps auto-memory per project, and git worktrees of one repository share that memory.
By default the room's Claude agent brings this repo's own Claude memory (--memory repo), and it
can read and write it (use --memory-readonly for a copy it can only read). To opt out, use
--memory off: the room then gets an isolated memory, kept only for that room
(~/.scaffold-ai/rooms/<room>/memory).
Choose a different memory with --memory on jam room connect, jam room create and
jam room fork --connect:
--memory repo(default): the memory Claude Code keeps for the repository of the folder you connect (--folder). Non-Claude providers get no memory by default.--memory off: isolated memory for this room, sharing nothing from your Claude memory.--memory profile:<name>: a named memory kept in~/.scaffold-ai/agents/<name>/memory, shared by every room that uses that profile.--memory project:<path-or-slug>: another project's memory. Command line only.--memory path:<dir>: any folder you choose as memory. Command line only.
The web app can only choose off, repo or profile:<name>. project: and path: are for the
command line.
Other flags:
--memory-readonly: the agent works on a copy of the memory, so the original is never altered.--local-config: copiesCLAUDE.local.mdand.claude/settings.local.jsonfrom the folder into the room's worktree (they are kept out of git).
jam agent memory list shows the memory sources you can bring: project memories that contain at
least one file, and profiles.
Preview before you bring anything: jam room connect <room> --preview (or jam agent preview, which
needs no room) prints the memory that would be shared, the CLAUDE.md files, Claude Code skills,
plugins and agent card the agent would take with it, and connects nothing. Nothing is sent
anywhere. When --memory is given explicitly with a choice other than off, or --local-config is
given, on a terminal (and without --yes), connect, create and fork print the same preview and ask
Bring this to the room? [y/N] first; answering anything but y or yes cancels before anything is
attached or created. --yes skips the prompt. Without --memory, connect, create and fork print one
line saying the repo's memory is being brought (--memory off opts out, --preview shows what it
brings) and do not ask.
Saved agent cards: jam agent cards lists the cards you've used (id, name, description, skills, and
how many rooms use them). Pass --card <id|name> to jam room connect, jam room create or
jam room fork --connect to reuse one. Its name, description and skills are used unless you also
give --name, --description or --skill, and those flags win per field. A card never brings
memory: --memory is always your choice.
Your CLAUDE.md, settings, skills and plugins from your Claude config already come with the agent,
and CLAUDE_CONFIG_DIR is honoured when it is set. To leave that global setup behind, pass
--no-global-config: the agent then loads only the repo's own CLAUDE.md and .claude/ plus the memory
you chose. jam agent preview --no-global-config marks what stays behind.
The agent's default name is "'s Claude" when it uses the Claude provider. Override it
with --name, or with agent_profile.name in ~/.scaffold-ai/config.json:
{"agent_profile": {"name": "Ada's Claude"}}
Privacy: your memory choice and its paths stay on your computer and are never sent to the backend.
The room only sees a "brings memory" badge. Tool activity is shown only as locations inside the
worktree, and the agent's thought chunks never leave your computer. The agent's reply text is only
guarded by its prompt, though, so anything the agent chooses to say in the room is visible to
everyone. If you don't want the agent altering or surfacing memory, use --memory-readonly or a
dedicated profile.
Build an agent from a room, and teach it more
jam agent create <room-url> [--name "DB incident responder"] [--public] has your own Claude read a
room -- its conversation, plan files and shared notes -- and draft an agent card: a description,
skills (A2A AgentSkill style: name, description, tags, example requests) and a markdown playbook
of the lessons, procedures and pitfalls the room learned. You see the whole draft; type feedback to
have Claude revise it, as often as you like, and nothing is saved until you accept (y). q quits.
--feedback "..." applies feedback up front, --yes saves the first draft, --dry-run only shows it.
jam agent learn <card> <room-url> teaches an existing card from another room the same way: Claude
returns the complete updated card (new lessons merged in, outdated ones corrected), and you review it
before it replaces the old one. The card keeps its id, so --card <id> keeps working.
The room's text is untrusted (anyone in it wrote it), so the distiller runs with no tools and no Claude Code settings in an empty folder: it can only read and answer.
jam room connect <room> --card <id> then brings the card's playbook: the agent is given it as expert
guidance that never overrides the room's rules. Edit any card -- description, skills, playbook, MCP
servers -- on the web under Agent Cards; share it publicly so others can "Use this card".
Context packs: carry your agent's context anywhere
A context pack is your agent's context, versioned and shareable, not tied to any one card:
- memory: your global
~/.claude/CLAUDE.mdand a project's auto memory - instructions: the repo's
CLAUDE.local.md - skills and subagents, packaged as one Claude Code plugin
- settings (sanitized) and the marketplace plugins you have enabled
jam pack create "My agent" --sections memory,instructions,skills,agents # review, then upload
jam room connect <room-url> --pack "My agent" # bring it into a room (its memory, unless --memory)
jam pack use "My agent" # or into any Claude Code session
jam pack sync "My agent" # pull + merge + push what the agent learned
jam pack share "My agent" <user-id> --write # read-only without --write; publish to make it public
jam pack delete "My agent" # delete a pack you own (asks first; --yes to skip)
Nothing leaves your computer until you review the capture. Only text files go in; binaries, .env
files, files over 512 KB and anything that looks like a secret stay behind, as do Claude's own synced
skills. Settings lose credential helpers, machine paths and secret-looking env vars; hooks that point
into your home folder (or at Scaffold's own hook) are left out. Absolute paths never go in a pack.
Packs reach the agent through Claude Code's own extension points -- a local plugin, the memory
directory, appended instructions and session settings -- so nothing is written into your repo or
your ~/.claude. Someone else's hooks only run after you approve that exact set of hooks.
jam pack sync does a 3-way merge against the version you last synced. Changes on one side merge on
their own; MEMORY.md indexes merge line by line; when the same file changed on both sides, your own
Claude proposes a merge (it has no tools) and you accept it, keep yours or take theirs. A read-only
pack keeps your local changes on your computer. Agent cards can bring packs too (edit the card on
the web).
MCP servers
Register MCP servers on the web (Library > MCPs), then give one to a room, to one agent in it, or attach it to an agent card. Every agent's operator approves a grant before their agent uses it (granting your own server to your own agent counts as approval), and approved servers are handed to the agent the next time it connects.
- Local (stdio) servers run on each operator's own computer with their own values for the env
vars the server needs -- from the environment or
~/.scaffold-ai/mcp_env.json({"DATABASE_URL": "postgres://..."}, keep it private). A server missing a value is skipped; the room sees its name and the missing variable name, never a value. - Remote (http/sse) servers are used only if the agent supports that transport. Their owner may share one auth token: it's stored encrypted and sent only to approved agents' computers -- anyone you grant it to can use it, so share a scoped one.
What the room can see and do
The agent runs on your computer, under your accounts, in the room's worktree. Everyone in the room (anyone with the link, including guests) can message it.
- Agent actions. By default the agent approves its own actions (running commands, using the web, touching files) so it can work unattended — which means anyone in the room can have it run commands on your computer. As the room owner you can turn off Auto-approve agent actions in the room header: the agent then still reads and edits files inside the room's worktree on its own, but asks you (an Approve/Deny card in the chat, visible only to you with the details) before running a command, using the web, or touching anything outside the worktree. Unanswered requests are denied after 10 minutes.
- What's shown. The room sees what kind of action the agent is taking ("Running a command", "Editing src/app.py") but never the command lines, file contents or command output, and never the names of files outside the worktree. The agent's reasoning isn't shown either.
- What the server can't do. Which agent runs, and in which folder, is decided on your computer: the server can't change the agent command, point it at another folder, or switch it to a permission-bypassing mode.
Buddies & inbox
Buddies are mutual "friends" you can invite into rooms — they grant no extra permissions (any room is open to anyone with the link); they just make inviting people fast and let you see who's online.
jam buddy codeprints a single-use code and a/buddy/<code>link, good for 7 days.- The other person runs
jam buddy add <code-or-link>(or opens the link in the web app) to become mutual buddies. jam buddy listshows a green dot for buddies seen online within the last 2 minutes.jam buddy invite NAME... ROOM_URLand inviting from the web app both create a notification (a bell in the web app, and an entry injam inbox) for the invited buddy. Forking someone's room also notifies them.- Buddy accounts must be real (non-anonymous) Scaffold accounts.
Configuration
jam always talks to the hosted Scaffold service (https://scaffold-ai-relay.fly.dev, links
to https://frontend-scaffold2.vercel.app). There is deliberately no flag, environment variable
or config setting that points it — and your login — anywhere else.
Local files, all under ~/.scaffold-ai/:
credentials.json— your Supabase refresh/access tokens.connector_state.json— state for the always-onjam connectconnector. The connector only ever acts on this account's own agents.config.json— optional;{"custom_agent_command": "<acp agent command>"}offers your own ACP agent as the "Custom" provider.local_workers.json— bookkeeping for local agent workersjam room connectstarted.compat_check.json— cached result of the daily CLI/server compatibility check.logs/— per-room worker logs (worker-<room>.log).
Privacy
jam sends no telemetry. Every HTTP request it makes carries a User-Agent: scaffold-jam/<version>
header and an X-Collab-AI-Version: <version> header, both used only for the compatibility
check below — nothing else is collected or reported.
Once a day (cached in ~/.scaffold-ai/compat_check.json), jam checks
GET /api/cli/compat and, if a newer version is available,
suggests uv tool upgrade scaffold-jam; if your version is below the backend's stated minimum, it
refuses to run the command and tells you to upgrade. Set JAM_NO_UPDATE_CHECK=1 to skip this
check entirely (no network access, no cache read/write).
Metadata
Release files for scaffold-jam 0.2.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| scaffold_jam-0.2.4.tar.gz | 105.8 kB | With provenance | Details for scaffold_jam-0.2.4.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| scaffold_jam-0.2.4-py3-none-any.whl | Python 3 | none | any | Details for scaffold_jam-0.2.4-py3-none-any.whl |
Total release size: 219.6 kB
Release files / scaffold_jam-0.2.4.tar.gz
| Download URL | scaffold_jam-0.2.4.tar.gz |
|---|---|
| Size | 105.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a2b2a2ca7ece929063a5062a07f100e8a023cf68dc8890b0c55857d9632b138d
|
|
BLAKE2b-256 checksum How to use checksums |
ccec4dd27c3a9a5106aef15e5130ddf92721e8b6d7c9834d11ecaac84a4d653d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / scaffold_jam-0.2.4-py3-none-any.whl
| Download URL | scaffold_jam-0.2.4-py3-none-any.whl |
|---|---|
| Size | 113.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
02fe689e437bce79101bbdd7c5a3f2975a9eb67ae18aab3910cfc6e6c09d70b4
|
|
BLAKE2b-256 checksum How to use checksums |
912ca941113f330f267cab47a4b50c8b2edea4ac2b61dc932073ba2d4ffaf9e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logSecurity for scaffold-jam 0.2.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for scaffold_jam-0.2.4.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.