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

# Project Layout & cowboy.toml

> What an initialized Cowboy project contains, how actor targets are discovered, and what the manifest can declare

## Overview

`cowboy init` creates a *project*: a directory whose root holds a `cowboy.toml` manifest. Project commands (`cowboy check`, `cowboy build`, `cowboy run`, `cowboy test`, `cowboy deploy`, `cowboy actor call <target>`, and so on) find the root by walking up from the current directory to the nearest `cowboy.toml`, then operate on **actor targets**: named units of Python source that each compile to one deployable actor.

## Layout

```
my-cowboy-app/
├── cowboy.toml                 # manifest; marks the project root
├── pyproject.toml              # Python tooling (cowboy-actor-sdk, pytest, basedpyright, ruff)
├── README.md
├── AGENTS.md
├── .gitignore                  # excludes .venv/, caches and .cowboy/
├── actors/
│   ├── __init__.py
│   ├── hello/                  # target "hello"
│   │   ├── __init__.py
│   │   └── main.py             # entrypoint
│   └── billing/                # target "billing", added with `cowboy init billing`
│       ├── __init__.py
│       └── main.py
├── tests/
│   ├── test_hello.py           # SimulatedChain unit tests, run by `cowboy test`
│   └── test_billing.py
├── offchain/                   # only with --offchain: ordinary Python the actor awaits
│   ├── __init__.py             # explicit same-name re-exports declare the callables
│   ├── reports.py
│   └── tests/
├── .venv/                      # created by `uv sync` during init (local, ignored)
└── .cowboy/                    # local state (ignored by git)
    ├── config.json             # environments and the active one
    ├── key                     # wallet key written by `cowboy wallet create`
    ├── deploy/<env>/<target>.project.json   # deployment records written by `cowboy deploy`
    └── local/offchain-env/     # off-chain worker environment (with --offchain)
```

The [examples curriculum](https://docs.cowboy.inc/developers/examples.md) projects under `examples/core/` have the same shape: a `cowboy.toml`, one `actors/<name>/main.py` per actor, and `tests/test_<name>.py`.

## The manifest

The minimal manifest, the one `cowboy init` writes, is a single line:

```toml theme={null}
schema_version = 2
```

`schema_version` is the only required key. The CLI parses versions `1` through `4` and writes `2` for every new project; `[offchain]` and `uses_offchain` need schema 2, `[workloads]` needs schema 3 and `[web]` needs schema 4, and each is rejected in an older file with a hint naming the version that unlocks it. Unknown keys anywhere in the file are rejected, so a typo fails at parse time instead of being silently ignored.

### Conventional targets

With no `[actors.<name>]` declarations, targets come from the filesystem:

| Layout | Target name | `source_root` |
| - | - | - |
| `actors/<name>/main.py` | `<name>` | `actors/<name>` |
| `actors/<name>.py` containing an `Actor` subclass (schema 2 only) | `<name>` | `actors` |

A name that appears in both forms is an error (`conventional actor target '<name>' has both a directory and flat entrypoint`). Entries under `actors/` whose names are not valid target names are ignored, and symlinked entrypoints are refused. A project can hold at most 64 targets.

Target names match `[a-z][a-z0-9_]*` and are at most 64 bytes. `cowboy init <actor>` additionally refuses Python keywords and the reserved names `actors`, `main`, `offchain` and `tests`.

### Explicit targets

Declare a target when its entrypoint does not follow the convention, or when it needs library roots:

```toml theme={null}
schema_version = 2

[actors.router]
entrypoint = "src/router/app.py"
source_root = "src/router"        # optional; the entrypoint must be a direct child of it
libraries = []                    # optional; CIP-26 library roots
uses_offchain = false             # optional, schema 2; pins whether the target uses the off-chain proxy
```

In schema 2 an explicit declaration takes precedence over a conventional target of the same name and the two kinds can coexist. In schema 1 a name that is both conventional and declared is an error (`target '<name>' is both conventional and explicitly configured`).

### Off-chain configuration

`cowboy init --offchain` adds an `[offchain]` table. An empty table selects the defaults: the Python runtime (CPython 3.12), the `offchain/` package as the context, the runner's default resource class, and the `offchain-images` CBFS volume for the project's image deltas. The optional keys:

```toml theme={null}
[offchain]
runtime = "python"                # "python" (default), "node" or "rust"
resource_tier = "small-ephemeral" # a CIP-10 resource class name registered on the chain
min_isolation_tier = "standard"   # "standard" or "strong"
volume = "offchain-images"        # CBFS volume that receives the project's image deltas
secrets = ["OPENAI_API_KEY"]      # CBSS key names released into each off-chain call's environment

[[offchain.volumes]]              # public CBFS volumes the job reads
name = "public-models"
owner = "<publisher-address>"
mode = "ro"                       # optional; public volumes are read-only
files = ["qwen3-0.6b-q8.gguf"]    # local files prepared for this volume
```

`volumes` also accepts the shorthand `volumes = ["scratch:rw"]`, a `name:mode` entry (`ro`, `rw` or `wo`) resolved under the calling actor. At most 8 volumes are allowed. A target that imports from the `offchain` package is inferred to use off-chain functions even when the manifest has no `[offchain]` table; the defaults then apply.

## Selecting a target

Commands that take a `TARGET` argument resolve it in this order:

1. The name you pass (`cowboy deploy hello`).
2. Otherwise, the single target whose `source_root` contains the current directory.
3. Otherwise, the project's only target.
4. Otherwise an error: `project contains no actor targets`, or `actor target is ambiguous; discovered: billing, hello. Run \`deploy billing\`\`.

In a one-actor project `cowboy deploy`, `cowboy check` and `cowboy actor inspect` therefore need no argument at all.

## Local state under `.cowboy/`

`.cowboy/` is per-developer state and is git-ignored by the scaffold:

* **`config.json`**: environments (`rpc_url`, `key`, optional `watchtower_registry` and `identity`) and which one is `active`. Written by `cowboy init --env`, `cowboy env add`, `cowboy env use` and `cowboy deploy --env`. See [Key auto-discovery](https://docs.cowboy.inc/cli-specs/key-auto-discovery.md).
* No key is kept here: each environment's `key` names a key in the CLI keystore, `~/.cowboy/keys/<name>` (default `default`), written by `cowboy wallet create`. A leftover `.cowboy/key` is not read, and a project that keeps one while naming no key is refused (`key_unavailable`, `project_key_file`).
* **`deploy/<env>/<target>.project.json`**: the latest and any pending deployment of a target on an environment. Commands that take a project target (`cowboy actor call hello`, `cowboy actor inspect hello`) resolve the actor's address from this record for the active environment.
* **`local/offchain-env`**: the worker environment for native off-chain runs.
* Build output from `cowboy build`, which the scaffolded `pyproject.toml` excludes from ruff and basedpyright.

Of the files these commands write, only `offchain.lock` (written by `cowboy build` at the project root) is meant to be committed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.