Configuration YAML
Every field in an Ellipsis agent YAML file, with types, defaults, and constraints. Includes the smallest deployable config and where invalid configs fail.
An agent is one YAML file in your repository. This page is the full schema reference: every field, its type, its default, and its constraints.
Config files live at agents/*.yaml by convention; .agents/, ellipsis/, and .ellipsis/ also work, including any subdirectory under them, with either a .yml or .yaml extension. The top-level ellipsis: block is what marks a file as an Ellipsis config: a YAML file in a config directory without one is treated as unrelated YAML and ignored. How files deploy, preview, and revive: Lifecycle.
Minimal config
Only the ellipsis: block is structurally required. Every other field has a default, so a file containing nothing else is a valid agent that runs on demand from the CLI, API, or dashboard. A useful agent adds instructions, a trigger, and repositories:
ellipsis:
version: v1
name: Unfilled shift digest
claude:
system: |
List next week's shifts in splitshift-api that are still
unassigned and open a GitHub issue titled "Unfilled shifts
next week" with the list, grouped by restaurant.
trigger:
type: cron
schedule: "0 9 * * 1"
sandbox:
repositories:
- name: splitshift-apiellipsismarks the file as an agent config and names it.version: v1is the only supported schema version.claude.systemis the agent's instructions. Omit it and the agent runs on Claude Code's own default prompt, likeclaudewith no arguments.triggerdecides when the agent runs on its own; Mondays at 09:00 UTC here. Omit it for a manual-only agent. All trigger shapes: Triggers.sandbox.repositoriesnames the repositories cloned into the session's sandbox.
Merged to the default branch, this file is a live agent. Every Monday it wakes in a sandbox with splitshift-api checked out and opens the issue.
All fields
Types and defaults below come from the live validator. The schema is strict: an unknown or misplaced key (a top-level name: that belongs under ellipsis:, say) fails validation instead of being silently dropped.
Top-level shape:
| Field | Type | Default | Description |
|---|---|---|---|
ellipsis | object | required | Schema version, name and 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. |
codex | object | null | null | Run the agent on OpenAI's Codex CLI instead of Claude Code. Declaring the block is what selects the harness. |
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: repositories, environment variables, ports, compute sizing, image customization, lifecycle hooks, and the GitHub token scope. |
skills | list of skill objects | [] | Claude Code skills installed for the session beyond what the sandbox repositories already provide. |
structured_output | object | null | null | JSON Schema contract for machine-readable session output. |
budget | object | all null | Per-session and trailing spend caps for this agent, in US dollars. |
llm | object | {} | Where this agent's completions go. Omit to use Ellipsis's own LLM proxy. |
mcp_servers | list of names | [] | Built-in integrations this agent opts into by name (linear, slack). |
ellipsis
The Ellipsis namespace: schema version, identity, organizational metadata, and the enabled/interactive/ide flags.
| Field | Type | Default | Description |
|---|---|---|---|
version | string | v1 | Config schema version. v1 is the only supported version; anything else fails validation. |
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 send it messages, 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 a browser IDE or a port URL into the running sandbox. See Sandboxes. |
metadata | object | {} | Freeform labels and annotations. No effect on how the agent runs. |
An agent config declares no kind. Setting ellipsis.kind: code_review makes the file a review pipeline with a different schema; writing kind: agent explicitly fails validation, so omit the key.
ellipsis.metadata:
| Field | Type | Default | Description |
|---|---|---|---|
labels | list of strings | [] | Flat string tags for grouping and filtering. |
annotations | map of string to string | {} | 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 session start and appended to Claude Code's default system prompt. Optional: an agent with no instructions runs on Claude Code's own default prompt. Mention agents ignore it entirely; their 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 session start at the session's commit. 64 KiB max per file and for the composed prompt. |
model | string | claude-opus-5 | 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 session 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, applied below Ellipsis-managed settings. It customizes behavior (permissions, commit co-author trailer, status line) but cannot weaken a managed setting, and hooks stay disabled. |
settings.path | string | required | Path of the settings.json, relative to the repository root (no leading /, no ..). Must be a UTF-8 JSON object, 64 KiB max, read at session start. |
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: 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). |
settings.repository.ref | string | null | default-branch head | Branch, tag, or commit SHA to fetch the file at. When the repository is cloned into the session's sandbox the checkout SHA wins. |
Allowed effort values, in increasing depth: low, medium, high, xhigh, max.
A settings file must not set environment keys that would redirect the model off the Ellipsis proxy (ANTHROPIC_*, ELLIPSIS_*, CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, apiKeyHelper); use sandbox.variables for your own environment variables. A settings file that is missing, not a JSON object, over 64 KiB, or sets a protected key fails the session before the agent starts.
A system list composes the prompt from its parts in order, joined with blank lines:
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.Referenced 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. A file reference must not point at another agent config file.
codex
Run the agent on OpenAI's Codex CLI instead of Claude Code. Declaring the block at all is what selects the harness, so omit it unless you want Codex.
| Field | Type | Default | Description |
|---|---|---|---|
system | string | {file} | list of both | "" | Same shapes and constraints as claude.system. |
model | string | bedrock-gpt-5.6-terra | A model that supports the OpenAI Responses API. A model that does not (any claude-* id) fails validation. |
Codex has no equivalent of claude.effort, fallback_model, max_turns, or settings, and skills and mcp_servers are not wired through for this harness; setting one fails loudly rather than being ignored. The budget still bounds the session.
trigger
An agent declares at most one trigger, which decides when it runs on its own. A config with no trigger still runs on demand from the CLI, API, or dashboard. Behavior per surface: Triggers.
Cron trigger
| Field | Type | Default | Description |
|---|---|---|---|
type | "cron" | required | Selects the cron trigger shape. |
schedule | string | required | Five-field cron ("0 9 * * 1"), or an EventBridge cron(...), rate(...), or at(...) expression. Schedules fire in UTC. |
A five-field expression cannot restrict both day-of-month and day-of-week; use * for one of them.
React trigger
Run the agent in response to a repository, issue, Sentry, or Slack event. A react trigger sets exactly one surface block; each block carries its own on: 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 actions. Filters: repositories, base, head, draft, labels, paths, for. |
push | object | null | null | React to branch pushes. No on: list; every push to a matching branch fires. Filters: repositories, branch, paths, for. |
issue | object | null | null | React to GitHub issue actions. Filters: repositories, labels, for. |
linear_issue | object | null | null | React to Linear issue actions. Filter: for. |
sentry | object | null | null | React to Sentry alerts. Filter: projects. |
slack_channel | object | null | null | React when a new public channel is created in your Slack workspace. No on: list, no filters. |
Actions per surface:
| Field | Required | Allowed values |
|---|---|---|
pull_request.on | yes | opened (PR opened or marked ready), pushed (every head advance, including the open), merged, closed (closed without merge), review_submitted, commented |
issue.on | yes | opened, closed, commented |
linear_issue.on | no, default [opened] | opened |
sentry.on | yes | issue_alert (a Sentry issue alert rule fired), metric_alert (a metric alert entered critical status) |
Filter fields, each on the surfaces named above:
| Field | Type | Default | Description |
|---|---|---|---|
repositories | filter object | list of strings | all repositories | Repository watch filter. A bare list is shorthand for include. Independent of sandbox.repositories; the triggering repository is cloned regardless. |
repositories.include | list of strings | [] | Repository names to watch. Empty matches every repository of the installation, including ones added later. |
repositories.exclude | list of strings | [] | Repository names to exclude, applied after include. |
base | list of strings | [] | Base-branch filter (pull_request). Exact names, prefixes ending in * (release/*), or default for the repository's default branch. Empty matches any base. |
head | list of strings | [] | Head-branch filter (pull_request). Same shapes as base. Empty matches any head. |
branch | list of strings | [] | Branch filter (push). Same shapes as base. Empty matches every branch. |
draft | boolean | null | null | Draft filter (pull_request). true matches only draft PRs, false only non-draft, null both. |
labels | list of strings | [] | Label filter (pull_request, issue). Matches when any listed label is present; empty matches regardless. |
paths | list of strings | [] | Changed-path glob filter (pull_request, push). Include-only; negated ! patterns fail validation. Empty matches regardless. |
projects | list of strings | [] | Sentry project slugs (sentry). Empty matches every project in the connected Sentry org. |
for | audience object | users yes, bots no | Who may trigger the surface, classified on the entity author (the pusher for push). |
for.users | filter | list | boolean | true | Human authors, include-minus-exclude. true is all humans, a list is specific logins, false or [] is none. |
for.users.include | list of strings | boolean | true | Human authors to include. |
for.users.exclude | list of strings | [] | Human logins to exclude, applied after include. |
for.bots | filter | list | boolean | false | Bot authors, same shapes as for.users. |
Mention trigger
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: github (PR and issue comments and reviews), slack (messages and app mentions), linear (issue comments). Empty means all of them. |
One agent answers per platform. If two configs claim the same platform, the oldest one wins and the rest are ignored. With no claimant, the built-in Ellipsis responder answers.
sandbox
The machine the agent runs in. The environment model, caching, and testing workflow: Sandboxes.
| Field | Type | Default | Description |
|---|---|---|---|
repositories | list of repository objects | [] | Repositories cloned into the sandbox. |
repositories[].name | string | required | The repository name, without the owner. |
repositories[].owner | string | null | the config account | GitHub owner. Public repositories from other owners work; private repositories outside the owning account are rejected. |
repositories[].ref | string | null | default-branch head | Pins the checkout, fetched and checked out verbatim; use a commit SHA for a reproducible checkout. |
variables | list of variable objects | [] | Environment variables injected into the sandbox. An allowlist: only the variables named here reach this agent. Duplicate names fail validation. |
variables[].name | string | required | The 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. Omit it to resolve the value by name from your stored sandbox variables at session start, keeping secrets out of YAML. A variable with no value and no stored value fails the session. See Permissions. |
ports | list of integers | [3000, 5173, 8000, 8080] | The quick-pick ports shown for a live session's preview links. Any listening port serves regardless; this does not gate reachability. |
image | object | {} | Customizes the container image. Ellipsis owns the base image (FROM, user, entrypoint, preinstalled tooling); you contribute appended layers and a build-time script. |
image.dockerfile_append | string | null | null | RUN instructions appended onto the base image, before any repository exists. Use for toolchain installs. Only RUN is accepted; FROM, USER, WORKDIR, ENTRYPOINT, and COPY fail validation. Changing it rebuilds the cached image. |
image.setup | string | null | null | A shell script run once at image-build time, after repositories are checked out; everything it writes to disk is captured in the cached image. Use for dependency installs. Capped at 10 minutes. Files are captured but environment variables are not, so never write a secret to disk here. A non-zero exit fails the session. |
hooks | object | {} | Shell scripts run on every session, never cached. A hook that exits non-zero fails the session with exit status lifecycle_hook_failed. Each is capped at 5 minutes. |
hooks.post_start | string | null | null | Runs after the container starts, before any repository work. Use for repository-independent setup such as authenticating a CLI. |
hooks.post_clone | string | null | null | Runs after all repositories are checked out, before the agent starts. Use for per-session, repository-dependent setup. Prefer image.setup for dependency installs so the result is cached. |
compute | object | {} | Sandbox compute sizing. A value outside the allowed range fails validation; nothing is clamped. Compute is billed on the requested allocation over the sandbox's lifetime. |
compute.cpu | number | null | 1 | vCPU cores, 0.125 to 16. Fractional values are allowed. |
compute.memory | string | object | null | 4GB | Memory, 512MB to 64GB. A size string (16GB, 512MB; units are binary, so 1GB is 1024MB) or an object with gb/mb keys. |
compute.timeout | string | object | null | 1h | Maximum session wall clock, 60s to 1h. A duration string (15m, 90s, 1h30m) or an object with hours/minutes/seconds keys. One hour is both the default and the maximum, so this only shortens a session. |
github | object | {} | Scopes the GitHub token minted for the sandbox (GH_TOKEN, the credential git and gh authenticate with). By default it carries the installation's full permissions, scoped to the sandbox repositories. See Permissions. |
github.permissions | read_only | map | null | null | The string read_only grants read access to contents, issues, metadata, and pull requests. A map names GitHub App permission scopes one by one (contents: read, pull_requests: write); most scopes take read or write, administration and repository_projects also take admin, and checks is write-only. Either form can only reduce what the installation granted; requesting an ungranted permission fails the session with exit status missing_token_permissions. An unknown scope, an invalid level, or an empty map fails validation. |
github.repositories | list of strings | null | null | Repository names the token may touch, narrowing the default (the sandbox repositories owned by your account). An empty list or duplicates fail validation; a name the installation cannot access fails the session with exit status missing_repo_access. Public repositories from other owners are never in the token scope. |
skills
Claude Code skills installed for the session. Skills checked into a cloned repository's .claude/skills/ load automatically and need no entry here; a skills entry brings in skills the clones don't provide: another repository of your installation, a public repository, or a session with no repositories at all. See Skills.
| Field | Type | Default | Description |
|---|---|---|---|
path | string | required | Directory containing the SKILL.md, relative to the repository root (no leading /, no ..; not the root itself, and not an agent config file). The last path segment becomes the installed skill name, so it must be unique across the 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: 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. |
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. |
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 at session start fails the session before the agent starts.
structured_output
A JSON Schema contract for the session's output, passed to the runtime so the result is machine-readable.
| Field | Type | Default | Description |
|---|---|---|---|
type | "json_schema" | json_schema | Structured output type. |
json_schema | object | required | JSON Schema the agent's output must satisfy. |
budget
Spend caps for this agent, in US dollars. session caps a single session; day, week, and month cap the agent's own trailing spend. The full money model: Billing.
| Field | Type | Default | Description |
|---|---|---|---|
session | number | null | account default | Per-session budget. The account default is $250, which is also the platform maximum; a higher value is clamped to $250. |
day | number | null | platform ceiling | Trailing one-day spend cap for this agent. Ceiling $1,000. |
week | number | null | platform ceiling | Trailing seven-day spend cap for this agent. Ceiling $10,000. |
month | number | null | platform ceiling | Trailing 28-day spend cap for this agent. Ceiling $40,000. |
llm
Where this agent's completions go. Omit the block to use Ellipsis's own LLM proxy. To route one agent through a gateway of your own, register it on the Models page and name its id here; registering alone moves no traffic. See Custom LLM proxy.
| Field | Type | Default | Description |
|---|---|---|---|
proxy | string | null | null | The id of a proxy registered on the Models page (proxycfg_...). Only your own account's ids resolve. An id that names no enabled proxy fails the session rather than falling back to Ellipsis's proxy, so deleting a proxy while an agent still references it breaks that agent by design. |
mcp_servers
Built-in integrations this agent opts into by name, as a bare name or a {name: ...} object. Only consulted when the integration's account setting is "opt in only"; an integration left on "all sessions" is available to every agent regardless. Sessions spawned from an integration's own surface (a Slack mention, a Linear issue) always get that integration's tools without an entry here.
| Field | Type | Default | Description |
|---|---|---|---|
mcp_servers[] | string | {name} | [] | An integration name: linear or slack. Any other name fails validation. GitHub is the gh CLI, always present, and takes no entry. |
Validation
Every surface runs the same validator, so a file that validates in one place validates everywhere. Where an invalid config surfaces:
- On push to the default branch. A new file that fails validation is reported and no agent is created. An existing agent whose file becomes invalid keeps running its last valid version; the error shows on the agent in the dashboard, and you get an email the first time a working agent breaks.
- On pull requests. Ellipsis maintains one validation comment on the pull request listing every config file that fails to parse at the head commit, with the exact error per file. It updates on each push and confirms when everything parses.
- In the dashboard. The agent editor validates against the same validator before it opens the deploy pull request, so an invalid file never ships from there.
- At session start. Checks that need the session's own commit or your live account state run then, and a failure fails the session with the reason recorded on it: a
systemorsettingsfile that is gone or over its limit, a skill that cannot be resolved, a stored variable with no value, a GitHub permission the installation was not granted, or anllm.proxythat no longer exists. See session exit statuses.
What fails, and where:
| 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. |
ellipsis.kind is set on an agent config | Validation fails. kind only exists on code_review pipeline files; an agent config omits it. |
| A key is unknown or misplaced | Validation fails naming the key. The schema forbids unknown fields everywhere except metadata.annotations and structured_output.json_schema. |
A system, settings, or skills path is absolute, unnormalized, or escapes the repository root | Validation fails. |
A system file is missing 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. |
A system file reference or skills path points at an agent config file | Validation fails. |
| Cron expression is invalid, or restricts both day-of-month and day-of-week | Validation fails before anything is stored or scheduled. |
| A react trigger sets zero or more than one surface block | Validation fails; exactly one of pull_request, push, issue, linear_issue, sentry, slack_channel. |
A paths filter has a negated ! pattern | Validation fails; path filters are include-only. |
A sandbox.compute value is out of range or unparseable | Validation fails; values are never clamped. Bounds: cpu 0.125 to 16, memory 512MB to 64GB, timeout 60s to 1h. |
A sandbox.variables name is not a valid shell name, or appears twice | Validation fails. |
image.dockerfile_append uses an instruction other than RUN | Validation fails. |
sandbox.github.permissions names an unknown scope, an invalid level, or is an empty map | Validation fails. |
sandbox.github.permissions requests a permission the installation was not granted | The session fails at sandbox creation with exit status missing_token_permissions. |
sandbox.github.repositories is empty or has duplicates | Validation fails. A name the installation cannot access fails the session with exit status missing_repo_access. |
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 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. |
An mcp_servers entry is not linear or slack | Validation fails. |
codex.model does not support the OpenAI Responses API | Validation fails. |
A sandbox.variables entry has no value and no stored value | The session fails at start; store the variable before referencing it. |
A claude.settings file is missing, not a JSON object, over 64 KiB, or sets a protected key | The session fails before the agent starts. |
llm.proxy names no enabled proxy for your account | The session fails at start. Ellipsis never falls back to its own proxy. |
| A new file is invalid | The push is reported and no agent is created. |
| An existing file becomes invalid | The error is recorded on the agent, which keeps running its last valid version. |
| The file is removed | The agent is soft-deleted and its schedules removed. It revives if the file comes back. |
Quick start
Install the GitHub app, commit one agent YAML to your repository, and watch its first session run. Zero to a deployed agent in one sitting.
Triggers
When agents run. A config declares one trigger, a cron schedule, a react event, or an @ellipsis mention. Any agent also starts from the API and CLI.