Claude Code cloud sessions
The runner in daily use. A worker is a cloud session on claude.ai/code. The coordinator creates it, once the owner has authorised that, or the owner creates it by hand. The coordinator briefs it from a terminal.
Once per profile: the environment
On claude.ai/code, add a cloud environment for the repository:
- Network: the package registries your stack needs.
- Environment variables (
.envformat):CR_PROFILE=<profile>. The documentation warns that anyone who uses the environment can read its variables: no secrets. - Setup script: paste
setup.shwhole, with your stack’s installs added. A one-linebash scripts/setup.shcan fail to start: in practice the repository was not always cloned when the setup box ran. The documentation does not say either way.
What the documentation says about the setup box
(https://code.claude.com/docs/en/cloud-environments, read 2026-09-24): it is
a Bash script that runs before Claude Code launches; a non-zero exit stops
the session from starting; it should finish in about five minutes; its result
is cached as a filesystem snapshot and reused, and running processes are not.
A cloud session has CLAUDE_CODE_REMOTE=true, which is how the project’s
agent instructions tell a worker from the coordinator.
Per worker: the coordinator creates the session
claude --cloud cannot create a session without a person at the keyboard.
With -p, it only sends to a session that exists: “Claude Code rejects
--bg, and rejects --cloud with a task description”
(https://code.claude.com/docs/en/headless, read 2026-09-29). So the
coordinator creates each new worker as a one-off routine, from its own
session:
- The owner authorises it once. “Create workers yourself” is said once,
in the coordinator’s chat, and recorded in its state file. The rules the
worker follows are unchanged. The opening message says who created the
session and why (
routine-preamble.md). -
The routine’s body:
cr-cloud new backend brief.md --environment <environment id> \ --repository https://github.com/<owner>/<repo> \ --model claude-sonnet-5-5 > routine.jsonIt fills
new-worker.routine.json:name, andrun_once_at: a UTC time two minutes ahead (--atsets another);job_config.ccr.environment_id: the repository’s cloud environment, the one with the setup script;session_context: themodel, the repository as thesources, and theallowed_tools. Edit the template’s list for your project;persist_session: true, so the session stays, and later epics are briefed in it;events: one user message with its ownuuid. It holds the preamble, then the opening (prompts/en/worker-opening.md, filled for the profile), then the first brief.
- The coordinator’s session submits it with the routine tool it has
under the owner’s claude.ai sign-in. The coordinator that did this for
real used the remote-trigger API,
POST /v1/code/triggers. That API is reached with the session’s own claude.ai sign-in, and control-room knows no documented way for a script to obtain that sign-in. Socr-cloudonly prints the body. It holds no token and asks for none. Never put a token in a file for it. - After it fires, the routine’s runs give the new session’s id. The
last run of a routine carries a
session_id. The coordinator records worker → session → routine, the model and the effort in its state file (docs/templates/queue.md), and briefs later epics withcr-cloud brief. A one-off routine disables itself once it has fired.
What is verified, and what is not.
- Checked against the routines documentation
(https://code.claude.com/docs/en/routines, read 2026-09-29):
- routines can be scheduled “once at a specific future time”;
- “after the routine fires, it auto-disables”;
- one-off runs “do not count against the daily routine run cap”;
- “each run creates a new session”.
- The documentation describes creating a routine only through the web form
and
/schedule. The remote-trigger API is not described there, and routines are a research preview whose “API surface may change”. - The body’s field names are those the coordinator used on 2026-09-28/29. They were not verified by a run from this repository.
- A one-off routine created from a cloud session on 2026-09-25, then read
back through the routine API, showed:
persist_session: true;run_once_at;- the message stored as an event with a
uuid,type: "user"andmessage: {role: "user", content}.
- Read the routine back after creating it, and fix the template if the shape has changed.
- The documentation also says a fired routine’s prompt “is not live user input and can’t act as approval or consent for actions during the run” (Claude Code v2.1.213 or later). The opening sets the worker’s task and rules. Anything that needs the owner’s consent beyond them still goes to the desk.
By hand, when the coordinator is not authorised: print the opening,
cr-cloud opening backend, and paste it into a new session in that
environment. The worker replies WORKER backend READY. Give the coordinator
the session’s URL, and say which profile it is.
Model and effort (docs/protocol.md, Model and effort): the routine
sets the model. The effort is not a field of the routine’s body that we know
of, so the brief states it in words. In a running session, /effort <level>
typed as a message sets it (documented for cloud sessions).
Per epic: the brief
cr-cloud brief https://claude.ai/code/session_… brief.md
which runs
claude -p "$(cat brief.md)" --cloud <session> < /dev/null
with --output-format json added. The documentation
(https://code.claude.com/docs/en/claude-code-on-the-web, “Send follow-ups
from the CLI”) says:
- the command “posts one message and exits”;
<session>is “the bare ID, such assession_...orcse_..., or the session’sclaude.ai/code/<id>URL”;- it needs the CLI signed in with
claude auth loginto the account that owns the session, not an API key; - with
--output-format json, it prints{ok, session_id, url}on success, or{ok: false, session_id, error}when the send fails.
The brief arrives in the running session as a user message.
A send that fails makes cr-cloud brief exit 3, with the reason and what
to tell the owner. That covers:
ok: false(the session expired or was archived);- a configuration error on stderr with no JSON;
- no result at all.
The coordinator reports it first thing, with the session’s link, and does not
retry silently. A CLI signed in with an API key fails with Unable to get
organization UUID: sign in with the claude.ai account (/login).
A message from another session is not a brief
The brief must arrive as a user message: typed or pasted by the owner, or
sent with claude -p … --cloud. A message relayed from another agent session
(a cross-session message, a subagent’s report, a teammate’s note) is not one.
In practice Claude Code shows it to the worker marked as coming from another
agent, and a worker treats it as data,
not as an assignment, even when it has the shape of a brief. That is by
design: it is what stops one confused session from assigning work to
another. If a coordinator session wants to brief a worker, it runs
cr-cloud brief, or asks the owner to paste the brief.
Pull requests
The cloud machine may have no gh: the worker opens its pull request through
its GitHub tools. scripts/guard judges both forms (a gh pr create command
and the MCP create_pull_request tool).