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

# Dev environment

> Configure how Capy prepares and maintains project VMs with Setup scripts, commands, environment variables, and snapshots.

Every Build and Captain run happens in an isolated VM. **Setup** defines how
Capy prepares and maintains that VM: which branches to use, which scripts run
automatically, which commands agents can invoke, and how much compute the VM
receives.

Configure it at **Settings → Project → Dev environment**.

<Note>
  Review runs use a separate, fixed environment: a Medium VM with only the pull
  request checkout. Project Setup scripts, Commands, tool hooks, environment
  variables, VM size, and Snapshots do not apply to Review.
</Note>

## Let Captain manage it

You do not have to write Setup by hand. Captain inspects your repositories and
configures the environment for you.

<Steps>
  <Step title="Start from settings or chat">
    Open **Settings → Project → Dev environment** and click **Set up with
    Captain** — or tell Captain in any thread: *"Set up this project's dev
    environment."*
  </Step>

  <Step title="Captain writes and saves Setup">
    Captain reads package manifests, lockfiles, READMEs, and agent instructions
    for every attached repository. It chooses lifecycle scripts, useful
    commands, and a fitting VM size, then saves Setup for future runs.
  </Step>

  <Step title="Captain validates it">
    Captain starts a fresh validation run, exercises the configured environment,
    and fixes Setup if anything fails.
  </Step>
</Steps>

Already have Setup? **Improve with Captain** reviews it against the current
state of your repositories.

Saved changes apply to future runs immediately. The **History** section records
changes made by people and Captain.

## Manual setup

Open a repository from **Setup & commands** to edit its base branch, lifecycle
scripts, per-script timeouts, and named Commands. Tool hooks and VM size are
configured on the main Dev environment page.

The equivalent Setup object looks like this:

```json theme={null}
{
  "vmSize": "medium",
  "repositories": [
    {
      "repository": "acme/app",
      "branch": "main",
      "scripts": {
        "initialize": "pnpm install --frozen-lockfile",
        "updateAfterCheckout": "pnpm install --frozen-lockfile",
        "startup": "nohup pnpm dev >/tmp/dev.log 2>&1 &"
      },
      "timeouts": {
        "initialize": 900,
        "updateAfterCheckout": 300,
        "startup": 300
      },
      "commands": [
        { "name": "Check", "command": "pnpm check" },
        { "name": "Test", "command": "pnpm test" }
      ]
    }
  ]
}
```

Scripts are optional. Leave a script empty when that lifecycle phase has no
work to do.

## What Setup defines

| Section          | What it controls                                            |
| ---------------- | ----------------------------------------------------------- |
| **VM size**      | Compute resources allocated to Build and Captain runs       |
| **Repositories** | Per-repo base branch, lifecycle scripts, and named commands |
| **Tool hooks**   | Optional commands that run before/after agent tool calls    |

Environment variables and Snapshots are configured alongside Setup and are covered below.

## Mental model

| Concept             | What it is                                                              |
| ------------------- | ----------------------------------------------------------------------- |
| **Setup**           | The source of truth for branches, scripts, Commands, hooks, and VM size |
| **Run preparation** | The lifecycle Capy selects for each repository before the agent works   |
| **Snapshot**        | An optional cached VM produced from Setup to avoid repeating Initialize |

Setup is always authoritative. Snapshots cache its results; they do not replace
it. Run preparation reconciles whichever VM Capy obtains with the active Setup
and requested checkout.

## How a run becomes ready

Before the agent starts working, Capy:

