> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auto.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Resource Lifecycle

> How .auto/ files compile into project resources, how applies reconcile them, and how to validate changes before they land.

Everything auto runs is declared in a `.auto/` directory: agents, their runtime environments, their chat identities, and project settings. This page explains the directory layout, what a resource is, how the root-level agent facade compiles into resources, what an apply does, and how to validate changes before they take effect. Read it before authoring your first agent or debugging an apply failure.

## The `.auto/` directory

A `.auto/` directory has four kinds of content:

| Path                | Contents                                                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `.auto/agents/`     | Agent definitions — one or more YAML (or JSON) documents per file, written in the root-level agent format described below |
| `.auto/fragments/`  | Reusable fragments imported by agents (by convention, shared runtimes live under `.auto/fragments/environments/`)         |
| `.auto/config.yaml` | Optional project settings singleton — at most one, no envelope                                                            |
| `.auto/assets/`     | Avatar images (`.png`, `.jpg`, `.jpeg`) referenced by `identity.avatar.asset`                                             |

A small, realistic layout — this is a trimmed version of the `.auto/` directory that configures auto's own repository:

```text theme={null}
.auto/
├── agents/
│   ├── default.yaml
│   ├── pr-review.yaml
│   └── ship-digest.yaml
├── fragments/
│   └── environments/
│       └── agent-runtime-base.yaml
├── assets/
│   ├── pr-reviewer.png
│   └── ship-digest.png
└── config.yaml
```

The rules the parser enforces:

* Only files ending in `.yaml`, `.yml`, or `.json` under `.auto/agents/` are read as resource files. Files are read in sorted path order, and one file may contain multiple YAML documents separated by `---`; each document compiles independently.
* Fragment files under `.auto/fragments/` must contain exactly one document. They are validated (parse, import cycles, removal targets) but produce no resources on their own — they only exist to be imported.
* `.auto/config.yaml` (or `.yml`) must be the only project config file. An empty file is a valid, empty config.
* Legacy layouts are rejected loudly: `.auto/sessions/` files, standalone `.auto/environments/` or `.auto/identities/` resources, and the old `kind`/`metadata`/`spec` envelope inside agent files all fail the apply with an error telling you where the content belongs now. Environments and identities are always declared inline on the agent that uses them.

## What a resource is

Compiling a `.auto/` directory produces **resources**: project-scoped records identified by `kind/name`. Four kinds are authorable through `.auto/`:

| Kind          | Authored as                       | What it is                                                                                                 |
| ------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `agent`       | A document in `.auto/agents/`     | A reusable definition of an autonomous worker: harness, prompts, tools, mounts, triggers, runtime controls |
| `environment` | Inline `environment:` on an agent | The sandbox image, resources, and setup steps a session runs in                                            |
| `identity`    | Inline `identity:` on an agent    | The display name, username, avatar, and description the agent presents in chat and on GitHub               |
| `config`      | `.auto/config.yaml`               | The per-project settings singleton, always named `config/project`                                          |

Resource names are trimmed strings of 1–128 characters matching `[A-Za-z0-9_.-]+`. The `kind/name` pair — not the file path — is a resource's identity: you can move a definition between files freely, and two files may not define the same resource differently.

Sessions are **not** resources. An agent resource is the template; a [session](/concepts/sessions) is a durable run of it, created at runtime by a trigger, a message, or an explicit start.

## The agent facade

Agent files use a flat, root-level format — the **agent facade**. There is no `kind:` or `spec:` wrapper; metadata fields (`name`, `labels`, `annotations`) and spec fields (`harness`, `model`, `systemPrompt`, `env`, `tools`, `mounts`, `triggers`, and the rest) sit side by side at the top level. The full field list is in the [agent file reference](/reference/agent-file).

Three additional keys are **control fields**: `imports` (or singular `import`), `remove`, and `variables`. The compiler consumes them and they never appear in the compiled resource:

* `imports` pulls in other documents — relative paths to files in the bundle, or [managed template](/reference/managed-templates) specifiers like `@auto/agents@latest/pr-review.yaml`. See [imports and fragments](/reference/imports-and-fragments).
* `remove` drops named items inherited from imports. Exactly three targets are supported: `tools`, `triggers`, and `env`.
* `variables` declares `{{ $name }}` substitution values that resolve inside imported content. See [variables and templating](/reference/variables-and-templating).

Compilation follows a strict order:

1. Merge each import in listed order, each compiled recursively first. **Later imports win** over earlier ones, field by field.
2. Apply the document's `remove:` directives to the merged import result.
3. Merge the document's own body last — **local fields always win**.

After all merging, a valid agent needs exactly three things: a `name`, a `harness`, and an `environment`. Everything else is optional or defaulted. In practice the harness and environment usually arrive through an imported fragment or template, so a tenant file can be as small as this real one from auto's own repository:

```yaml .auto/agents/pr-review.yaml theme={null}
name: pr-review
imports:
  - "@auto/agents@latest/pr-review.yaml"
  # Later imports win the merge, so this tooled runtime overrides
  # the template's default environment.
  - ../fragments/environments/agent-runtime-base.yaml
variables:
  repoFullName: fractal-works/auto
  githubConnection: github-fractal-works
```

<Note>
  An agent named `default` is special: it receives Auto's built-in Default base before its declared imports, so `name: default` alone is a complete, runnable agent. A project with no `default` file at all still gets the built-in one.
</Note>

### Inline resources compile out

`environment:` and `identity:` accept either a name (a reference to a resource defined elsewhere in the bundle) or an inline object. Inline objects are compiled out into **generated resources**, and the agent's spec keeps only the name. An inline identity with no `name` of its own inherits the agent's name.

