Skip to content

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):

  1. reads its task from /agent/input and its instructions from /agent/instructions.md;
  2. calls its model at $ASTRAEUS_TOOL_GATEWAY/model — …/model/v1/messages or …/model/v1/chat/completions per $ASTRAEUS_MODEL_API, model $ASTRAEUS_MODEL — with the token from $ASTRAEUS_IDENTITY_DIR/token.jwt as its key (most SDKs read ANTHROPIC_BASE_URL or OPENAI_BASE_URL: set them to the gateway's …/model or …/model/v1);
  3. calls its tools as listed in /agent/mcp.json and at $ASTRAEUS_TOOL_GATEWAY/http/<tool>/…, with the same token, reading the token again when it is renewed;
  4. 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.