Agent config
Every field, default, and constraint in agent config YAML files.
The field-by-field reference for Ellipsis agent YAML files. The canonical path is agents/*.yaml; .agents/, ellipsis/, and .ellipsis/ are also accepted, including any subdirectory under them. The machine-readable source of truth is GET /agents/schema.
Every config file must declare a top-level ellipsis: mapping. Its presence is what identifies the file as an Ellipsis agent config: a .yaml/.yml file in a config directory without an ellipsis: block is treated as unrelated YAML and ignored.
For how agents deploy and sync, see Agents as code; for trigger behavior, the schedule, react, and mention guides; for spend, Budgets. This page documents the fields.
Top-level fields
The shape of an agent file. Every field has a default; a useful agent sets a `trigger` and a `claude.system` prompt (mention agents need neither).
| Field | Type | Default | Description |
|---|---|---|---|
ellipsis | object | required | Ellipsis namespace: schema version, name/description, organizational metadata, and the enabled/interactive/ide flags. Its presence marks the file as an agent config. |
claude | object | {} | Claude runtime config: the system prompt, model, reasoning effort, turn cap, and an optional Claude Code settings file. Optional for mention-only agents. |
trigger | trigger object | null | null | How the agent runs automatically. One trigger of type cron, react, or mention. Omit for a manual-only agent. |
sandbox | object | {} | The sandbox the agent runs in: which repositories are checked out, which stored environment variables are injected, exposed ports, compute sizing, image customization, lifecycle hooks, and the scope of its GitHub token. |
skills | list of skill objects | [] | Claude Code skills installed for the session beyond what the sandbox repositories already provide. Skills checked into a cloned repository's .claude/skills/ load automatically and need no entry here. |
structured_output | object | null | null | JSON Schema contract for machine-readable run output. |
budget | object | all null | Per-session and trailing spend caps for this agent, in US dollars. |
ellipsis
The Ellipsis namespace: schema version, identity, organizational metadata, and the enabled/interactive/ide flags. Its presence is what marks a YAML file as an agent config; a config-path file without it is ignored.
| Field | Type | Default | Description |
|---|---|---|---|
version | string | v1 | Config schema version. Bumped only on a breaking shape change; an unsupported value fails validation. v1 is the only supported version today. |
name | string | null | null | Display name. Dashboard-created files slug this into the file path. |
description | string | null | null | Short summary shown in product surfaces. |
enabled | boolean | true | When false, cron, react, and mention starts are skipped. Manual runs still work. |
interactive | boolean | true | When true, a human can `agent session connect` to a live session and inject messages into it over the CLI relay, and an on-demand session stays warm as a durable conversation after its first turn. Set false for fire-and-forget automations. React and cron sessions are always single-turn regardless. |
ide | boolean | true | When true, a human can open an editor or a port URL into the running sandbox. |
metadata | object | {} | Freeform labels and annotations. Does not affect how the agent runs; excluded from the config content identity. |
ellipsis.metadata
Freeform organization, modeled on Kubernetes labels and annotations. It has no effect on how the agent runs and is excluded from the config content identity.
| Field | Type | Default | Description |
|---|---|---|---|
labels | list of strings | [] | Flat string tags for grouping and filtering. |
annotations | object | {} | Arbitrary key-value pairs. |
claude
| Field | Type | Default | Description |
|---|---|---|---|
system | string | {file} | list of both | "" | The agent's instructions: inline text, a {file: ...} reference to a repository file, or an ordered list interleaving both, joined into one prompt at run start and appended to Claude Code's default system prompt (never replacing it). Required (non-empty) for cron, react, and manual agents; ignored for mention agents, whose reply is built from the conversation. |
system[].file | string | required | Path of a UTF-8 text file in the repository the config lives in, relative to the repository root (no leading /, no ..). Read at run start at the run's commit; 64 KiB max per file and for the composed prompt. |
model | string | claude-opus-4-8 | Model passed to Claude Code. Omit unless Ellipsis gave your account explicit guidance. |
effort | enum | null | null | Reasoning effort passed to Claude Code. Higher effort trades latency and cost for depth. Omit to use the model default. |
fallback_model | string | null | null | Model Claude Code falls back to when the primary model is overloaded. Omit for no fallback. |
max_turns | integer | null | null | Hard cap on the number of agent turns. Must be a positive integer. The session budget bounds the run independently; use this to stop a loop by turn count. |
settings | object | null | null | Point the session at a Claude Code settings.json in a repository. It is applied below Ellipsis-managed settings, so it customizes behavior (permissions, commit co-author trailer, status line) but cannot weaken a managed setting; hooks stay disabled. Environment keys that would redirect the model off the Ellipsis proxy (ANTHROPIC_*, ELLIPSIS_*, provider routing, apiKeyHelper) are rejected; use sandbox.variables for your own environment variables. |
settings.path | string | required | Path of the settings.json, relative to the repository root (no leading /, no ..). Read at session start; must be a UTF-8 JSON object, 64 KiB max. |
settings.repository | object | null | null | Where path resolves. Omitted: the repository this config lives in, at the session's checkout when that repository is in the sandbox, otherwise at the head of the config's branch. Set: the named repository, which may be any repository of your installation or a public repository from another owner (external private repositories are rejected). |
settings.repository.name | string | required | The repository name, without the owner. |
settings.repository.owner | string | null | the config account | GitHub owner (organization or user login). Defaults to the account the config belongs to. |
settings.repository.ref | string | null | default-branch head | Branch, tag, or commit SHA to fetch the settings file at. When the repository is cloned into the session's sandbox the checkout SHA wins; otherwise an omitted ref resolves the default-branch head at session start. |
Allowed effort values:
| Value | Levels |
|---|---|
low | Fastest, cheapest. |
medium | Moderate reasoning. |
high | More reasoning for harder tasks. |
xhigh | Very high reasoning. |
max | Maximum reasoning; slowest. |
settings is applied below Ellipsis-managed settings and cannot weaken them. An unresolvable settings file (missing, not a JSON object, over 64 KiB, or setting a protected environment key) fails the session before the agent starts.
System prompts from repository files
system takes three shapes: inline text, a single file reference, or an ordered list interleaving both. A file reference points at a UTF-8 text file in the repository the config lives in, by a path relative to the repository root:
claude:
system:
file: .agents/prompts/release-notes.mdA list composes the prompt from its parts in order. Each part is trimmed, and parts are joined with a blank line:
ellipsis:
version: v1
name: Linear issue implementer
description: Implements Linear issues as pull requests
claude:
system:
- file: .agents/prompts/engineering-standards.md
- |
Implement the Linear issue this session was started for. Open a
pull request and link the issue in its description.
trigger:
type: react
linear_issue:
on: [opened]
sandbox:
repositories:
- name: splitshift-api
- name: splitshift-webReferenced files are read at session start, at the commit the session has the config's repository checked out at, so prompt and code always move together. Every agent that references .agents/prompts/engineering-standards.md picks up an edit to it on its next session: no config change, no sync. When the config's repository is not in the session's sandbox, files resolve at the head of the branch the config syncs from.
Constraints:
- A path must be relative to the repository root and normalized: no leading
/, no\, no..escaping the root. - A referenced file must exist at the resolved commit, be valid UTF-8, be non-empty, and decode to at most 64 KiB. The composed prompt is capped at 64 KiB total.
- A file reference must not point at another agent config file.
Sync and pull request validation check every referenced file at the pushed commit. A file that breaks a constraint at session start (deleted, emptied, grown past the limit) fails the session: status is error, with the reason in the session's status_reason.
Settings file
claude.settings points the session at a Claude Code settings.json in a repository, so a team can reuse the settings file it runs locally instead of re-encoding it. Ellipsis passes it to Claude Code as --settings, which applies below Ellipsis-managed settings: it can set permissions, the commit co-author trailer, a status line, and other Claude Code options, but cannot override a managed setting, and hooks stay disabled.
claude:
system: Review the push and draft release notes.
settings:
path: .claude/settings.jsonOmit repository to resolve the path in the repository the config lives in, at the session's checkout when that repository is in the sandbox. Set it to pull a shared file from another repository of your installation or a public repository:
claude:
system: Review the push and draft release notes.
settings:
path: claude/settings.json
repository:
name: platform-configConstraints:
- The file is read at session start, must be a UTF-8 JSON object, and decodes to at most 64 KiB.
- Environment keys that would redirect the model off the Ellipsis proxy (
ANTHROPIC_*,ELLIPSIS_*, provider-routing variables,apiKeyHelper) are rejected. Usesandbox.variablesfor your own environment variables. - An unresolvable settings file (missing, not a JSON object, over the limit, or setting a protected key) fails the session before the agent starts:
statusiserror, with the reason instatus_reason.
triggers
An agent can declare zero or more triggers; each independently decides when the agent runs. A config with no triggers still runs on demand from the CLI, API, or dashboard.
Cron trigger
Run the agent on a schedule. See Spawn an agent session on a cron schedule.
Run the agent on a schedule.
| Field | Type | Default | Description |
|---|---|---|---|
type | "cron" | required | Selects the cron trigger shape. |
schedule | string | required | Five-field cron, or an EventBridge cron(...), rate(...), or at(...) expression. Five-field cron is converted to EventBridge format. |
EventBridge Scheduler cannot restrict both day-of-month and day-of-week in one expression.
React trigger
Run the agent when a pull request, issue, push, Linear, Sentry, or Slack event happens. For the pull request surfaces, see Spawn an agent session in response to Pull Request lifecycle events; the fields below cover every surface.
Run the agent in response to a repository, issue, Sentry, or Slack event. A react trigger sets exactly one surface block (pull_request, push, code_review, issue, linear_issue, sentry, or slack_channel); each block carries its own action list and filters.
| Field | Type | Default | Description |
|---|---|---|---|
type | "react" | required | Selects the react trigger shape. |
pull_request | object | null | null | React to pull-request lifecycle actions. Filters: repositories, base, head, draft, labels, paths, for. |
pull_request.on | list of pull-request actions | required | Pull-request actions that can start the agent. |
push | object | null | null | React to branch pushes. Action-less. Filters: repositories, branch, paths, for. |
code_review | object | null | null | Review the unreviewed delta on every head advance of a matched PR, never re-commenting reviewed lines. Action-less; reuses the pull_request filters minus on: repositories, base, head, draft, labels, paths, for. |
issue | object | null | null | React to GitHub issue actions. Filters: repositories, labels, for. |
issue.on | list of issue actions | required | GitHub issue actions that can start the agent. |
linear_issue | object | null | null | React to Linear issue actions. Filter: for. |
linear_issue.on | list of Linear issue actions | [opened] | Linear issue actions that can start the agent. |
sentry | object | null | null | React to Sentry alerts. Filter: projects (Sentry project slugs; empty matches every project in the connected Sentry org). |
sentry.on | list of Sentry actions | required | Sentry alert kinds that can start the agent. |
slack_channel | object | null | null | React when a new public channel is created in your Slack workspace. Takes no fields. |
repositories | list of strings | [] | Repository name filter (pull_request, push, code_review, issue). Empty matches every repository of the installation. |
base | list of strings | [] | Base-branch filter (pull_request, code_review). Exact names or prefixes ending in *. Empty matches any base. |
head | list of strings | [] | Head-branch filter (pull_request, code_review). Exact names or prefixes ending in *. Empty matches any head. |
branch | list of strings | [] | Branch filter for push. Exact names or prefixes ending in *. Empty matches every branch. |
draft | boolean | null | null | Draft filter (pull_request, code_review). true matches only draft PRs, false only non-draft; null matches both. |
labels | list of strings | [] | Label filter (pull_request, code_review, issue). Empty matches regardless of labels. |
paths | list of strings | [] | Changed-path glob filter (pull_request, push, code_review). Empty matches regardless of paths. |
projects | list of strings | [] | Sentry project slugs to react to (sentry). Empty matches every project in the connected Sentry org. |
for | audience object | {users: true} | Who may trigger the surface, classified on the stable entity author (the pusher for push). An author matches if in the include set (users/bots) and in no exclude set. |
for.users | list of strings | boolean | true | Human authors. true is all humans, a list is specific logins, [] or false is none. |
for.bots | list of strings | boolean | false | Bot authors. true is all bots, a list is specific logins, [] or false is none. |
for.exclude_users | list of strings | [] | Human logins to exclude, applied after the include set. |
for.exclude_bots | list of strings | [] | Bot logins to exclude, applied after the include set. |
Allowed pull_request.on values:
| Value | Fires for |
|---|---|
opened | PR opened or marked ready. |
pushed | New commits pushed to the PR. |
merged | PR merged. |
closed | PR closed without merge. |
review_submitted | A review was submitted on the PR. |
commented | A comment was added to the PR. |
Allowed issue.on values:
| Value | Fires for |
|---|---|
opened | Issue opened. |
closed | Issue closed. |
commented | Comment added to the issue. |
Allowed linear_issue.on values:
| Value | Fires for |
|---|---|
opened | Linear issue opened. |
Allowed sentry.on values:
| Value | Fires for |
|---|---|
issue_alert | A Sentry issue alert rule fired (via the Ellipsis alert rule action). |
metric_alert | A Sentry metric alert entered critical status. |
Exactly one surface block may be set on a react trigger.
Mention trigger
Route @ellipsis mentions to this agent instead of the built-in responder. See Spawn an agent session by mentioning @ellipsis.
Route @ellipsis mentions to this agent instead of the built-in responder.
| Field | Type | Default | Description |
|---|---|---|---|
type | "mention" | required | Selects the mention trigger shape. |
platforms | list of platform strings | [] | Surfaces this agent answers @ellipsis on. Empty means all of them. |
Allowed platforms values:
| Value | Covers |
|---|---|
github | @ellipsis in GitHub PR and issue comments and reviews. |
slack | @ellipsis messages and app mentions in Slack. |
linear | @ellipsis in Linear issue comments. |
One agent answers per platform. If two configs claim the same platform the oldest one wins; the rest are ignored. With no claimant, the built-in Ellipsis responder answers.
sandbox
The sandbox the agent runs in. See The sandbox for the environment and Inject credentials with sandbox variables for variables.
The sandbox the agent runs in. Each repository entry takes name (required), owner (defaults to the config account), and ref (defaults to the default-branch head).
| Field | Type | Default | Description |
|---|---|---|---|
repositories | list of repository objects | [] | Repositories checked out in the sandbox. Each takes name (required), owner, and ref. |
repositories[].name | string | required | The repository name, without the owner. |
repositories[].owner | string | the config account | GitHub owner (organization or user login). Defaults to the account the config belongs to. Public repositories from other owners work; private repositories outside the owning account are rejected. |
repositories[].ref | string | default-branch head | Pins the checkout: fetched and checked out verbatim (git fetch origin <ref> && git checkout <ref>), so use a commit SHA for a reproducible checkout. When omitted, the default branch head at session start. |
variables | list of variable objects | [] | Environment variables injected into the sandbox (an allowlist — only the variables named here reach this agent). Each entry takes a name and an optional value. |
ports | list of integers | [3000, 5173, 8000, 8080] | TCP ports exposed from the sandbox for IDE and port-URL access. |
variables[].name | string | required | The environment variable name. Must be a valid shell name (letters, digits, underscores; not starting with a digit). |
variables[].value | string | null | null | A literal value injected as-is — use for non-secret config like a log level or API base URL. Omit it to resolve the value by name from your sandbox-variables store (dashboard or PUT /sandboxes/variables) at run time, keeping secrets out of YAML. |
image | object | {} | Customizes the container image. Ellipsis owns the base image (FROM, user, entrypoint, and preinstalled tooling); you contribute appended layers (dockerfile_append) and a build-time script (setup). |
image.dockerfile_append | string | null | null | RUN instructions appended onto the base image, e.g. installing a CLI. Runs when the image is assembled, before any repository exists. Only RUN is supported — FROM, USER, WORKDIR, ENTRYPOINT, and COPY are not. Changing it rebuilds and re-caches the image. |
image.setup | string | null | null | A shell script run once at image-build time, after your repositories are checked out and before the snapshot that becomes the cached image. Use it for dependency installs (npm install, poetry install): later runs start with the results already on disk, and a new commit re-runs it on top of the previous build (installing only the delta). Runs as the sandbox user with the sandbox variables available. Environment variables are not captured by the snapshot, but files are, so it must never write secrets to disk. A non-zero exit fails the run; capped at 10 minutes. |
hooks | object | {} | Shell scripts run on every run, before the agent starts, each as the sandbox user with the sandbox variables available. Their output is never cached; a dependency install whose result should be reused across runs belongs in image.setup. A hook that exits non-zero fails the run. |
hooks.post_start | string | null | null | Runs after the container starts, before any repository is cloned. Use for repo-independent setup such as authenticating a CLI (e.g. doppler setup). Must not depend on repository contents. |
hooks.post_clone | string | null | null | Runs after all repositories are cloned and checked out, before the agent starts. Use for per-run, repo-dependent setup such as code generation or anything that touches run-scoped credentials. For dependency installs, prefer image.setup so the result is cached. |
compute | object | {} | Sandbox compute sizing. Every field is optional; an omitted field uses the platform default. A value outside the allowed range fails config validation, it is never clamped. Compute is billed on the requested allocation over the sandbox lifetime, so a bigger or longer sandbox costs proportionally more. |
compute.cpu | number | null | 1 | vCPU cores, 0.125 to 16. Fractional values are allowed (e.g. 0.5). |
compute.memory | string | object | null | 4GB | Memory allocation, 512MB to 64GB. Either a size string ("16GB", "512MB"; units are binary, so 1GB is 1024MB) or an object with gb / mb keys. Omit to use the default. |
compute.timeout | string | object | null | 1h | Maximum session wall clock, 60s to 1h. Either a duration string ("15m", "1h", "90s", or combined like "1h30m") or an object with hours / minutes / seconds keys. One hour is both the default and the maximum (a sandbox and its GitHub token live at most one hour), so this only shortens a session. A session that reaches the timeout has its sandbox killed and fails. |
github_token | object | {} | Scopes the GitHub installation token injected into the sandbox as GH_TOKEN (the credential git and gh authenticate with). By default the token carries the full permissions of your installation, scoped to the repositories in the sandbox. Narrowing is enforced by GitHub itself: the token is minted with the reduced scope, so nothing running in the sandbox can exceed it. |
github_token.permissions | 'read_only' | map | null | null | What the token may do. read_only grants read access to contents, issues, metadata, and pull_requests. A map requests an explicit level per GitHub App permission scope (for example contents: read, pull_requests: write) and can only reduce what the installation granted: requesting an ungranted permission fails the session with exit status missing_token_permissions. Omit for full installation permissions. |
github_token.repositories | list of strings | null | null | Repository names the token may touch, narrowing the default (the sandbox repositories owned by your account). Names must belong to the installation; a name it lacks access to fails the session with exit status missing_repo_access. Public repositories from other owners are never in the token scope. |
Ellipsis clones repositories available to the account installation, and can clone public repositories from other owners. It rejects private repositories outside the owning account. A variable with no value and no stored value fails the run, so define it before referencing it. A lifecycle hook that exits non-zero fails the run.
skills
Claude Code skills installed for the session, beyond the .claude/skills/ directories the sandbox repositories already provide. See Share skills across your team's agents and repositories.
Claude Code skills installed for the session. Skills checked into a sandbox repository's .claude/skills/ load automatically at that session's checkout; a skills entry brings in skills those clones don't provide: another repository of your installation, a public repository, or a session with no repositories at all. Each entry names a repository directory containing a SKILL.md; it is fetched at session start and installed at the sandbox's personal skill level (~/.claude/skills/<directory name>/), where it overrides a same-named repository skill.
| Field | Type | Default | Description |
|---|---|---|---|
path | string | required | Directory containing the SKILL.md, relative to the repository root (no leading /, no ..; not the root itself). The last path segment becomes the installed skill name, so it must be unique across the skills list. |
repository | object | null | null | Where path resolves. Omitted: the repository this config lives in, at the session's checkout when that repository is in the sandbox, otherwise at the head of the config's branch. Set: the named repository, which may be any repository of your installation or a public repository from another owner (external private repositories are rejected). |
repository.name | string | required | The repository name, without the owner. |
repository.owner | string | null | the config account | GitHub owner (organization or user login). Defaults to the account the config belongs to. |
repository.ref | string | null | default-branch head | Branch, tag, or commit SHA to fetch the skill at. When the repository is cloned into the session's sandbox the checkout SHA wins, so skill and code move together; otherwise an omitted ref resolves the default-branch head at session start. |
At most 10 skills per config; each skill at most 50 files and 512 KiB total, 64 KiB per file, UTF-8 text only. A skill that cannot be resolved (missing SKILL.md, unreachable repository, over a limit) fails the session before the agent starts.
structured_output
| Field | Type | Default | Description |
|---|---|---|---|
type | "json_schema" | "json_schema" | Structured output type. |
json_schema | object | required | JSON Schema the agent output must satisfy. |
When present, Ellipsis passes this schema to the Claude Code runtime for the run's output.
limits
Per-session and trailing spend limits, in US dollars. See Budgets for defaults and ceilings.
Validation and sync behavior
| Case | Result |
|---|---|
File has no top-level ellipsis: block | Not an agent config: ignored entirely, even at a config path. |
ellipsis.version is unsupported | Validation fails. Only v1 exists. |
| YAML is empty | Rejected: an empty config has no claude.system. |
claude.system is empty on a non-mention agent | Validation fails. Inline text or a file reference satisfies the requirement. |
A system file path is absolute, unnormalized, or escapes the repository root | Validation fails. |
A system file is missing, empty, or over 64 KiB at the validated commit | Validation fails at sync and on config pull requests. At session start it fails the session instead. |
system is an empty list | Validation fails; a list needs at least one text part or file reference. |
| Cron expression is invalid | Validation fails before anything is stored or scheduled. |
branches is set on a non-push react event | Validation fails. |
A sandbox.compute value is out of range or unparseable | Validation fails; values are never clamped. Bounds: cpu 0.125 to 16 vCPU, memory 512MB to 64GB, timeout 60s to 1h. memory is a size string (8GB, 512MB; binary, 1GB = 1024MB) or an object with gb/mb keys; timeout is a duration string (30m, 1h, 90s) or an object with hours/minutes/seconds keys. |
sandbox.github_token.permissions names an unknown scope or an invalid level | Validation fails. The value is read_only or a map of GitHub App permission scopes to read/write. |
sandbox.github_token.permissions requests a permission the installation was not granted | The session fails at sandbox creation with exit status missing_token_permissions. |
sandbox.github_token.repositories is empty, has duplicates, or names a repository the installation cannot access | An empty list or duplicates fail validation. An inaccessible name fails the session with exit status missing_repo_access. |
A skills path is absolute, unnormalized, escapes the repository root, or is the root itself | Validation fails. |
A skills path points at an agent config file | Validation fails; a skill is a directory containing a SKILL.md. |
More than 10 skills entries, or two entries whose paths end in the same directory name | Validation fails; the last path segment is the installed skill name. |
A skills entry without repository: has no SKILL.md, or unparseable frontmatter, at the validated commit | Validation fails at sync and on config pull requests. Entries with repository: are checked at session start. |
A skill cannot be resolved at session start (missing SKILL.md, unreachable repository, over a size limit, not UTF-8) | The session fails before the agent starts: status is error, with the reason in status_reason. |
| New file is invalid | The sync reports the error and does not create an agent. |
| Existing file becomes invalid | The sync records the error and keeps the last good config. |
| File is removed | The agent is soft-deleted and its schedules removed. |