1. Allocates a new VM, restores a snapshot, or resumes the thread's existing VM.
2. Loads shared project environment variables. When a VM is prepared for a run
   you start, your [personal variables](#environment-variables) are layered
   afterward and override shared variables with the same name.
3. Refreshes GitHub credentials and attaches each repository at the requested
   branch and commit.
4. Selects the required Setup path for each repository based on the VM's saved
   state, active Setup revision, and current checkout.
5. Runs the selected scripts. A Build agent becomes ready only after every
   blocking script succeeds.

Shared environment variables and credentials are refreshed after restoring or
resuming cached VM state. A snapshot is never the authority for those values.

## Lifecycle scripts

Each repository has three automatic scripts:

| Script                    | Purpose                                                               | Default timeout |
| ------------------------- | --------------------------------------------------------------------- | --------------- |
| **Initialize**            | Prepare a repository on a new VM, after cloning and environment setup | 15 min          |
| **Update after checkout** | Maintain dependencies after a reused environment moves to new code    | 5 min           |
| **Startup**               | Start services required for the run after repository preparation      | 5 min           |

The path is selected per repository:

| Environment state                                        | Automatic scripts               |
| -------------------------------------------------------- | ------------------------------- |
| New VM or repository not previously prepared             | Initialize → Startup            |
| Existing VM after Setup changes                          | Initialize → Startup            |
| Existing VM after its requested branch or commit changes | Update after checkout → Startup |
| Existing VM with the same Setup revision and checkout    | Startup                         |
| Snapshot build                                           | Initialize, then capture        |
| Run restored from a snapshot with a changed checkout     | Update after checkout → Startup |
| Run restored from a snapshot with the captured checkout  | Startup                         |

The same phase runs across independent repositories in parallel, but phases
remain ordered: all selected Initialize work finishes before Startup begins.

### Initialize

Use Initialize for work needed to make a clean repository usable:

* Install language runtimes, system packages, and global tools
* Authenticate a private package registry before the first dependency fetch
* Install project dependencies
* Compile native dependencies or generate required artifacts

Initialize runs from the repository directory with environment variables loaded.
It also runs while building a snapshot. It does not run again on every unchanged
resume.

```bash Initialize example theme={null}
node scripts/setup-npm-auth.js && pnpm install --frozen-lockfile
```

If dependency installation requires authentication, bootstrap credentials
explicitly before invoking the package manager. A package-manager `preinstall`
hook cannot authenticate the dependency fetch that must happen before the hook
is available.

### Update after checkout

Update after checkout is the maintenance phase. It repairs a prepared VM after
Capy checks out a different branch or commit. Keep it fast and safe to rerun:

* Synchronize dependencies from the current lockfile
* Regenerate code derived from the checkout
* Apply local, idempotent schema preparation needed by the development stack
* Refresh repository-scoped configuration

```bash Update after checkout example theme={null}
pnpm install --frozen-lockfile
```

Capy records the repository, requested branch, resolved commit, Setup revision,
and whether maintenance completed successfully. It skips Update after checkout
when those inputs still match the last successful preparation. A changed
checkout or an unsuccessful previous preparation causes it to run again.

Do not duplicate an expensive bootstrap in both Initialize and Update after
checkout unless both clean and reused environments genuinely require it.

### Startup

Startup runs after the selected preparation phase whenever the run needs its
services started. Use it for development servers, local databases, and other
processes that must be available while the agent works.

Startup is blocking, so the script itself must exit. Launch long-running
processes in the background and wait until they are ready:

```bash Startup example theme={null}
nohup pnpm dev >/tmp/dev.log 2>&1 &
for attempt in {1..30}; do
  curl -fsS http://127.0.0.1:3000 >/dev/null && exit 0
  sleep 1
done
exit 1
```

Startup runs again when an existing VM resumes. Make the script idempotent:
reuse a healthy service or replace stale processes instead of starting
duplicates.

### Execution and failures

Scripts run:

* From the corresponding repository directory
* In Bash with `set -e`
* With shared and applicable personal environment variables loaded
* With root access inside the isolated VM
* With configurable timeouts from 60 to 3600 seconds

An exit code other than zero, a timeout, or a transport failure fails the phase.
Build runs stop before the agent starts and show **Setup failed**. Captain
threads receive the failure and continue in a degraded environment so Captain
can inspect and repair Setup.

The VM status menu shows live and most recently recorded Setup steps, including
the repository, phase, duration, and result.

## Multiple repositories

All repositories in a run share one VM but have separate working directories.
Within a lifecycle phase, their scripts execute in parallel. The next phase
starts only after the current phase succeeds for every configured repository.

Avoid scripts that depend on another repository finishing first. If repositories
need the same global tool or system package, make the installation idempotent
and safe under concurrent execution. Repository-specific dependency work should
stay in that repository's script.

## Commands

Commands are named, opt-in actions agents can run while working — build, test, lint, typecheck. They never run automatically during Setup; agents invoke them when relevant.

| Name       | Command            |
| ---------- | ------------------ |
| Type check | `pnpm check-types` |
| Test       | `pnpm vitest run`  |
| Build      | `pnpm build`       |

Keep Commands executable and specific. Prose guidance ("always run lint before committing") belongs in [agent instructions](/configs/instructions), not Commands.

## Tool hooks

Setup can define commands that run before or after specific agent tools. Tool
hooks are useful for policy checks and lightweight automatic formatting:

```json theme={null}
{
  "pre": {
    "bash_run": ["echo 'About to run command'"]
  },
  "post": {
    "edit": ["pnpm prettier --write ${file_path}"],
    "write": ["pnpm prettier --write ${file_path}"]
  }
}
```

Available tools: `bash_run`, `edit`, `multi_edit`, `write`, `read`, `glob`, `grep`.

## VM size

| Size   | CPU      | RAM   | Disk  | Cost/hour |
| ------ | -------- | ----- | ----- | --------- |
| Small  | 2 cores  | 4 GB  | 20 GB | \$0.30    |
| Medium | 4 cores  | 8 GB  | 30 GB | \$0.60    |
| Large  | 8 cores  | 16 GB | 40 GB | \$1.20    |
| Ultra  | 16 cores | 32 GB | 50 GB | \$2.40    |
| Hyper  | 16 cores | 64 GB | 50 GB | \$3.00    |

Small is the default and works for most tasks. Use larger sizes for heavy builds, large test suites, or resource-intensive compilation. Changes apply to the next run.

## Environment variables

Configure variables at **Settings → Project → Environment variables**:

* **Shared** variables are available to every project run.
* **Personal** variables are available only in project runs you start. A
  personal value overrides a shared variable with the same name.

Shared variables are available during snapshot builds. Personal variables are
not stored in snapshots; Capy injects them when preparing the VM for your run.
When a VM resumes, Capy refreshes shared project variables before lifecycle
scripts execute.

You can add key-value pairs directly or paste a full `.env` file.

<Warning>
  Environment variables are available to the agent during task execution. Only
  provide secrets you're comfortable sharing with the agent. Never put secret
  values inside Setup scripts — reference them as variables instead.
</Warning>

## Snapshots

<Note>
  Environment Snapshots are currently available to select Enterprise customers.
  [Contact us](https://cal.com/team/capy/enterprise) to request access for your
  organization.
</Note>

Snapshots cache a prepared VM so later runs can avoid repeating Initialize.
Enabling Snapshots requires a saved Setup.

A snapshot build:

1. Starts a clean VM at the configured size.
2. Injects shared project environment variables and GitHub credentials.
3. Clones each configured repository at its base branch.
4. Runs Initialize for each repository.
5. Removes platform-managed environment files, credentials, session tokens, and
   transient runtime state before capturing the VM.

<Warning>
  Capy removes platform-managed secret files before capture, but it cannot know
  every path your scripts write. If Initialize writes a secret into another
  file, that file can persist in the snapshot. Keep credentials in environment
  variables and avoid writing secret values to disk.
</Warning>

When a run restores that snapshot, Capy injects current credentials and
environment variables, checks out the requested code, runs Update after checkout
only where the captured checkout no longer matches, and then runs Startup.

From the **Snapshots** section of the Dev environment page you can:

* **Enable Snapshots** — reuse a matching current snapshot, start the first
  build immediately, or queue it behind a build already in progress.
* **Set the rebuild schedule** — snapshots refresh automatically every 1, 2, 4,
  or 8 hours to keep dependencies current.
* **Trigger a build manually** — rebuild on demand after changing Setup.
* **Test a snapshot** — run the full capture, restore, and warm-up lifecycle
  without promoting the result.
* **Inspect build history** — every build has logs and status (ready, building, stale, or failed).

Snapshot builds are triggered by enabling Snapshots, a manual rebuild, a
snapshot test, or the configured 1, 2, 4, or 8 hour refresh schedule. Saving
Setup does not block on a snapshot build; rebuild after a Setup change when you
want new runs to use the updated cached state.

| Status       | Meaning                                                        |
| ------------ | -------------------------------------------------------------- |
| **Building** | A new snapshot is being prepared                               |
| **Ready**    | A current snapshot is available for new runs                   |
| **Stale**    | The cached artifact no longer matches the required environment |
| **Failed**   | The latest build failed; inspect its step logs                 |

Snapshots are an optimization, never a requirement: Setup stays the source of truth, and if no current snapshot is available a run falls back to fresh provisioning with the same Setup.

## Troubleshooting

### Initialize fails

Inspect the failing repository and phase in the VM status menu, then open that
repository's Setup to inspect the configured command. For snapshot builds,
inspect the build logs. Common causes are missing package-manager authentication,
an interactive installer, an unavailable system package, or a timeout.

### Update after checkout fails

Run the command against the checked-out branch and current lockfile. Maintenance
must be safe to repeat after a failed attempt. Prefer incremental dependency
repair over deleting and rebuilding the entire environment.

### Startup times out

The Startup script must return. Background long-running processes, add a bounded
readiness check, and fail clearly when the service never becomes healthy. Also
make Startup idempotent so a resumed VM does not accumulate duplicate servers.

### A snapshot build fails

Open the build from **Settings → Project → Dev environment → Build history** and
inspect the first failed step. Fix Setup, use **Test snapshot** to exercise the
capture and restore lifecycle without promotion, then rebuild.

### Iterate with Captain

Click **Improve with Captain** or ask Captain to inspect the failure. Captain can
read Setup, the repositories, and build state, save a correction, and start a
fresh validation run.

## Migrating from `.capy/settings.json`

Repository hooks in `.capy/settings.json` are deprecated. Once any Setup exists
for the project, those hooks are ignored. Carry over any setup commands and tool
hooks you still need before saving; Captain detects and migrates them when it
configures the project.

The Dev environment page shows whether Setup, deprecated repository hooks, or
default behavior is currently authoritative.

## Manage via API

Everything on this page is also scriptable: read and save Setup with [`GET /setup`](/api-reference/setup/get-setup) and [`PATCH /setup`](/api-reference/setup/update-setup), and control snapshot state through the [Snapshots API](/api-reference/snapshots/overview). See the [Setup API overview](/api-reference/setup/overview) for the full object shape.
