
# Project files

A project file is a `cruma.yaml` or `cruma.toml` in your repository that lists the sites, backends and processes the project needs. `cruma up` runs it from a terminal. A coding agent connected through `cruma mcp` can attach the same file, bring the project up, and keep the file in step with what you ask for. The file format is the one described in [Configuration](https://cruma.io/book/cruma-tunnels/configuration.md); tunnel credentials and listeners in the file are ignored by an agent that is already running.

## Finding the file

`cruma mcp` looks for the project file from the directory it starts in, then in each parent directory, with the same rules as `cruma up`: `cruma.yaml` before `cruma.toml` in each directory, stopping after the repository root or your home directory. `cruma mcp --project <PATH>` names the file instead. The file is attached for preview when the window connects; nothing is served until you agree. With none found, `cruma mcp` works as it does without project files. If you need a new file, the agent can create it with `attach_project` and `create: true`.

## Committing the file

Commit `cruma.yaml` or `cruma.toml` with the rest of the project so teammates, other windows and `cruma up` start the same sites. It holds no secrets, so it is safe to commit. Secrets stay in the environment, in files outside the repository, or in the project's secret store (`cruma secret set NAME`). Review the diff after an agent changes it: Cruma rewrites the file in a fixed layout, so a first rewrite can move lines around.

## Preview, apply, and what gets written

| State | What happens |
|---|---|
| Previewed (`attach_project`) | The file is read and summarized. Nothing is served and nothing is written. |
| Applied (`apply_project`, after you agree) | The project is live. Changes you ask the agent to make are also saved to the file. |

Once a project is applied, these changes made through that coding-agent window update the file:

- Sharing a port or a folder (`expose_local_port`, `expose_local_directory`) adds a hostname and its backend.
- `unexpose` removes a share it saved.
- Adding, editing or removing a hosted process changes the process entry.

Every one of these tool results says whether the change reached the file. The change itself is live either way. A previewed project is never written, and the result says to apply it first. Detaching, applying and closing the window never write the file. Only the file attached to that window can be written; the agent's own config and settings are not touched.

Shares and processes defined by the file itself are changed by editing the file, or, for processes, with `upsert_process` and `remove_process`. `unexpose` only removes shares you made through the agent.

## What is never saved

The file is meant for version control, so secrets are never written into it. A change that would carry one stays live and is not saved, and the result names the reason.

| Change | In the file |
|---|---|
| Password written as `${env:NAME}` or `${file:/absolute/path}` | Saved as the reference you wrote. The value is never written. |
| Password or process environment value written as `${file:relative/path}` | Live and not saved, because the running agent and the file would read different directories. Use an absolute path. |
| Password the agent generated, or one you typed | Not saved. The share works until it is withdrawn. Use a reference to have it saved. |
| Process environment value written as `${env:NAME}` or `${file:/absolute/path}` | Saved as written. |
| Password or process environment value written as `${secret:NAME}` | Refused: the change is not made, because a change made through the coding agent cannot read the project's secret store. Use `${env:NAME}` or an absolute `${file:}` path. |
| Process environment value written as plain text | The process runs but is not saved, because the value could be a secret. Use a reference to have it saved. |
| Folder inside the project's directory | Saved as a path relative to the file, so the project works on any machine. |
| Folder outside the project's directory | Live and not saved. The file never contains `..` or an absolute path to another place. |

A saved process without a working directory runs in the project's folder. A working directory given as an absolute path inside the project is saved relative to it. A relative one, one outside the project and one reached through `..` keep the process live and are not saved.

If a write would put any secret in the file for another reason, it is cancelled and the file stays as it was.

## What to expect from the file

- Comments are not kept. Whenever Cruma writes the file it adds a header saying so and rewrites the contents in a fixed layout. Keep notes in your README.
- Two windows attached to the same file take turns. Each change is applied to the file as it is at that moment, so edits you made by hand and changes from another window are kept.
- If the file cannot be read or is no longer valid, for example mid-edit, the change stays live, nothing is written, and the result says the file could not be read. Fix the file and repeat the change.
- A read-only file is not overwritten.

## Example

You ask your agent to share `./site` and run a dev server. The agent attaches `cruma.yaml`, shows the preview, and applies it after you agree. Then it shares the folder with a password taken from `${env:SITE_PASSWORD}` and adds a process whose token is `${env:API_TOKEN}`. The file now contains:

```yaml
# Generated by Cruma. Comments in this file are not kept when Cruma rewrites it.
backends:
- id: share-site
  kind: local-directory
  destination: site
frontends:
- hostname: site
  backend_id: share-site
  listener_kinds:
  - cruma
  middlewares:
  - type: basic_auth
    users:
    - - cruma
      - ${env:SITE_PASSWORD}
processes:
- id: dev
  command: npm
  args:
  - run
  - dev
  env:
    API_TOKEN: ${env:API_TOKEN}
```

Shares are served through the tunnel only (`listener_kinds: cruma`). Another window, or `cruma up`, brings the same project up from this file. See [Use with coding agents](https://cruma.io/book/cruma-tunnels/coding-agents.md) for the tools.

---

- Book: [Cruma Tunnels](https://cruma.io/book/cruma-tunnels.md)
- Previous: [Run Cruma in a container](https://cruma.io/book/cruma-tunnels/container.md)
- Next: [What your app receives after sign-in](https://cruma.io/book/cruma-tunnels/sign-in-headers.md)
- Pages: [Home](https://cruma.io/home.md) · [Docs](https://cruma.io/docs.md) · [Pricing](https://cruma.io/pricing.md) · [Share localhost](https://cruma.io/share-localhost.md) · [Webhook testing](https://cruma.io/webhook-testing.md) · [Homelab](https://cruma.io/homelab.md) · [AI coding agents](https://cruma.io/ai-coding-agents.md) · [Cruma vs ngrok](https://cruma.io/ngrok-alternative.md) · [Cruma vs Cloudflare Tunnel](https://cruma.io/cloudflare-tunnel-alternative.md) · [Blog](https://cruma.io/blog.md)
