Cloud Agents

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-api
  • ellipsis marks the file as an agent config and names it. version: v1 is the only supported schema version.
  • claude.system is the agent's instructions. Omit it and the agent runs on Claude Code's own default prompt, like claude with no arguments.
  • trigger decides 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.repositories names 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:

FieldTypeDefaultDescription
ellipsisobjectrequiredSchema version, name and description, organizational metadata, and the enabled/interactive/ide flags. Its presence marks the file as an agent config.
claudeobject{}Claude runtime config: the system prompt, model, reasoning effort, turn cap, and an optional Claude Code settings file.
codexobject | nullnullRun the agent on OpenAI's Codex CLI instead of Claude Code. Declaring the block is what selects the harness.
triggertrigger object | nullnullHow the agent runs automatically: one trigger of type cron, react, or mention. Omit for a manual-only agent.
sandboxobject{}The sandbox the agent runs in: repositories, environment variables, ports, compute sizing, image customization, lifecycle hooks, and the GitHub token scope.
skillslist of skill objects[]Claude Code skills installed for the session beyond what the sandbox repositories already provide.
structured_outputobject | nullnullJSON Schema contract for machine-readable session output.
budgetobjectall nullPer-session and trailing spend caps for this agent, in US dollars.
llmobject{}Where this agent's completions go. Omit to use Ellipsis's own LLM proxy.
mcp_serverslist 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.

FieldTypeDefaultDescription
versionstringv1Config schema version. v1 is the only supported version; anything else fails validation.
namestring | nullnullDisplay name. Dashboard-created files slug this into the file path.
descriptionstring | nullnullShort summary shown in product surfaces.
enabledbooleantrueWhen false, cron, react, and mention starts are skipped. Manual runs still work.
interactivebooleantrueWhen 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.
idebooleantrueWhen true, a human can open a browser IDE or a port URL into the running sandbox. See Sandboxes.
metadataobject{}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:

FieldTypeDefaultDescription
labelslist of strings[]Flat string tags for grouping and filtering.
annotationsmap of string to string{}Arbitrary key-value pairs.

claude

