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

# Files & Schema

> The repository layout and the full flow, suite, and hook file reference for code-managed flows

This is the complete file reference for [code-managed flows](/code-managed-flows): where files live under `.autosana/`, and every recognized key in flow files, suite manifests, and hook scripts.

## Repository layout

Everything Autosana manages lives under a single `.autosana/` folder — at your repository root by default, or under a subdirectory you point Autosana at (see [Monorepos](#monorepos)). Flows are `*.flow.yaml` files, a suite is a folder containing a `_suite.yaml` manifest, and hooks are script files under a `hooks/` directory.

```text theme={null}
.autosana/
├── login.flow.yaml          # a root flow (folder "")
├── hooks/
│   └── seed-db.py           # a hook — slug "seed-db"
└── smoke/                   # a suite folder
    ├── _suite.yaml          # the suite manifest (suite key "smoke")
    ├── checkout.flow.yaml   # a flow in the smoke suite
    └── hooks/
        └── reset-test-env.sh  # another hook — slug "reset-test-env"
```

| File type | Location                                                    | Purpose                         |
| --------- | ----------------------------------------------------------- | ------------------------------- |
| **Flow**  | `<name>.flow.yaml` (anywhere under `.autosana/`)            | One test flow                   |
| **Suite** | `<folder>/_suite.yaml` (one per folder)                     | Groups the flows in that folder |
| **Hook**  | `<any>/hooks/<name>.<ext>` (direct parent must be `hooks/`) | A setup/teardown script         |

<Note>
  A file is only recognized if it ends in `.flow.yaml`, is named exactly `_suite.yaml`, or sits directly inside a `hooks/` folder with a supported extension. Other files under `.autosana/` are ignored.
</Note>

## Flow files

A flow file ends in `.flow.yaml`. The only required keys are `name` and `instructions`, where `instructions` is either a single multiline prompt or a YAML list of steps.

As a multiline prompt:

```yaml theme={null}
key: login
name: Login
instructions: |
  Log in as qa+smoke@example.com using the password in ${env:LOGIN_PASSWORD}.
  Open the account menu and verify the signed-in email is shown.
  Sign out and confirm you land back on the login screen.
```

Or as a list of steps:

```yaml theme={null}
key: checkout
name: Checkout happy path
description: Buys one item as a logged-in user
caching: false
instructions:
  - From the home screen, tap the cart icon
  - Tap "Checkout"
  - Verify the order confirmation screen appears
```

The recognized top-level keys are:

| Key                 | Required  | Notes                                                                                                                                                                           |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **name**            | Yes       | Non-empty string.                                                                                                                                                               |
| **instructions**    | Yes       | A YAML list of non-empty step strings, or a single non-empty prompt string. A list is numbered into a single prompt.                                                            |
| **key**             | No        | Unique flow key. Defaults to the path minus `.autosana/` and `.flow.yaml` (e.g. `smoke/checkout`).                                                                              |
| **description**     | No        | Free-text description.                                                                                                                                                          |
| **app**             | Sometimes | Name of a linked app. Optional when the repo is linked to 0 or 1 apps; **required on every flow once the repo is linked to more than one app**. An unknown name fails the sync. |
| **caching**         | No        | Boolean, defaults to `true`. Only has an effect when [Run Caching](/flows#run-caching) is enabled for your org.                                                                 |
| **setup\_hooks**    | No        | Ordered list of hook slugs to run before the flow.                                                                                                                              |
| **teardown\_hooks** | No        | Ordered list of hook slugs to run after the flow.                                                                                                                               |
| **labels**          | No        | List of label names — see [Labels](#labels).                                                                                                                                    |

<Warning>
  Any top-level key that isn't in the table above is a hard error. A typo like `instructoins:` fails validation with a "Did you mean 'instructions'?" suggestion on the [Autosana Flows check](/code-managed-sync#sync-status--validation), so mechanical mistakes are caught before they merge.
</Warning>

<Tip>
  **Let the path derive your key.** If you omit `key`, the key comes from the file path (`.autosana/smoke/checkout.flow.yaml` becomes `smoke/checkout`). Set an explicit `key` when you want the key to stay stable even if you move or rename the file — see [Deleting and renaming](/code-managed-sync#deleting-and-renaming).
</Tip>

### Referencing variables

Reference environment variables inside `instructions` with the `${env:VAR_NAME}` token. This is **reference only** — the values stay defined in the dashboard and are resolved just in time when the flow runs. There is no `env:` block in the YAML; the value never lives in your repo.

```yaml theme={null}
name: Login
instructions: |
  Log in with email ${env:TEST_EMAIL} and password ${env:TEST_PASSWORD}.
  Verify you land on the welcome screen.
```

Define and manage the actual values in the dashboard — see [Variables](/variables) for the full variable model and [Environments](/environments) for per-environment values.

### Referencing hooks

Attach hooks to a flow with `setup_hooks` and `teardown_hooks`, each an ordered list of hook **slugs**:

```yaml theme={null}
name: Checkout happy path
setup_hooks:
  - seed-db
teardown_hooks:
  - reset-test-env
instructions:
  - Add an item to the cart and check out
  - Verify the order confirmation appears
```

A slug resolves against **every active hook in your organization** — not just repo files — so you can also reference hooks authored in the dashboard, including cURL hooks (which can only be created in the dashboard). Find a dashboard hook's slug on the hook in the [Hooks](/hooks) page. See [Hooks as files](#hooks-as-files) for how a repo file's slug is derived.

Duplicate slugs within one list are rejected. The same slug may appear in both `setup_hooks` and `teardown_hooks` — that's legal. To reference a hook by name inside your instructions at run time, use `${hooks:Hook Name}` (by display name); see [Hooks](/hooks).

### Labels

Attach [labels](/api-labels) to a flow or suite with `labels`, a list of label names:

```yaml theme={null}
name: Checkout happy path
labels: [smoke, critical]
instructions:
  - Add an item to the cart and check out
```

Names match case-insensitively against your org's labels; unknown names are auto-created. Omitting `labels` leaves the flow/suite's existing labels untouched — an explicit `labels: []` clears them. Labeled flows and suites dispatch via run-by-label as usual.

## Suites

A suite is a folder containing a `_suite.yaml` manifest. The suite's key is its folder path (a `smoke/` folder gives the suite key `smoke`). The only required key is `name`:

```yaml theme={null}
name: Smoke Tests
description: Critical-path checks
setup_flow: login
parallelize_flows: false
instructions: |
  Test account is qa+smoke@example.com.
flows: [login, checkout]
```

The recognized keys are:

| Key                                    | Required | Notes                                                                                                                                                                                                              |
| -------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **name**                               | Yes      | Non-empty string.                                                                                                                                                                                                  |
| **flows**                              | No       | Ordered list of flow-key references. Omit it to include every flow **directly in the suite's own folder** (subfolders are not included), in filename-alphabetical order.                                           |
| **setup\_flow**                        | No       | A single flow-key reference to run first.                                                                                                                                                                          |
| **parallelize\_flows**                 | No       | Boolean. Runs each member flow in an independent session when `true`; defaults to `false`. An explicit API request override takes precedence for that launch; an omitted or `null` override uses this saved value. |
| **description**                        | No       | Free-text description.                                                                                                                                                                                             |
| **instructions**                       | No       | Suite-level context shared across the suite's flows (e.g. shared test-account info).                                                                                                                               |
| **setup\_hooks** / **teardown\_hooks** | No       | Ordered lists of hook slugs.                                                                                                                                                                                       |
| **labels**                             | No       | List of label names — see [Labels](#labels).                                                                                                                                                                       |

References in `flows` and `setup_flow` resolve **sibling-first**: a flow directly in the suite's own folder wins, otherwise the reference is matched against every flow in the repo. Flows in a subfolder are not default members — list them explicitly (or give the subfolder its own `_suite.yaml`). Flow keys and suite keys must each be unique across the whole repo. An unknown reference, or the same flow listed twice, is a validation error.

<Note>
  The `_suite.yaml` file must live inside a folder — it cannot sit at the `.autosana/` root, because a suite *is* a folder. Membership is defined by the suite (its `flows` list or its folder), never declared inside the flow files themselves.
</Note>

<Warning>
  YAML parses bare `no`, `yes`, `on`, and `off` as booleans (the "Norway problem"). Because `setup_flow` and `name` must be strings, `setup_flow: no` fails validation — quote the value if you really mean the string `"no"`.
</Warning>

For how variables and setup flows propagate across a suite's flows, see [Suites](/suites).

## Hooks as files

Hooks live as script files inside a `hooks/` folder — either `.autosana/hooks/` or `<suite>/hooks/`. The file extension determines the hook type, and the filename becomes the hook's slug.

| Extension | Hook type                        |
| --------- | -------------------------------- |
| `.py`     | Python script                    |
| `.js`     | JavaScript script                |
| `.ts`     | TypeScript script                |
| `.sh`     | Bash script                      |
| `.json`   | Launch args (must be valid JSON) |

The **slug** is derived from the filename with its final extension removed: lowercased, with runs of non-alphanumeric characters collapsed to `-`. So `Seed DB.sh` becomes slug `seed-db`, and `reset.env.json` becomes `reset-env`. This slug is what you reference in `setup_hooks` / `teardown_hooks`. The **display name** is the humanized filename (`reset-test-env.sh` shows as "Reset Test Env").

<Warning>
  **Hook slugs are unique across your whole organization** — the folder a hook lives in has no scoping effect. Two files that slugify the same (`seed-db.py` and `seed_db.sh`), or a slug that collides with a **different repository's** hook, fail the sync with a rename error. A slug that matches an existing **dashboard-authored** hook is *not* an error — that hook is adopted (its run history preserved), the same way flows adopt by name; see [Migrating existing flows](/code-managed-flows#migrating-existing-flows). Rename the file if that isn't what you intend.
</Warning>

<Note>
  The file content **is** the hook script, stored verbatim. Empty or whitespace-only files are rejected. A `.json` launch-args hook must parse as valid JSON, and a filename with no letters or digits (so it produces an empty slug) is rejected.
</Note>

Script hooks (`.py`, `.js`, `.ts`, `.sh`) read environment variables **natively** — `os.environ.get(...)` in Python, `process.env` in JavaScript/TypeScript, `$VAR` in Bash. Launch-args (`.json`) hooks — and dashboard-authored cURL hooks — use the `${env:KEY}` token instead, since they aren't executed scripts. cURL hooks have no file form; reference an existing dashboard cURL hook by slug, or use a `.sh` hook that runs `curl`. See [Hooks](/hooks) for the full hook model.

## Monorepos

By default Autosana looks for `.autosana/` at your repository root. If your definitions live in a subdirectory — common in a monorepo — point Autosana at that folder with the repo's **Root directory** setting.

1. Go to **[Settings > Integrations](https://autosana.ai/settings?tab=integrations)**
2. On the repo with **Code-Managed Testing** enabled, set **Root directory** to the folder that contains `.autosana/` (for example, `services/mobile` for `services/mobile/.autosana/`)
3. Leave it blank to use the repository root

Flow and suite **keys stay relative to `.autosana/`**, so moving your definitions into a subdirectory doesn't change any keys — a flow at `services/mobile/.autosana/login.flow.yaml` still has the key `login`. The GitHub links on each row point at the full path in your repo.

<Note>
  Saving a new Root directory doesn't re-sync on its own, and an unrelated push won't either. To re-sync from the new location, push a change under `<root-directory>/.autosana/` on your default branch, or toggle **Code-Managed Testing** off and on. The nightly resync also picks it up within a day.
</Note>

## Next Steps

* [Validate, sync, and preview on PRs →](/code-managed-sync)
* [Write effective flows →](/flows)
* [Organize flows with Suites →](/suites)
* [Learn about hooks →](/hooks)
* [Manage variables →](/variables)
