Cordium documentation · Latest
Claude Code
This example runs Claude Code unattended inside ephemeral Cordium Workspaces to fix bugs and implement small features in a Go repository. Each run clones the repository, lets Claude Code make and test the change, pushes a branch and opens a draft pull request, and then stops and discards the Workspace.
What makes this setup different from running an agent in a typical container or CI runner is that the Workspace holds no credential at all: not the Anthropic API key, not a GitHub token, nothing. Claude Code talks to the Anthropic API, git pushes the branch and curl opens the pull request through Octelium Services that inject the credentials on a per-request basis and only for the Workspaces of a specific Template and repository (read more about secretless access here). A prompt-injected or misbehaving agent therefore has nothing to exfiltrate, and every request it makes is authorized and logged by Octelium.
The Octelium Services
First, a Cluster administrator stores the credentials as Octelium Secrets. The GitHub token is a fine-grained personal access token or a GitHub App installation token that has the Contents and Pull requests read and write permissions on the target repository only:
Then, the administrator creates the following Services:
anthropic: anLLMService that exposes the Anthropic API (read more about LLM Services here).github.payments: anHTTPService in front ofhttps://github.comthat injects the token as HTTP basic authentication, which is whatgituses over HTTPS.github-api.payments: anHTTPService in front of the GitHub REST API that injects the token as a bearer token.
Both GitHub Services are restricted to the Workspaces of the claude-agent Template of the payments Space, and to the acme-corp/payments-api repository:
You can apply them via octeliumctl apply (read more here). The Users who run the agent must also be allowed to access the anthropic Service by a Policy (read more about scoping LLM access here).
The inline Policies above make the GitHub Services usable only from the agent's Workspaces and only for one repository. Even the Users who own those Workspaces cannot use the token from their laptops, and the agent cannot push to any other repository or call any other GitHub API.
The Template
Next, a Space admin creates the following Template in the payments Space. Its ON_CREATE tasks install Claude Code and a few tools, and its agent task runs the whole workflow once the Workspace is connected to the Cluster:
Here are a few notes about this Template:
The
agenttask is aPOST_STARTtask since it needs the Workspace's connection to the Cluster, which is established at the beginning of thePOST_STARTphase. It waits forgithub.paymentsto become reachable before cloning (read more here).The task variables are passed to the script as environment variables rather than substituted into the script itself, which keeps an arbitrary
TASKtext from being interpreted by the shell.Claude Code's standard input is redirected from
/dev/null, sinceclaude -potherwise waits for piped input when its standard input is not a terminal.--dangerously-skip-permissionslets Claude Code run commands and edit files without prompting. This is what the Workspace is for: an isolated, disposable sandbox in which the agent runs as an unprivileged user and holds no credentials. You can further restrict its network egress (read more here).autoStopstops the Workspace as soon as theagenttask completes, and theON_FAILURE_ABORTpolicy makes the run fail if any step fails. All the foreground tasks of a run must complete within 60 minutes (read more here).
Create the Template and pre-build it so that every run starts with the tools already installed (read more about pre-builds here):
Pre-builds run the foreground POST_START tasks too, but without any connection to the Cluster. This is why the agent task exits immediately when TASK is empty, which is its default value.
Running the Agent
Every run is a new ephemeral Workspace of the Template with its own TASK:
You can follow the run live from the web portal or via cordium logs:
You can also trigger runs programmatically, for example from an issue tracker webhook or a scheduler, via the SDKs. Here is an example via the Python SDK that starts a run and waits until it stops:
Interactive Sessions
The same Template also works for interactive sessions. Create a persistent Workspace without a TASK, open a terminal from the web portal, or via cordium ssh or VS Code, and run claude as usual. Since ANTHROPIC_BASE_URL points to the anthropic Service, Claude Code uses the Cluster's Anthropic API key without any login:
If your team uses Claude subscriptions instead of API keys, store a token generated via claude setup-token as a UserSecret and inject it via your UserConfig as the CLAUDE_CODE_OAUTH_TOKEN environment variable (read more here). In that case, remove ANTHROPIC_BASE_URL and ANTHROPIC_API_KEY from the Template. Note, however, that the token is then readable inside the Workspace.