# Workflow layout Where `canyonos` finds a workflow, what goes in its `config` folder, what reaches the agent images, and what CanyonOS writes into your files. ## The workflow root Every `canyonos` command reads the workflow from its root, which depends on the folder you run the command from: | The folder you run `canyonos` from | Workflow root | | ---------------------------------- | ------------------------------------------------------------------------------------------- | | Has a `.canyon` folder | `.canyon`, which `canyonos convert` writes. The source beside it is not part of the deploy. | | Has no `.canyon` folder | The folder itself | Nothing outside the root is read, with two exceptions from the folder you run `canyonos` from: its `.env` ([What `.env` is for](#what-env-is-for)) and its name, which goes into the Docker names ([Names](#names)). Every path in these docs is relative to the root. ## Layout ```text config/ workflow_config.yaml (required) llms.yaml optional, like every other file in config/ prompts.yaml scaling.yaml policy.yaml governance.yaml test_query.txt ... your application code, becomes /app stubs/ generated by the build grpc_stubs/ generated by the build docker_container/ generated by the build, one context per image ``` You write `config/` and the code. The build generates the other three folders in the Global Controller container's copy of the root, not in your folder. These names and a few others are reserved; see [Reserved names](WORKFLOW_DESIGN.md#reserved-names). | File in `config/` | What it holds | Guide | | ------------------------ | ------------------------------------------------ | -------------------------------------------------------- | | `workflow_config.yaml` | The agents and the endpoint | [Workflow config](WORKFLOW_CONFIG.md) | | `llms.yaml` | Which models agents may use, and spending caps | [LLM Gateway](LLM_GATEWAY.md) | | `prompts.yaml` | Prompts you edit on the dashboard | [Prompt management](PROMPTS.md) | | `scaling.yaml` | The autoscaling policy | [Autoscaling](SCALING.md) | | `policy.yaml` | Which requests may reach which agents | [Policy](RUNTIME_CONTRACT.md#policy) | | `governance.yaml` | Per-agent rules you then change on the dashboard | [Governance rules](RUNTIME_CONTRACT.md#governance-rules) | | `test_query.txt` | The query `canyonos test` sends | [CLI](CLI.md) | Each `entrypoint` in the workflow config is a path relative to the root. It has to name a `.py` file, it can't be absolute, and it can't use `..` to climb out. A symlink that takes an entrypoint outside the root is rejected too. ## What becomes `/app` Each agent image is built from a context that starts as a copy of the root, with relative paths intact. Among other things, the copy leaves out `config/`, the three generated folders, hidden files, symlinks and private keys. The build then writes the platform's runtime modules, every agent's stub, the generated gRPC modules and the agent's own entrypoint on top of it. Inside the container the working directory is `/app` and Python starts there, so `/app/pkg/mod.py` imports as `pkg.mod`. [Images and dependencies](IMAGES_AND_DEPENDENCIES.md) lists everything the copy leaves out and everything the build writes on top. ## What the platform writes into your files | Command | What it writes | | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `canyonos new-app` | The starter files, into an empty folder | | `canyonos convert` | `.canyon`, through your coding agent, including `.canyon/.env.example` with the names of the keys your code needs. In a git repository, it also adds `.canyon/` to `.gitignore` unless it is already there. | | `canyonos deploy` | `project_id` on the first deploy. On Docker, also each agent's `resources` and `replicas`, with defaults filled in and any change you make in the deploy's menu. | | `canyonos test` | `project_id`, if there is none yet. With nothing deployed, it sets `provider: local` for its own deploy, then restores the file as it was. | | `canyonos config`, `canyonos target` | The keys you change | | `canyonos clean` | Deletes `.canyon`; see [Stop and clean up](CLI.md#stop-and-clean-up) | `deploy`, `test`, `config` and `target` write to `config/workflow_config.yaml` in the root. Every later deploy reuses `project_id`, so the workflow stays one project on the dashboard and keeps its Docker names. Deleting that line starts a new project, and so does `canyonos clean` on a converted workflow, because it deletes `.canyon` and the workflow config with it. Nothing in CanyonOS writes or deletes `.env`: it is only read. ## What `.env` is for `.env` lives in the folder you run `canyonos` from. Put API keys and any other secrets your code reads there. `canyonos deploy` copies it into the Global Controller's `/workspace`. The Global Controller reads it for `${VAR}` references in the workflow config and for cloud credentials. On Docker, it passes the file to each agent replica with `--env-file`; the endpoint, Redis and metrics-collector containers don't get it. On Kubernetes, `.env` becomes a Secret; see [Kubernetes deployment](KUBERNETES.md). Before it builds anything, `canyonos deploy` warns about keys that `.env.example` in the root lists but `.env` leaves out or empty. Don't put the Bedrock endpoint URL or the proxy variables in `.env`: CanyonOS sets those on every replica, and its values win over the file. See [LLM Gateway](LLM_GATEWAY.md#what-goes-in-env). Hidden files such as `.env` never reach an image. Never put any other secret in the root: the copy would bake it into every image. The copy does drop PEM private keys and `.p12`, `.pfx` and `.jks` files, with a warning for each, but it can't recognize a key written into a Python string or a JSON file. ## Names On Docker, CanyonOS names everything it starts after the project: the name of the folder `canyonos` runs from, lowercased, with characters Docker doesn't allow replaced by `-` and cut to 24 characters, then the first 8 characters of `project_id`. For a folder `myapp`: | What | Name | Example | | --------------------- | -------------------------------------- | --------------------------------------------- | | An agent's image | `canyonos--` | `canyonos-myapp-3f9a1c2e-splitagent` | | An agent replica | `canyonos---` | `canyonos-myapp-3f9a1c2e-splitagent-1a2b3c4d` | | The Global Controller | `canyonos--global-controller` | `canyonos-myapp-3f9a1c2e-global-controller` | | The workflow's Redis | `canyonos--redis-` | `canyonos-myapp-3f9a1c2e-redis-localhost` | Agent names are lowercased, and `` is 8 random hexadecimal characters.