Cloud Agents
environment.json for Cursor Cloud Agents: Full Reference
.cursor/environment.json defines a cloud agent's machine in code. Cursor's published schema documents ten fields: name, user, install, start, terminals, ports, repositoryDependencies, snapshot, agentCanUpdateSnapshot and build (dockerfile plus context). Agents use the config at the commit they start from, and it wins over any saved dashboard environment.
On this page
What is .cursor/environment.json?
It's the config-as-code option for cloud agent environments. Instead of saving an environment in the dashboard, you commit a JSON file at .cursor/environment.json and every agent launched against the repo builds its machine from it. Cursor resolves configuration by first match: this file, then a personal saved environment, then a team saved environment. When the file exists, it wins.
One behavior makes it unusually pleasant to work with: agents use the configuration at the commit they start from. Push a config change to a branch, start an agent from that branch, and you've tested the new environment without touching what the rest of the team runs. The setup guide covers how this fits into the two setup paths; this page is the field-by-field reference.
- Location
.cursor/environment.jsonin the repository root- Precedence
- Beats personal and team saved environments
- Versioning
- Read at the commit the agent starts from
- Syntax
- JSON with comments allowed; trailing commas rejected; unknown fields rejected
This is covered hands-on in Agent Mode Foundations — 6 short modules, free to read.
What fields does environment.json support?
The published schema defines exactly ten top-level fields, split between the base image (how the machine is built) and the runtime (what runs on it). Fields not in this table don't exist; the schema rejects unknown properties, so a typo like startup fails validation rather than being silently ignored.
- Field
name- Type
- string
- What it does
- Names the environment.
- Field
user- Type
- string
- What it does
- The user the environment runs as.
- Field
install- Type
- string
- What it does
- The update script. Runs on VM startup, after pulling latest changes, to refresh dependencies. Called the update command in the dashboard.
- Field
start- Type
- string
- What it does
- Runs when the environment starts; for processes that stay alive during the run, like
sudo service docker start.
- Field
terminals- Type
- array
- What it does
- Named terminals started for the run, each
{ name, command, description }. They run in atmuxsession shared by you and the agent.
- Field
ports- Type
- array
- What it does
- Ports to expose from the container, each
{ name, port }. The docs compare it to devcontainer port forwarding.
- Field
repositoryDependencies- Type
- array
- What it does
- Extra repos, as
github.com/org/repo, that must be included in the GitHub access token generated for the environment.
- Field
snapshot- Type
- string
- What it does
- A snapshot ID to use as the base environment. Copy it from the environment's page in the dashboard.
- Field
agentCanUpdateSnapshot- Type
- boolean
- What it does
- Whether the agent may update the snapshot.
- Field
build- Type
- object
- What it does
- Docker build options:
dockerfile(required withinbuild) andcontext, both paths relative to the.cursorfolder.
| Field | Type | What it does |
|---|---|---|
name | string | Names the environment. |
user | string | The user the environment runs as. |
install | string | The update script. Runs on VM startup, after pulling latest changes, to refresh dependencies. Called the update command in the dashboard. |
start | string | Runs when the environment starts; for processes that stay alive during the run, like sudo service docker start. |
terminals | array | Named terminals started for the run, each { name, command, description }. They run in a tmux session shared by you and the agent. |
ports | array | Ports to expose from the container, each { name, port }. The docs compare it to devcontainer port forwarding. |
repositoryDependencies | array | Extra repos, as github.com/org/repo, that must be included in the GitHub access token generated for the environment. |
snapshot | string | A snapshot ID to use as the base environment. Copy it from the environment's page in the dashboard. |
agentCanUpdateSnapshot | boolean | Whether the agent may update the snapshot. |
build | object | Docker build options: dockerfile (required within build) and context, both paths relative to the .cursor folder. |
Verified against Cursor's published JSON schema, July 2026. `snapshot` and `build` are alternatives for the base image.
Two of these deserve a closer look because their descriptions carry non-obvious detail. The terminals entries take a description field that is displayed to the agent, so it doubles as a prompt: a terminal described as 'Next.js dev server on port 3000' tells the agent what's already running and where. And repositoryDependencies is about access, not cloning: the schema describes it as repos that need to be in the environment's GitHub token, which matters when your build pulls a private sibling repo.
In what order do install, start and terminals run?
Every new machine walks the same sequence, and knowing it tells you where each command belongs. The base image comes first, from a snapshot or a Dockerfile build, and the rest layers on top.
- 1Base environment. The VM boots from your
snapshotor from the image built bybuild.dockerfile. With neither, it's Cursor's default Ubuntu base. - 2`install`. The update script runs after the latest changes are pulled. Dependency setup goes here:
pnpm install,pip install,bazel build. - 3`start`. Long-lived services the run depends on. Many repos skip it entirely.
- 4`terminals`. Each configured terminal launches in the shared
tmuxsession, in the workspace, visible to both you and the agent.
The install command has a contract: it must be idempotent, because Cursor may run it more than once and on partially cached state. There's a payoff for keeping it fast and repeatable. When install takes more than a few seconds, Cursor snapshots an internal checkpoint afterward and tries to start future agents from it, which is why a plain pnpm install usually means near-instant startups on active repos. Caching is best effort; rarely-used repos start slower.
Expensive one-off commands, like building Docker images or seeding databases, slow every startup if they live in install. Cursor's recommended pattern is cached dependency updates in install, plus a 'Cursor Cloud specific instructions' section in AGENTS.md so the agent figures out per-task commands on demand.
What does a complete environment.json look like?
Here's a Dockerfile-based config exercising most of the schema: a custom image, an idempotent install, Docker started for the run, a dev server the agent can see, and its port exposed.
{
"name": "web-app",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"install": "pnpm install",
"start": "sudo service docker start",
"terminals": [
{
"name": "dev",
"command": "pnpm dev",
"description": "Next.js dev server on port 3000"
}
],
"ports": [{ "name": "web", "port": 3000 }]
}The snapshot-based variant is shorter, because the base image is a saved VM instead of a build. This is what you typically commit after agent-driven setup, so the whole team inherits the environment.
{
"snapshot": "snapshot-20260212-00000000-0000-0000-0000-000000000000",
"install": "npm install",
"agentCanUpdateSnapshot": true
}What are the gotchas?
Most environment.json failures come from a handful of documented sharp edges rather than from the fields themselves. These are the ones worth knowing before you debug a broken setup run.
- Paths split between two roots.
build.dockerfileandbuild.contextare relative to.cursor; theinstallcommand runs from the project root. Mixing those up is the classic first failure. - Don't `COPY` the project in your Dockerfile. Cursor manages the workspace and checks out the correct commit itself; a
COPY . .bakes a stale tree into the image. - No secrets field exists. Credentials go in the dashboard's Secrets tab and arrive as environment variables. If your agent can't read one, that's its own fix path.
- Snapshots can fall back. If a snapshot expired, failed or isn't accessible to you, Cursor swaps in the default base image, keeps the rest of the config, still runs
install, and shows 'Environment ready (with warnings)'. Roll back deliberately from Version history in the dashboard settings if you need the old version. - You never get direct machine access. With Dockerfile setup, the image definition is your only lever; there is no SSH into the VM to patch things by hand.
- Layer caching works for you. Changing a Dockerfile rebuilds only the changed layers, so order slow steps first and volatile steps last.
Frequently asked questions
Does environment.json override my saved dashboard environment?
Yes. Cursor resolves configuration by first match: .cursor/environment.json in the repo, then a personal saved environment, then a team saved environment. Committing the file makes it the source of truth for that repo.
Where do I find a snapshot ID for environment.json?
On the environment's page in the Cloud Agents dashboard. After agent-driven setup you can save a snapshot of the machine, and the resulting ID is what the snapshot field references.
How do I test a new environment.json without breaking the team?
Commit the change to a branch and start a cloud agent from that branch. Agents read the config at the commit they start from, so the main branch and every saved environment stay untouched while you verify the new setup.
Can environment.json hold API keys or database credentials?
No. The schema has no secrets field, and the file is committed to your repo in plaintext. Use the Secrets tab in the Cloud Agents dashboard, which encrypts values and exposes them to the agent as environment variables.
Sources & last verified
Cursor ships frequently. Facts verified against primary sources on July 16, 2026.