Environments
environments/ defines project setup for a new Git worktree (a separate checkout of the same repository), cloud sandbox, or preview. Use it to install dependencies, copy local config, start a dev server, and stop it afterwards. Sync writes each tool's native file, such as .cursor/worktrees.json, .codex/environments/environment.toml, or .claude/launch.json.
Write one
agnostic-ai new environment development
It creates .agnostic-ai/environments/development.yaml with no commands. Add the commands you have reviewed, and create any script they call before syncing:
name: dev
setup: bash scripts/setup-worktree.bash
cleanup: bash scripts/stop-preview.bash
dev-commands:
- name: Docs
command: [pnpm, dev:mintlify]
cwd: apps/docs
port: 3000
auto-port: true
A sandbox that runs an install step and keeps a terminal open (Cursor, OpenHands, Amp). Cursor runs install each time its VM starts, and Amp runs it again when it refreshes a snapshot, so make it safe to repeat:
install: go mod download
terminals:
- name: dev
command: go run ./cmd/agnostic-ai
Fields
setup: the commands a tool runs in a new worktree (one command or a list).setup-windowsreplaces it on Windows.cleanup: the commands a tool runs when it removes the worktree.installandterminals: a sandbox's install step and its long-running processes.dev-commands: dev servers a tool can start and preview. Each entry needs a uniquenameand acommand(a string or a list of words).cwd(relative to the project root),port,auto-port,env,url, andicon(the Codex button icon,runby default) are optional. An entry with aurland nocommandtells Claude Code to open a server you already run instead of starting one; Codex has no such action, so sync skips the entry there with a note.A string command with shell syntax (pipe, several lines,
VAR=value, a builtin likecd) runs throughsh -c, which on Windows needs a POSIX shell such as Git Bash on thePATH. A list runs with no shell.envvalues are written as text.Specs merge by top-level key, and the last value wins. A field that no enabled tool uses gets a no-effect note.
lintreports a dev command with noname, with neithercommandnorurl, a repeated name, an unknown key, or a value of the wrong type (LINT016). It also reports aurlentry with nocommandthat reaches Codex, and names the target. Give Codex its own list without that entry underx-codex.dev-commands.
Support by target
Fields a tool does not use get a no-effect note. Other tools report the spec as unsupported. Each tool's page has the key mapping.
| Target | Uses | Writes |
|---|---|---|
| Cursor | setup, setup-windows; every other key except name, scope, description, the target fields, dev-commands, and cleanup | .cursor/worktrees.json, .cursor/environment.json |
| Codex | setup, setup-windows, cleanup, dev-commands (as scripts and action buttons) | .codex/environments/environment.toml |
| Claude Code | setup (worktree setup), dev-commands (a relative cwd reads from the project root, so no ${workspaceFolder}) | .claude/hooks/agnostic-ai-worktree-setup.sh, .claude/launch.json |
| OpenHands | install (a setup script) | .openhands/setup.sh |
| Amp | install (a setup script), terminals (services) | .agents/setup, .amp/services.yaml |
| Ellipsis | install as hooks.build_base, setup as hooks.after_checkout, each after cd /sandbox/<repository>, only for the environment x-ellipsis.environment selects | .ellipsis/environments/<name>.yaml |
import cursor, import codex, and import ellipsis read their files back. After installation and sync, run the project readiness checks before starting a cached environment. Installation alone does not check generated files.
Claude Code worktree setup
Claude Code has no setup step for a worktree it creates (worktrees), so sync writes setup into .claude/hooks/agnostic-ai-worktree-setup.sh and runs it from three hooks in .claude/settings.json:
SessionStartwith matcherstartup, forclaude --worktreeand Desktop worktree sessions.SubagentStart, for a subagent withisolation: worktree.SessionStartdoes not fire for a subagent.PostToolUsewith matcherEnterWorktree, for a worktree Claude enters during a session.
Each hook sets shell: bash, so on Windows the script needs Git Bash, or setup does not run. A checkout without the script, such as a worktree created before the first sync, skips the hook. Claude Code runs matching hooks in parallel, so delete a hand-written SessionStart hook that installs the same dependencies.
How the script runs:
- It takes the worktree from the
cwdin the hook's event data, because$CLAUDE_PROJECT_DIRstays at the directory the session started in. - It runs
setupfrom the worktree root throughsh, only in a linked Git worktree, never in the main checkout. - A successful run leaves a marker in the worktree's own Git directory, so later sessions there skip setup. A failed run, or a worktree made before the first sync with
setup, has no marker, so the next session, subagent, or worktree entry runs it. - Claude Code stops a command hook after 600 seconds by default, so a longer setup fails and runs again next time.
- Setup output goes to stderr, because Claude Code adds a
SessionStarthook's stdout to the session context. - The script exits when
AGNOSTIC_AI_TARGETis notclaude. A tool that also reads the hooks in.claude/settings.json, such as Cursor, then does not run setup a second time.
Refresh an existing worktree
After changing setup or dependencies, sync one worktree and rerun its Claude setup:
agnostic-ai hook worktree-refresh --repo /path/to/main --worktree "/path/to/linked worktree"
It resets only that linked worktree's marker and runs setup again; a failure leaves no marker. See worktree refresh for what it checks and refuses.
Include setup in new worktrees
A new worktree needs .claude/settings.json and the script.
- With
gitignore.enabled, both are ignored..worktreeinclude, which sync keeps whenclaudeis a target, copies them into each worktree Claude Code creates (see gitignore). - Without it, both files are committed, so the checkout has them.
To keep setup for the other tools and set up Claude Code another way, turn the hooks off:
setup: composer install
x-claude:
setup: false
Claude cleanup limits
cleanup has no Claude Code equivalent. Claude Code documents WorktreeRemove as the removal step for a worktree a WorktreeCreate hook made. SessionEnd runs at the end of every session with a 1.5-second budget.
Import
When several tools keep their own environment file, import limits each spec to its tool with targets: [<tool>], so the next sync writes every file back as it was. Remove the line to share a spec. A project with one tool's environment file gets one shared spec.