This agent file:

```yaml .auto/agents/ship-digest.yaml theme={null}
name: ship-digest
harness: claude-code
environment:
  name: agent-runtime
  image:
    kind: preset
    name: node24
  resources:
    memoryMB: 8192
identity:
  displayName: Ship Digest
  username: ship-digest
  avatar:
    asset: .auto/assets/ship-digest.png
systemPrompt: |
  You are a code-analysis agent. Summarize what shipped in the last
  24 hours, grounded in the diff.
triggers:
  - kind: heartbeat
    cron: 0 8 * * *
    timezone: America/Los_Angeles
    routing:
      kind: spawn
```

compiles into three resources: `agent/ship-digest` (whose spec references `environment: agent-runtime` and `identity: ship-digest` by name), `environment/agent-runtime`, and `identity/ship-digest`.

Because generated resources are shared by name, two files may declare the same inline environment — common when several agents import the same runtime fragment — as long as they compile to the same content. Identical duplicates dedupe; different content under the same `kind/name` fails the apply with a "Conflicting generated resource" error naming both files.

## Apply semantics

An **apply** reconciles a project's resources to match a compiled `.auto/` bundle. It is declarative: the apply engine plans an action for every resource — `create`, `update`, `archive`, or `unchanged` — then executes the plan. You never patch a live resource; you change the files and apply again.

One compile path is shared by every apply surface, so the same bundle produces the same plan (or the same error) everywhere:

* **[GitHub Sync](/concepts/github-sync)** applies the `.auto/` tree of a bound repository after each merge to the production branch, and plans it on every pull request.
* **`auto.resources.dry_run`** validates a bundle from inside a running session over MCP, without applying.

Two behaviors follow from the declarative model:

* **Prune.** An apply archives resources that exist in the project but are absent from the bundle — deleting a file deletes its resources. Your repository is the complete inventory, not a patch.
* **The config singleton tracks its file.** `.auto/config.yaml` compiles to the `config/project` resource, so the file's presence and the resource's presence stay in lockstep: add the file and the resource is created, remove it and the resource is archived. The spec is currently an empty object — any key fails validation — so the file exists for forward compatibility. See [project config](/reference/project-config).

## Validation diagnostics

When a bundle fails to compile or validate, the error carries a machine-readable diagnostic alongside the human message. Tooling should branch on `diagnostic.code`, never on message text — messages can change between releases.

| Code                                        | Meaning                                                                           |
| ------------------------------------------- | --------------------------------------------------------------------------------- |
| `auto.validation.input.dialect_conflict`    | A dry-run call passed both the `files` and `resources` input dialects             |
| `auto.validation.input.invalid_shape`       | The validation input does not match the selected dialect                          |
| `auto.validation.authoring.facade_required` | The file uses a legacy typed-resource envelope where the agent facade is required |
| `auto.validation.parse.yaml_invalid`        | The file could not be parsed as YAML or JSON                                      |
| `auto.validation.schema.invalid`            | The resource does not match its schema (also raised for an empty apply file)      |
| `auto.validation.legacy.unknown`            | Fallback for a failure without a recognized code                                  |

Every diagnostic includes `severity` (`error`, `warning`, or `info`), `blocking`, and a safe message, and may include a `location` (`file`, `line`, `column`) and a `remediation` with a suggested fix. Unknown future codes must not crash a consumer — treat the set as open.

Apply *plans* can also carry non-blocking diagnostics that are not validation errors — for example `optional_connection_skipped` (info) when a tool or trigger marked `optional: true` references a connection with no active grant, or the template bump advisories described in [GitHub Sync](/concepts/github-sync#template-subscriptions-and-the-sweep). These render as notes on the plan rather than failing it.

## Dry runs

There are two ways to see what an apply would do without doing it. Both run the identical compile-and-plan path, so a bundle that plans cleanly in one surface plans cleanly in the other:

<Steps>
  <Step title="Pull request sync plan">
    Every pull request against a synced repository's production branch that touches `.auto/` gets a **Sync plan** check and comment — a full dry-run apply of the PR head. This is the plan of record for what merging will change. See [GitHub Sync](/concepts/github-sync#the-sync-check-on-pull-requests).
  </Step>

  <Step title="From a session">
    The `auto.resources.dry_run` tool on the session's Auto MCP server validates and plans resource changes in place. It accepts inline `files` (`{ path, content }` pairs, UTF-8, capped at 3,000,000 bytes per call) or typed `resources` — exactly one of the two. Managed template imports resolve automatically. Binary avatar assets cannot be passed inline; keep the image committed and let the full GitHub Sync apply validate its bytes.
  </Step>
</Steps>

<Tip>
  Agents running in a sandbox get a path-first version of `auto.resources.dry_run`: calling it with no arguments validates the working tree's entire `.auto/` directory, and passing repository-relative `paths` validates a focused subset with its local imports included automatically.
</Tip>

## Where to go next

<CardGroup cols={2}>
  <Card title="Agent file reference" href="/reference/agent-file">
    Every field of the agent facade — types, defaults, constraints.
  </Card>

  <Card title="Imports and fragments" href="/reference/imports-and-fragments">
    Merge semantics, remove directives, append, and file-backed prompts.
  </Card>

  <Card title="Managed templates" href="/reference/managed-templates">
    Importing `@auto/...` templates, pinning versions, and overrides.
  </Card>

  <Card title="GitHub Sync" href="/concepts/github-sync">
    Applying `.auto/` from your repository, CI/CD-style.
  </Card>
</CardGroup>
