Inside an agent run#
This page lists what an agent run finds when it starts: its files, its
environment, how it reaches its model and tools, and, for the Assistant,
the tools the model is given. It is also the contract an agent in an image
of your own (kind: image) follows.
Files#
| Path | What |
|---|---|
/agent/input |
The input, as given to the run. |
/agent/instructions.md |
The version's instructions, followed by a note on how tools are reached. |
/agent/mcp.json |
The MCP tools as a client configuration (Claude Code's --mcp-config shape): {"mcpServers": {"<tool>": {"type": "http", "url", "headers"}}}, with @TOOL_GATEWAY@ and @TOOL_TOKEN@ in place of the gateway's address and the token. |
/agent/tools.json |
The Assistant only: the HTTP and web tools with their address, description and how to call them. |
/agent/codex.toml, /agent/opencode.json |
Codex's and OpenCode's configuration. |
/var/run/astraeus/identity/token.jwt |
The run's workload token, renewed by the machine (about hourly). |
/sandbox, /tmp |
Writable. The Assistant's file tools work in /sandbox. |
/flow |
In a flow's step or an evaluation: the execution's drive, read-write. |
/.astraeus/bin/anemoi-assistant |
The Assistant (kind astralyx), mounted read-only by the machine. |
The start script of the built-in kinds copies the configuration files into
/tmp/agent with the gateway's address and the token filled in.
Environment#
| Variable | Value |
|---|---|
ASTRAEUS_AGENT |
The agent's name. |
ASTRAEUS_AGENT_VERSION |
The version. |
ASTRAEUS_AGENT_INPUT |
/agent/input. |
ASTRAEUS_AGENT_MCP_CONFIG |
/agent/mcp.json. |
ASTRAEUS_AGENT_WORK |
The Assistant: /tmp/agent. |
ASTRAEUS_MODEL |
The model's name: the provider's, or the deployment's served name. |
ASTRAEUS_MODEL_API |
anthropic (the Messages API) or openai (chat completions). |
ASTRAEUS_TOOL_GATEWAY |
The gateway's base URL (http://<address>:8801). |
ASTRAEUS_IDENTITY_DIR |
Where the token is. |
ASTRAEUS_OUTPUTS |
In a flow's step: the file to write key=value outputs to. |
Your secrets |
The credentials' keys you exposed, under the names you chose. |
The start script also sets ASTRAEUS_TOOL_TOKEN (the token),
ASTRAEUS_MODEL_URL and ASTRAEUS_MODEL_KEY (for the Assistant), and
ANTHROPIC_BASE_URL/ANTHROPIC_API_KEY or OPENAI_BASE_URL/OPENAI_API_KEY
pointing at the gateway with the token as the key, for the coding agents.
An image of your own sets these itself from the variables above.
The gateway's routes#
Every request carries the token: Authorization: Bearer <token> (or
x-api-key: <token>, where Anthropic's clients put their key).
| Route | What |
|---|---|
ANY $ASTRAEUS_TOOL_GATEWAY/model/… |
The model: …/model/v1/messages (Anthropic) or …/model/v1/chat/completions (OpenAI), and the API's other model calls. The key is added, tokens counted, budgets enforced, routes applied. |
POST $ASTRAEUS_TOOL_GATEWAY/mcp/<tool> |
An MCP tool (streamable HTTP). GET and DELETE pass through to the server's stream and session end. |
ANY $ASTRAEUS_TOOL_GATEWAY/http/<tool>/<path> |
An HTTP tool: <its URL>/<path>. Paths with . or .. segments or an encoded slash are refused. |
ANY $ASTRAEUS_TOOL_GATEWAY/web/<tool>?url=<page> |
A web tool: any public http(s):// page. Redirects are returned, not followed. |
GET $ASTRAEUS_TOOL_GATEWAY/healthz |
Up. |
Bodies up to 16 MiB are forwarded; web answers are cut at 5 MiB (the
header x-astraeus-truncated says so). A refused call answers a JSON
{"error": {"code", "message"}}:
| Status | Code | Why |
|---|---|---|
| 403 | TOOL_CALL_DENIED |
The policy denies it; the message is the reason and the rule. |
| 403 | WEB_ADDRESS_REFUSED |
The page's address is not public. |
| 403 | APPROVAL_DENIED, APPROVAL_PENDING, APPROVAL_EXPIRED, APPROVAL_UNAVAILABLE |
A call held for approval was denied, is still waiting, lapsed, or could not be asked. |
| 403 | MODEL_PATH_DENIED |
Not a model call of the API. |
| 402 | BUDGET_REACHED |
The run's or a period's budget is reached. |
| 401 | UNAUTHENTICATED |
No token, or not a valid one. |
| 403 | NO_TOOLS, WRONG_ADDRESS |
The run has no tools here, or the token came from another address. |
| 404 | NO_SUCH_SERVER, NO_MODEL |
No tool of that name and kind; no model through the gateway. |
| 400 | BAD_PATH, BAD_URL |
A path or page URL that is refused. |
| 413 | TOO_LARGE |
The request is over 16 MiB. |
| 502 | UPSTREAM_UNREACHABLE, UPSTREAM_ANSWER |
The tool or model could not be reached, or answered unreadably. |
| 503 | CREDENTIAL_NOT_READY, KEYS_UNAVAILABLE |
The credential is not on the machine yet; the machine cannot check tokens yet. |
The Assistant#
The Assistant (kind: astralyx) runs one loop: the instructions as the
system prompt, the input as the user's message; it calls each tool the
model asks for and hands the result back; when the model answers without
asking for a tool, that answer is printed — it is the run's output. Each
step is logged to standard error ([step n] tool server__name → ok|denied|error (ms)).
| Tool given to the model | What |
|---|---|
<tool>__<name> |
Each MCP tool the policy lets it list. |
http_request |
The HTTP tools: server, method, path, query, headers, body. |
web_fetch |
The web tools: url, method (GET by default), headers, body; pages come back as text. |
read_file, write_file, list_files |
Files under /sandbox only: .. and links out of it are refused; reads at most 8 MiB, listings at most 1 000 entries. |
| Limit | Value |
|---|---|
| Steps | 40 model turns |
| Output tokens per model call | 8 192 |
| A tool result handed to the model | 64 KiB |
| Tries per model call | 3, with back-off |
A refused call is the tool's answer to the model, which may do something
else; it never fails the run. Exit codes: 0 answered, 1 could not run
(no input, the model unreachable after its tries, or the model refusing),
2 the steps ran out first.
Claude Code, Codex, OpenCode#
| Kind | Started as |
|---|---|
claude-code |
claude -p "<input>" --output-format text --mcp-config /tmp/agent/mcp.json --strict-mcp-config --permission-mode bypassPermissions --append-system-prompt "<instructions>" (with --model for a provider's model) |
codex |
codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox "<instructions>\n\n<input>" |
opencode |
opencode run "<input>" with OPENCODE_CONFIG=/tmp/agent/opencode.json |
Their own permission prompts are off: the sandbox and the tool gateway are what limit them.
An image of your own#
Your program, started as the image's entrypoint (or command and
args):
- reads its task from
/agent/inputand its instructions from/agent/instructions.md; - calls its model at
$ASTRAEUS_TOOL_GATEWAY/model—…/model/v1/messagesor…/model/v1/chat/completionsper$ASTRAEUS_MODEL_API, model$ASTRAEUS_MODEL— with the token from$ASTRAEUS_IDENTITY_DIR/token.jwtas its key (most SDKs readANTHROPIC_BASE_URLorOPENAI_BASE_URL: set them to the gateway's…/modelor…/model/v1); - calls its tools as listed in
/agent/mcp.jsonand at$ASTRAEUS_TOOL_GATEWAY/http/<tool>/…, with the same token, reading the token again when it is renewed; - prints its answer on standard output, and exits.
The image runs under the sandbox policy like any kind: keep /tmp
writable, and name in it the hosts your program needs besides the gateway.