FieldTypeDefaultDescription
systemstring | {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[].filestringrequiredPath 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.
modelstringclaude-opus-5Model passed to Claude Code. Omit unless Ellipsis gave your account explicit guidance.
effortenum | nullnullReasoning effort passed to Claude Code. Higher effort trades latency and cost for depth. Omit to use the model default.
fallback_modelstring | nullnullModel Claude Code falls back to when the primary model is overloaded. Omit for no fallback.
max_turnsinteger | nullnullHard 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.
settingsobject | nullnullPoint 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.pathstringrequiredPath 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.repositoryobject | nullnullWhere 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.namestringrequiredThe repository name, without the owner.
settings.repository.ownerstring | nullthe config accountGitHub owner (organization or user login).
settings.repository.refstring | nulldefault-branch headBranch, 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.

FieldTypeDefaultDescription
systemstring | {file} | list of both""Same shapes and constraints as claude.system.
modelstringbedrock-gpt-5.6-terraA 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

FieldTypeDefaultDescription
type"cron"requiredSelects the cron trigger shape.
schedulestringrequiredFive-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.

FieldTypeDefaultDescription
type"react"requiredSelects the react trigger shape.
pull_requestobject | nullnullReact to pull-request actions. Filters: repositories, base, head, draft, labels, paths, for.
pushobject | nullnullReact to branch pushes. No on: list; every push to a matching branch fires. Filters: repositories, branch, paths, for.
issueobject | nullnullReact to GitHub issue actions. Filters: repositories, labels, for.
linear_issueobject | nullnullReact to Linear issue actions. Filter: for.
sentryobject | nullnullReact to Sentry alerts. Filter: projects.
slack_channelobject | nullnullReact when a new public channel is created in your Slack workspace. No on: list, no filters.

Actions per surface:

FieldRequiredAllowed values
pull_request.onyesopened (PR opened or marked ready), pushed (every head advance, including the open), merged, closed (closed without merge), review_submitted, commented
issue.onyesopened, closed, commented
linear_issue.onno, default [opened]opened
sentry.onyesissue_alert (a Sentry issue alert rule fired), metric_alert (a metric alert entered critical status)

Filter fields, each on the surfaces named above:

FieldTypeDefaultDescription
repositoriesfilter object | list of stringsall repositoriesRepository watch filter. A bare list is shorthand for include. Independent of sandbox.repositories; the triggering repository is cloned regardless.
repositories.includelist of strings[]Repository names to watch. Empty matches every repository of the installation, including ones added later.
repositories.excludelist of strings[]Repository names to exclude, applied after include.
baselist 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.
headlist of strings[]Head-branch filter (pull_request). Same shapes as base. Empty matches any head.
branchlist of strings[]Branch filter (push). Same shapes as base. Empty matches every branch.
draftboolean | nullnullDraft filter (pull_request). true matches only draft PRs, false only non-draft, null both.
labelslist of strings[]Label filter (pull_request, issue). Matches when any listed label is present; empty matches regardless.
pathslist of strings[]Changed-path glob filter (pull_request, push). Include-only; negated ! patterns fail validation. Empty matches regardless.
projectslist of strings[]Sentry project slugs (sentry). Empty matches every project in the connected Sentry org.
foraudience objectusers yes, bots noWho may trigger the surface, classified on the entity author (the pusher for push).
for.usersfilter | list | booleantrueHuman authors, include-minus-exclude. true is all humans, a list is specific logins, false or [] is none.
for.users.includelist of strings | booleantrueHuman authors to include.
for.users.excludelist of strings[]Human logins to exclude, applied after include.
for.botsfilter | list | booleanfalseBot authors, same shapes as for.users.

Mention trigger

Route @ellipsis mentions to this agent instead of the built-in responder.

FieldTypeDefaultDescription
type"mention"requiredSelects the mention trigger shape.
platformslist 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.

FieldTypeDefaultDescription
repositorieslist of repository objects[]Repositories cloned into the sandbox.
repositories[].namestringrequiredThe repository name, without the owner.
repositories[].ownerstring | nullthe config accountGitHub owner. Public repositories from other owners work; private repositories outside the owning account are rejected.
repositories[].refstring | nulldefault-branch headPins the checkout, fetched and checked out verbatim; use a commit SHA for a reproducible checkout.
variableslist of variable objects[]Environment variables injected into the sandbox. An allowlist: only the variables named here reach this agent. Duplicate names fail validation.
variables[].namestringrequiredThe variable name. Must be a valid shell name: letters, digits, underscores, not starting with a digit.
variables[].valuestring | nullnullA 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.
portslist 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.
imageobject{}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_appendstring | nullnullRUN 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.setupstring | nullnullA 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.
hooksobject{}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_startstring | nullnullRuns after the container starts, before any repository work. Use for repository-independent setup such as authenticating a CLI.
hooks.post_clonestring | nullnullRuns 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.
computeobject{}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.cpunumber | null1vCPU cores, 0.125 to 16. Fractional values are allowed.
compute.memorystring | object | null4GBMemory, 512MB to 64GB. A size string (16GB, 512MB; units are binary, so 1GB is 1024MB) or an object with gb/mb keys.
compute.timeoutstring | object | null1hMaximum 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.
githubobject{}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.permissionsread_only | map | nullnullThe 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.repositorieslist of strings | nullnullRepository 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.

FieldTypeDefaultDescription
pathstringrequiredDirectory 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.
repositoryobject | nullnullWhere 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.namestringrequiredThe repository name, without the owner.
repository.ownerstring | nullthe config accountGitHub owner.
repository.refstring | nulldefault-branch headBranch, 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.

FieldTypeDefaultDescription
type"json_schema"json_schemaStructured output type.
json_schemaobjectrequiredJSON 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.

FieldTypeDefaultDescription
sessionnumber | nullaccount defaultPer-session budget. The account default is $250, which is also the platform maximum; a higher value is clamped to $250.
daynumber | nullplatform ceilingTrailing one-day spend cap for this agent. Ceiling $1,000.
weeknumber | nullplatform ceilingTrailing seven-day spend cap for this agent. Ceiling $10,000.
monthnumber | nullplatform ceilingTrailing 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.

FieldTypeDefaultDescription
proxystring | nullnullThe 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.

FieldTypeDefaultDescription
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 system or settings file 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 an llm.proxy that no longer exists. See session exit statuses.

What fails, and where:

CaseResult
File has no top-level ellipsis: blockNot an agent config: ignored entirely, even at a config path.
ellipsis.version is unsupportedValidation fails. Only v1 exists.
ellipsis.kind is set on an agent configValidation fails. kind only exists on code_review pipeline files; an agent config omits it.
A key is unknown or misplacedValidation 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 rootValidation fails.
A system file is missing or over 64 KiB at the validated commitValidation fails at sync and on config pull requests. At session start it fails the session instead.
system is an empty listValidation fails; a list needs at least one text part or file reference.
A system file reference or skills path points at an agent config fileValidation fails.
Cron expression is invalid, or restricts both day-of-month and day-of-weekValidation fails before anything is stored or scheduled.
A react trigger sets zero or more than one surface blockValidation fails; exactly one of pull_request, push, issue, linear_issue, sentry, slack_channel.
A paths filter has a negated ! patternValidation fails; path filters are include-only.
A sandbox.compute value is out of range or unparseableValidation 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 twiceValidation fails.
image.dockerfile_append uses an instruction other than RUNValidation fails.
sandbox.github.permissions names an unknown scope, an invalid level, or is an empty mapValidation fails.
sandbox.github.permissions requests a permission the installation was not grantedThe session fails at sandbox creation with exit status missing_token_permissions.
sandbox.github.repositories is empty or has duplicatesValidation 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 nameValidation fails; the last path segment is the installed skill name.
A skills entry without repository: has no SKILL.md at the validated commitValidation 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 slackValidation fails.
codex.model does not support the OpenAI Responses APIValidation fails.
A sandbox.variables entry has no value and no stored valueThe 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 keyThe session fails before the agent starts.
llm.proxy names no enabled proxy for your accountThe session fails at start. Ellipsis never falls back to its own proxy.
A new file is invalidThe push is reported and no agent is created.
An existing file becomes invalidThe error is recorded on the agent, which keeps running its last valid version.
The file is removedThe agent is soft-deleted and its schedules removed. It revives if the file comes back.