Follow Discord
Sweep 23 Oct 2026 · 21:48Z Build v2.1.310 529 read Stable v2.1.308 Latest v2.1.310 Next v2.1.310 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Test self-hosted environments end to end changedself-hosted-environments-testing

Nearest release: v2.1.296, published 6 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 9 Oct 2026 23:38 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 23 Oct 2026 19:07 UTC.

Upstream edited
Recorded here
Lines+13added
Lines−13removed
From line 4 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits12to this page, all time

The whole hunk

from line 4, old and new numbered
/
lines
from line 4
44 
55> [!NOTE]
66>
7> Self-hosted environments are in public beta on Team and Enterprise plans; [Availability and limitations](/docs/en/self-hosted-environments#availability-and-limitations) covers the enablement path. This page is the CI test recipe; see the [quickstart](/docs/en/self-hosted-environments-quickstart.md) for setup and [Deploy to production](/docs/en/self-hosted-environments-deploy.md) for the fleet recipes.
7> Self-hosted environments are in public beta on Team and Enterprise plans; [Availability and limitations](https://code.claude.com/docs/en/self-hosted-environments#availability-and-limitations) covers the enablement path. This page is the CI test recipe; see the [quickstart](https://code.claude.com/docs/en/self-hosted-environments-quickstart.md) for setup and [Deploy to production](https://code.claude.com/docs/en/self-hosted-environments-deploy.md) for the fleet recipes.
88 
9In a [self-hosted environment](/docs/en/self-hosted-environments), Claude Code [cloud sessions](/docs/en/claude-code-on-the-web.md) run on a runner image you build and maintain. Before rolling a new image to your production environment, drive a full session against a test environment from a script: create a session, read Claude's reply, send a follow-up, and read that reply too. This is the shape of a CI smoke test that verifies your runner image, git access, and any custom tools before you promote a change.
9In a [self-hosted environment](https://code.claude.com/docs/en/self-hosted-environments), Claude Code [cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md) run on a runner image you build and maintain. Before rolling a new image to your production environment, drive a full session against a test environment from a script: create a session, read Claude's reply, send a follow-up, and read that reply too. This is the shape of a CI smoke test that verifies your runner image, git access, and any custom tools before you promote a change.
1010 
11This recipe assumes you've already [set up an environment and a runner](/docs/en/self-hosted-environments-quickstart.md#set-up-an-environment-and-runner), and that your CI job starts the runner process on the same host as the test script, the natural setup for testing a new runner image. A Stop hook you install on the runner writes each turn's final reply to a local file, and the script reads it from there, so the only calls to the Anthropic API are the two dispatches themselves. If your test runners are on separate infrastructure, see [Remote test runners](#remote-test-runners).
11This recipe assumes you've already [set up an environment and a runner](https://code.claude.com/docs/en/self-hosted-environments-quickstart.md#set-up-an-environment-and-runner), and that your CI job starts the runner process on the same host as the test script, the natural setup for testing a new runner image. A Stop hook you install on the runner writes each turn's final reply to a local file, and the script reads it from there, so the only calls to the Anthropic API are the two dispatches themselves. If your test runners are on separate infrastructure, see [Remote test runners](#remote-test-runners).
1212 
1313## Install the capture hook on your test runner
1414 
15The read-back works through a Claude Code [Stop hook](/docs/en/hooks.md#stop): when Claude finishes a turn, the hook receives the final assistant message as `last_assistant_message` in its stdin JSON and appends it to `$E2E_REPLY_DIR/<session_id>.txt`. Install it the same way as the [commit-nudge Stop hook](/docs/en/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work), on the runner host's `~/.claude/`, which the runner seeds into every session.
15The read-back works through a Claude Code [Stop hook](https://code.claude.com/docs/en/hooks.md#stop): when Claude finishes a turn, the hook receives the final assistant message as `last_assistant_message` in its stdin JSON and appends it to `$E2E_REPLY_DIR/<session_id>.txt`. Install it the same way as the [commit-nudge Stop hook](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work), on the runner host's `~/.claude/`, which the runner seeds into every session.
1616 
1717### Save the hook files
1818 
from line 80
8080 * **Session creation failed**: the line `{"ok":false,"error":"..."}`, and the command exits with status 1
8181 * **Some earlier errors**, such as cloud sessions being unavailable for your organization or a missing prompt: the error on stderr with no JSON line, and the command exits with status 1
82822. Waits for the reply to appear in `$E2E_REPLY_DIR/<session_id>.txt`, written by the Stop hook on the runner once the turn completes.
833. Sends a follow-up with `claude -p "<message>" --cloud <session_id> --output-format json` (see [Send a follow-up message to a running session](/docs/en/claude-code-on-the-web.md#send-follow-ups-from-the-cli)), which posts a user event to the existing session and exits.
833. Sends a follow-up with `claude -p "<message>" --cloud <session_id> --output-format json` (see [Send a follow-up message to a running session](https://code.claude.com/docs/en/claude-code-on-the-web.md#send-follow-ups-from-the-cli)), which posts a user event to the existing session and exits.
84844. Waits for the follow-up's reply the same way as step 2.
8585 
8686### `--environment` dispatch behavior
from line 87
8787 
8888Claude Code creates the session, prints the session ID and a link to it, and exits.
8989 
90The flag takes precedence over the [`remote.defaultEnvironmentId`](/docs/en/settings-reference#remote-defaultenvironmentid) setting. It doesn't support `--output-format stream-json`, and can't be combined with flags that resume, attach to, or preconfigure a session, such as `--resume`, `--continue`, `--teleport`, `--session-id`, or `--init-only`. `--cloud` is rejected with a session ID or URL, and in non-interactive runs when it carries a description. A bare `--cloud` is treated as absent. From a terminal, you can pass the task as the `--cloud` description instead of a positional prompt.
90The flag takes precedence over the [`remote.defaultEnvironmentId`](https://code.claude.com/docs/en/settings-reference#remote-defaultenvironmentid) setting. It doesn't support `--output-format stream-json`, and can't be combined with flags that resume, attach to, or preconfigure a session, such as `--resume`, `--continue`, `--teleport`, `--session-id`, or `--init-only`. `--cloud` is rejected with a session ID or URL, and in non-interactive runs when it carries a description. A bare `--cloud` is treated as absent. From a terminal, you can pass the task as the `--cloud` description instead of a positional prompt.
9191 
9292## Example script
9393 
from line 194
194194 
195195### Long-lived CI host
196196 
197Run `claude auth login` once interactively on the machine that executes the script, using a dedicated user account for automation. Claude Code stores the token in the OS keychain on macOS, or in `~/.claude/.credentials.json` on Linux and Windows. On a macOS host whose Keychain can't be written, as is typical in an SSH session where the login Keychain stays locked, Claude Code stores the token in `~/.claude/.credentials.json` there too. See [Credential management](/docs/en/authentication.md#credential-management).
197Run `claude auth login` once interactively on the machine that executes the script, using a dedicated user account for automation. Claude Code stores the token in the OS keychain on macOS, or in `~/.claude/.credentials.json` on Linux and Windows. On a macOS host whose Keychain can't be written, as is typical in an SSH session where the login Keychain stays locked, Claude Code stores the token in `~/.claude/.credentials.json` there too. See [Credential management](https://code.claude.com/docs/en/authentication.md#credential-management).
198198 
199199The CLI refreshes the short-lived access token automatically on each invocation, but the underlying refresh-token grant is capped at 30 days from the initial login, so re-run `claude auth login` interactively on that host every 30 days.
200200 
201201### Ephemeral CI runners
202202 
203There is no long-lived CI token for this today. The scope that grants cloud-session control, `user:sessions:claude_code`, is capped server-side at 30 days, so `claude setup-token`, which mints a one-year inference-only token, doesn't cover it. The [environment secret](/docs/en/self-hosted-environments-quickstart.md#set-up-an-environment-and-runner) isn't accepted either, since it only authorizes a runner to register with the environment, not to create sessions.
203There is no long-lived CI token for this today. The scope that grants cloud-session control, `user:sessions:claude_code`, is capped server-side at 30 days, so `claude setup-token`, which mints a one-year inference-only token, doesn't cover it. The [environment secret](https://code.claude.com/docs/en/self-hosted-environments-quickstart.md#set-up-an-environment-and-runner) isn't accepted either, since it only authorizes a runner to register with the environment, not to create sessions.
204204 
205To provision a stored login onto an ephemeral runner, set [`CLAUDE_CODE_OAUTH_REFRESH_TOKEN` and `CLAUDE_CODE_OAUTH_SCOPES`](/docs/en/env-vars#variables) so `claude auth login` exchanges the token without a browser; the same 30-day cap applies to the refresh grant. Contact your Anthropic account team if you need a machine-identity path that isn't bound to a human account.
205To provision a stored login onto an ephemeral runner, set [`CLAUDE_CODE_OAUTH_REFRESH_TOKEN` and `CLAUDE_CODE_OAUTH_SCOPES`](https://code.claude.com/docs/en/env-vars#variables) so `claude auth login` exchanges the token without a browser; the same 30-day cap applies to the refresh grant. Contact your Anthropic account team if you need a machine-identity path that isn't bound to a human account.
206206 
207207## Create a dedicated test environment
208208 
from line 231
231231ENVIRONMENT_SECRET=$(jq -er .pool_secret <<<"$create")
232232```
233233 
234Until an [Owner turns on **Allow self-hosted environments**](/docs/en/self-hosted-environments#availability-and-limitations) for the organization, the call fails with a `403` `permission_error` reading `self-hosted runners are disabled by your organization's policy`.
234Until an [Owner turns on **Allow self-hosted environments**](https://code.claude.com/docs/en/self-hosted-environments#availability-and-limitations) for the organization, the call fails with a `403` `permission_error` reading `self-hosted runners are disabled by your organization's policy`.
235235 
236236Start a runner on this host with `SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET=$ENVIRONMENT_SECRET`, plus the capture hook and `E2E_REPLY_DIR` per [Install the capture hook](#install-the-capture-hook-on-your-test-runner), then run the test script.
237237 
Feedback