On this page
- JSON Schema
- Minimal Manifest
- Full Schema
- version
- platform
- image
- sources
- env
- setup
- services
- commands
- ready
- simulators
- ios
- agent
- mounts
- callbacks
- secrets
- docker_compose
- Health Check Format
- Port Definitions
- Service Dependencies
- Secret references
- What Gets Auto-Injected
- Configuration Layering
- Examples
- Node.js Web App with PostgreSQL
- Python Django Project
- iOS App with Simulator
- Multi-Repo Setup
Manifest Reference
Published
Updated
The Agent Environment Spec (AES) manifest is a declarative definition of a VM environment. It specifies the platform, source repositories, setup commands, services, health checks, commands, and agent configuration. Public API VMs boot from environments; store the manifest on an environment, then create VMs or sessions from that environment.
Wallfacer uses manifests at every level: base images, environment snapshots, and session boot all derive from the same format.
JSON Schema
The manifest is formally described by a JSON Schema (Draft 2020-12). The public API validates every submitted manifest against it, then applies additional API checks such as environment permissions, snapshot state, and missing secret references.
Stable URL
https://wallfacer.dev/schemas/aes/v1.jsonThis URL is permanent for the lifetime of version 1. Backwards-compatible additions edit the file in place. Breaking changes publish at a new URL (v2.json, and so on).
Editor integration
Point your editor at the schema URL and you get completion, validation, and inline docs while you write the manifest.
VS Code YAML (via the Red Hat YAML extension), .vscode/settings.json:
{
"yaml.schemas": {
"https://wallfacer.dev/schemas/aes/v1.json": [
"agent-env.yml",
"agent-env.yaml"
]
}
}VS Code JSON (.vscode/settings.json):
{
"json.schemas": [
{
"fileMatch": ["agent-env.json"],
"url": "https://wallfacer.dev/schemas/aes/v1.json"
}
]
}JetBrains IDEs support the same schema via Preferences > Languages & Frameworks > Schemas and DTDs > JSON Schema Mappings.
Minimal Manifest
The smallest schema-valid manifest specifies the version. In practice, set platform.os explicitly so the environment is portable and obvious:
{
"version": 1,
"platform": {
"os": "linux/amd64"
}
}This boots a Linux VM with default resources, no repositories, no setup, and no services beyond the automatically injected agent-api.
Full Schema
version
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
version | integer | yes | -- | Manifest schema version. Currently 1. |
platform
Declares the compute platform and resource requirements.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
os | string | no | server default | Target OS. linux/amd64 or darwin/arm64. Set this explicitly for predictable environments. |
memory | integer | no | 8192 | Memory in MB. Set automatically by the server; cannot be overridden by users. |
vcpus | integer | no | 2 | Virtual CPU count. Set automatically by the server; cannot be overridden by users. |
gpu | boolean | no | false | Reserve GPU access. Set automatically by the server; cannot be overridden by users. |
platform:
os: darwin/arm64image
Optional base image and OS tuning.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
base | string | no | platform default | Base image identifier, including a version tag. |
system.file_descriptor_limit | integer | no | base image default | Max open file descriptors per process. |
system.spotlight | boolean | no | -- | Disable Spotlight indexing. macOS only. |
system.tcc.apple_events | array of strings | no | [] | Binaries pre-authorized to send AppleEvents. macOS only. |
system.tcc.accessibility | array of strings | no | [] | Binaries pre-authorized for accessibility automation. macOS only. |
system.locale | string | no | en_US.UTF-8 | System locale. |
sources
Git repositories to clone into the environment. Always an array, even for a single repo. Each source is cloned during snapshot construction; boot-time source reconciliation is managed by the platform.
The first entry's workspace is the primary workspace (default working directory for commands and Claude Code).
The deprecated source field accepts one source object as shorthand. Prefer sources for new manifests.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
repo | string | yes | -- | Git repository. Short form (owner/repo) or full URL (github.com/owner/repo). |
auth | string | no | token | Authentication method: token or ssh-key. Credentials are injected at session time, never stored in the manifest. |
workspace | string | no | {root}/{reponame} | Absolute path where the repo is cloned. Defaults to /workspace/{reponame} (Linux) or /Users/admin/workspace/{reponame} (macOS). |
branch | string | no | repository default | Omit to follow the repository default at snapshot generation, or name a branch to pin it. |
clone_strategy | string | no | shallow | shallow (--depth 1 --single-branch, fast) or full (complete history). Use full only if the agent needs git log or blame. |
identity.name | string | no | -- | Git commit author name. |
identity.email | string | no | -- | Git commit author email. |
sources:
- repo: github.com/acme/webapp
workspace: /Users/admin/workspace
branch: main
auth: token
clone_strategy: shallow
identity:
name: Wallfacer Agent
email: [email protected]Multi-repo example:
sources:
- repo: github.com/acme/frontend
workspace: /workspace/frontend
branch: main
- repo: github.com/acme/api
workspace: /workspace/api
branch: developEach source is cloned into its own workspace path. The first source's workspace is the primary working directory for commands and agent interaction unless a command or service sets working_dir.
When you omit branch, Wallfacer uses the repository default and updates the manifest if that default changes before the next snapshot generation. A branch you name is pinned, even if it currently matches the default. Wallfacer rejects a new or changed pin that is missing with 422 missing_branch. If a pinned branch disappears later, snapshot generation fails with the same error instead of switching branches. The structured response identifies repo, branch, and up to 100 available branches. Its human-readable message lists at most ten names. Choose an existing branch in the manifest. Empty repositories accept any branch.
If a pinned branch disappears after the manifest is saved and a VM reaches the clone step, the clone fails immediately instead of retrying. Its failure reason names the requested branch, repository, and available remote branches; the source clone status records the same reason. Update the pin to an existing branch and regenerate the snapshot.
env
Global environment variables available to all setup commands, services, and named commands.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| (key) | string | -- | -- | Variable name mapped to its value. |
${secrets.KEY} references are valid in any string field anywhere in the manifest and are substituted by the platform before the manifest is delivered to your VM. See Secret references for the full contract, including how missing secrets are rejected.
Setup commands can emit ::set-env name=VALUE on stdout to publish ${VAR} values that persist across subsequent setup commands and services.
env:
NODE_ENV: development
DATABASE_URL: postgres://user:${secrets.DB_PASSWORD}@localhost:5432/app
NPM_TOKEN: ${secrets.NPM_TOKEN}setup
Sequential commands executed during snapshot construction. Each must complete (exit 0 or pass its healthcheck) before the next runs. Setup commands are baked into the snapshot and not re-run on session restore.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | -- | Human-readable label. |
run | string | yes | -- | Shell command (executed via bash -c). |
working_dir | string | no | first source workspace | Working directory. |
env | object | no | {} | Command-specific env vars (merged with global env). |
retries | integer | no | 2 | Retry count on failure. |
healthcheck | object | no | -- | Verification after command completes. See Health Check Format. |
setup:
- name: Install project dependencies
run: npm install
retries: 2
healthcheck:
command: test -d node_modules
retries: 3
- name: Build project
run: npm run buildOn Linux, setup commands are automatically wrapped with sudo -E bash -c '...' so they have access to package management. On macOS, sudo is not used because Homebrew refuses to run under sudo.
services
Long-running background processes supervised by the in-VM agent. Services are launched concurrently but respect depends_on ordering via topological sort. Each service waits for its dependencies' health checks to pass before starting.
Services do not survive snapshot/restore. They are killed and restarted fresh on every boot.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | -- | Unique service name. |
run | string | yes | -- | Shell command to start the service. |
working_dir | string | no | first source workspace | Working directory. |
env | object | no | {} | Service-specific env vars (merged with global env). |
depends_on | array of strings | no | [] | Service names that must be healthy before this one starts. |
ports | array of objects | no | [] | Ports to expose. See Port Definitions. |
healthcheck | object | no | -- | Readiness probe. See Health Check Format. |
services:
- name: database
run: docker compose up postgres
healthcheck:
url: tcp://localhost:5432
- name: dev-server
run: npm run dev
depends_on: [database]
ports:
- port: 3000
name: web
protocol: http
healthcheck:
url: http://localhost:3000/healthcommands
Named, reusable command blocks. Commands can be invoked by the platform in these ways:
- Lifecycle -- via the
readyarray (runs after services are healthy, every boot) - HTTP API -- via the in-VM command API
- Platform tooling -- for diagnostics and infrastructure operations
Every command execution fires webhook events (command.started, command.completed, command.failed).
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| (key) | string | yes | -- | Command name (the YAML/JSON key). Must be unique. Used in the ready array and API calls. |
run | string | yes | -- | Shell command (executed via bash -c). |
working_dir | string | no | first source workspace | Working directory. |
env | object | no | {} | Command-specific env vars (merged with global env). |
timeout | duration | no | 30m | Maximum execution time. |
retries | integer | no | 1 | Retry count on failure. |
commands:
migrate:
run: npm run db:migrate
working_dir: /workspace
seed:
run: npm run db:seed
working_dir: /workspace
reset-db:
run: npm run db:reset && npm run db:seed
working_dir: /workspace
timeout: 5mready
An array of command names from the commands block. These run sequentially after all services are healthy, on every boot (both fresh build and snapshot restore).
Use ready for idempotent operations that depend on running services: database migrations, cache clearing, dependency updates that catch drift from code changes since the snapshot was built.
commands:
migrate:
run: npm run db:migrate
working_dir: /workspace
seed:
run: npm run db:seed
working_dir: /workspace
ready: [migrate, seed]Heavy installation belongs in setup (baked into the snapshot). The ready array is for lightweight operations that should re-run every session.
simulators
iOS/Android simulator configuration. Only valid when platform.os is darwin/arm64. Each entry boots a simulator, starts a capture service, and optionally registers build/run commands.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
platform | string | yes | -- | Simulator platform: ios (future: android). |
device | string | no | iPhone 18 Pro | Device name. Defaults to the configured device when omitted. |
runtime | string | no | latest | iOS version or latest. A selected version is preserved when the environment is saved. |
bundle_id | string | no | -- | App bundle ID. Used to verify the app launched in the simulator. Exposed as $IOS_BUNDLE_ID. |
build | string | no | -- | Compile, install, and launch script (Swift, native). Generates a build-ios command. |
run | string | no | -- | Start a dev server pointed at the simulator (Expo). Generates a run-ios command. |
Set runtime: latest to select the newest installed iOS runtime that supports the selected device. For example, if a newer runtime supports only another device, Wallfacer uses the newest compatible runtime instead. The stored manifest keeps latest, so an image with newer compatible runtimes can use them without changing the manifest. If no installed runtime supports the device, simulator startup fails with an error naming the device and installed runtime versions. Set a specific version to pin it; the simulator fails to start if that runtime is not installed or does not support the device. The platform fills in omitted values without replacing selections you provide.
The default device is iPhone 18 Pro on the Xcode 27.1 macOS image. A deployment with an IOS_SIMULATOR_DEVICE override uses that configured device instead. Existing saved iOS simulator entries naming iPhone 17 Pro are updated to the configured device, including entries that stored the former default. Entries naming another device and non-iOS entries keep their device selections. A macOS VM still using the Xcode 26.5 image cannot create the new default device; reprovision it onto the Xcode 27.1 image before booting the simulator.
The app's runtime picker currently offers only 26.4. To use latest or another installed runtime, edit the environment manifest directly. Selecting 26.4 fails when the current macOS image does not include it.
What the platform does with each entry:
- Boots the simulator via
xcrun simctl - Starts SimulatorCapture as a supervised service on port 8000
- Exposes
$IOS_SIMULATOR_UDIDand$IOS_BUNDLE_IDas env vars - If
buildis set, registers abuild-ioscommand (re-triggerable mid-session) - If
runis set, registers arun-ioscommand - If
bundle_idis set, waits for the app to appear in the simulator (2-minute timeout) - Registers the simulator MCP server in Claude Code settings
# Swift project (compile + install + launch):
simulators:
- platform: ios
bundle_id: com.acme.app
build: |
xcodebuild -project App.xcodeproj -scheme App \
-destination "id=$IOS_SIMULATOR_UDID" build
xcrun simctl install $IOS_SIMULATOR_UDID \
.build/Build/Products/Debug-iphonesimulator/App.app
xcrun simctl launch $IOS_SIMULATOR_UDID com.acme.app# Expo project (dev server pointed at simulator):
simulators:
- platform: ios
bundle_id: com.acme.app
run: npx expo run:ios --device $IOS_SIMULATOR_UDID --no-bundleriOS simulator and its commands run asynchronously after the VM is declared ready, so they do not block session start.
ios
Deprecated single-simulator block kept for older manifests. Prefer simulators for new manifests.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
device | string | no | server default | Device model name. |
runtime | string | no | server default | iOS runtime version. |
headless | boolean | no | true | Run the simulator in headless mode. |
bundle_id | string | no | -- | App bundle identifier. |
build | string | no | -- | Build, install, and launch script. |
timeout | duration | no | 30m | Max build duration. |
ports | array | no | [] | Ports exposed by the simulator capture service. |
agent
Configures Claude Code inside the VM: the instruction files it loads.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
instructions | array of strings | no | [] | Paths to instruction files relative to the workspace (e.g. .claude/CLAUDE.md). Written to Claude Code's settings. |
Claude Code loads the tool definitions from these servers on demand. It starts a turn knowing the tool names and fetches a tool's full schema before calling it, instead of carrying every schema in context from the first message. An environment that registers several MCP servers therefore leaves more of the context window for the work. The agent still reaches every tool declared here; only the moment the schema is read changes. The platform's own servers load on demand the same way, so nothing you declare here changes how they behave.
agent:
instructions:
- .claude/CLAUDE.md
- docs/ARCHITECTURE.mdMCP servers are not declared here. They are a field on the environment, mcp_servers, edited in the app or through the API, and changing them never regenerates the snapshot. See Environments for the three kinds and Environments and Secrets for the API shape.
When simulators are configured, the platform auto-registers a simulator MCP server pointing to SimulatorCapture.
mounts
S3 buckets attached to the VM's filesystem, so files an agent writes survive the machine. Optional, at most four, and Linux only: a manifest that declares mounts on darwin/arm64 is rejected. See Mounted S3 Storage for how they attach and how uploads are flushed before teardown.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
at | string | yes | -- | Absolute mountpoint inside the VM. No .. segments, unique per manifest, and under /mnt, /workspace, /app, or /home/appuser without being one of those roots. |
bucket | string | yes | -- | Bucket name. |
credentials | object | yes | -- | access_key_id and secret_access_key are required; session_token for STS credentials. Use ${secrets.KEY} references. |
region | string | conditional | -- | Required unless endpoint is set. |
endpoint | string | no | https://s3.<region>.amazonaws.com | S3-compatible endpoint. Must start with https://. |
name | string | no | last segment of at | Log and status name. Lowercase letters, digits, hyphens; up to 32 characters. |
prefix | string | no | whole bucket | Mount one key prefix instead of the entire bucket. |
read_only | boolean | no | false | Mount without write access. |
mounts:
- name: artifacts
at: /mnt/artifacts
bucket: acme-agent-artifacts
prefix: nightly/
region: us-east-1
credentials:
access_key_id: ${secrets.S3_ACCESS_KEY_ID}
secret_access_key: ${secrets.S3_SECRET_ACCESS_KEY}callbacks
Webhook event filtering. Optional. If omitted, the platform uses the WEBHOOK_URL and WEBHOOK_TOKEN environment variables (injected per-session by the platform).
The manifest callbacks section takes precedence over env vars when set.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | no | -- | Webhook endpoint URL. Supports ${secrets.KEY} substitution. |
auth | string | no | -- | Authorization header value (e.g. bearer ${secrets.WEBHOOK_TOKEN}). Supports ${secrets.KEY} substitution. |
events | array of strings | no | all | Event types to send. If omitted, all events are sent. |
callbacks:
url: ${WEBHOOK_URL}
auth: bearer ${WEBHOOK_TOKEN}
events:
- environment.ready
- environment.failed
- command.completed
- command.failedsecrets
Secrets are referenced using ${secrets.KEY} syntax. References are valid in any string field anywhere in the manifest, and are substituted with their plaintext values by the platform before the manifest is delivered to your VM. See Secret references below for the full contract.
env:
NPM_TOKEN: ${secrets.NPM_TOKEN}
DATABASE_URL: postgres://user:${secrets.DB_PASSWORD}@localhost:5432/app
STRIPE_KEY: ${secrets.STRIPE_SECRET_KEY}
services:
- name: web
run: node server.js --auth=${secrets.WEB_AUTH}
env:
ANALYTICS_KEY: ${secrets.ANALYTICS_KEY}
healthcheck:
url: http://localhost:3000/health?token=${secrets.HEALTH_TOKEN}You do not declare secrets in the manifest itself; the platform's secret store is the source of truth. Manage secrets through the platform's secrets API (one per environment).
docker_compose
Alternative to setup/services/commands for Docker Compose-based projects. Mutually exclusive with the standard mode fields.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
app_service | string | yes | -- | Primary service name in docker-compose.yml. |
setup | array of strings | no | [] | Commands to run before docker-compose up. |
exec | array of strings | no | [] | Commands to run inside app_service after services are up. |
docker_compose:
app_service: app
setup:
- cp .env.example .env
exec:
- php artisan migrate
- php artisan db:seedHealth Check Format
Health checks verify that a setup command succeeded or a service is ready. One of command or url is required.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
command | string | no* | -- | Shell command that must exit 0. |
url | string | no* | -- | URL to probe. Supports http://, https://, tcp:// schemes. HTTP expects 2xx. TCP expects connection accepted. |
interval | duration | no | 2s | Time between probes. |
timeout | duration | no | 60s | Total time before giving up. |
retries | integer | no | 30 | Max probe attempts. |
start_period | duration | no | 0s | Grace period before the first probe. |
Duration format: a decimal number followed by a unit. Supported units include ns, us, ms, s, m, and h. Examples: 500ms, 2s, 5m, 1.5h.
# HTTP health check
healthcheck:
url: http://localhost:3000/health
interval: 2s
timeout: 30s
retries: 15
# TCP health check (database)
healthcheck:
url: tcp://localhost:5432
# Command health check
healthcheck:
command: test -f /tmp/ready
retries: 10Port Definitions
Port declarations on services tell the platform which ports to expose publicly.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
port | integer | yes | -- | Port number inside the VM. |
name | string | yes | -- | Unique name for this port mapping. The platform uses this name to look up the external URL. |
protocol | string | no | tcp | Protocol hint: http, ws, or tcp. |
ports:
- port: 3000
name: web
protocol: httpWhen the VM boots, the platform allocates a host port and creates a proxy. The resulting public URL is available in the VM's port_mappings array, keyed by name.
Service Dependencies
The depends_on field on services creates a startup DAG (directed acyclic graph). Services start in dependency order via topological sort. Each service blocks until all of its dependencies' health checks pass.
Circular dependencies are detected and rejected at startup.
services:
- name: database
run: docker compose up postgres
healthcheck:
url: tcp://localhost:5432
- name: redis
run: docker compose up redis
healthcheck:
url: tcp://localhost:6379
- name: api
run: npm run start
depends_on: [database, redis]
healthcheck:
url: http://localhost:4000/healthIn this example, database and redis start concurrently. api waits for both to be healthy before starting.
Secret references
Anywhere a string appears in the manifest, ${secrets.KEY} is a valid reference. The platform substitutes every reference with its plaintext value before the manifest is delivered to your VM; your VM never receives a literal ${secrets.X} placeholder and never receives a copy of any secret it doesn't reference.
Where references are valid
Every string field in the manifest, including:
envvalues at the top level and inside any setup command, service, or named commandsetup[].run,services[].run,commands.<name>.run,simulators[].build,simulators[].runsetup[].working_dir,services[].working_dir,commands.<name>.working_dirsetup[].healthcheck.command,setup[].healthcheck.url, and the same fields on servicescallbacks.url,callbacks.authsources[].repo,sources[].branch,sources[].workspace,sources[].identity.name,sources[].identity.emailagent.command,agent.args[],agent.instructions[],agent.envvaluesdocker_compose.app_service,docker_compose.setup[],docker_compose.exec[]
Source of values
${secrets.KEY} references resolve from the secret store on the environment. You manage secrets through the platform's secrets API; you do not declare them in the manifest. See the secrets section for usage examples.
Missing references are rejected at the API
If the manifest references a secret that is not configured on the environment, the platform rejects the request before a VM is provisioned. This happens in two places:
- At manifest acceptance, when you save a new manifest or update an existing one. The save fails with a
422and an error listing every missing secret and every field that referenced one. - At VM provisioning, when a session boot or VM-create call resolves the manifest to a delivery-ready form. If a referenced secret was deleted in the window between manifest save and VM-create, the VM-create fails with a
422and the same diagnostic.
Either way, your VM never starts against a literal ${secrets.X} placeholder. A typo (${secrets.STRIP_KEY} instead of ${secrets.STRIPE_KEY}) is caught the moment you save the manifest. Forgetting to provision the secret is caught at the same point. The fix in both cases is to add the secret to the environment, or to remove the reference, then re-save.
Quoting is your responsibility
Substitution is a literal string replacement. The plaintext value lands in the manifest field exactly as stored, with no escaping applied for the surrounding context. If your secret contains shell metacharacters ($, ", ', backticks, spaces, newlines) and you reference it inside a run string, quote it the same way you would quote any other unknown input:
setup:
- name: bad-quoting
run: echo "Token is ${secrets.API_TOKEN}" # breaks if the value contains a "
- name: good-quoting
run: |
printf '%s' "$TOKEN" > .auth # value flows through env, no shell parsing
env:
TOKEN: ${secrets.API_TOKEN}Treating secret values as data passed via env and consumed by printf '%s', cat, or argument lists is the safe pattern. Inlining secret values into a shell-parsed command line is brittle for the same reason inlining any other untrusted string is.
Rotating a secret requires a new snapshot
The platform substitutes the manifest with the secret's current plaintext at the moment a VM is created. The captured snapshot is a frozen filesystem that may include side effects from setup commands, such as files written or packages configured with the value baked in. Rotating a secret with PATCH /v1/.../secrets/{id} updates the source of truth, but it does not retroactively change files or build artifacts already captured in existing snapshots.
If a secret is consumed by setup, regenerate the environment's base snapshot after rotation. New sessions booted from the new snapshot use the rotated value through the full lifecycle.
What Gets Auto-Injected
Wallfacer automatically modifies the manifest before execution:
| Behavior | Detail |
|---|---|
| agent-api service | If no service named agent-api exists, one is injected as the first service with a health check, port declaration, and platform-appropriate binary path. |
| Memory and vCPUs | Normalized from server configuration. User-provided values are overwritten. |
| Simulator device and runtime | Missing iOS device and runtime values default to the configured device and latest. Selected values are preserved. The agent resolves latest to the newest installed runtime compatible with the device at boot. |
| Map field normalization | env and commands are ensured to be objects (not arrays) for correct parsing. |
| Port normalization | Bare integer ports in service definitions are converted to proper port objects. |
Configuration Layering
Manifests are resolved by merging three layers, where later layers override earlier ones:
1. Repo file (agent-env.yml in repo root) -- committed by engineers
2. Environment config (stored in Wallfacer) -- per-environment overrides via app/API
3. Session config (injected at session start) -- per-session secrets and branch overridesMerge semantics: Deep merge with later layers winning. For arrays (setup, services), the override layer replaces the entire array. For objects (env, agent, commands), keys are merged with override values winning.
Examples
Node.js Web App with PostgreSQL
version: 1
platform:
os: linux/amd64
sources:
- repo: github.com/acme/webapp
branch: main
env:
NODE_ENV: development
DATABASE_URL: postgres://postgres:postgres@localhost:5432/app
setup:
- name: Install dependencies
run: npm install
retries: 2
healthcheck:
command: test -d node_modules
services:
- name: database
run: docker compose up postgres
healthcheck:
url: tcp://localhost:5432
- name: dev-server
run: npm run dev
depends_on: [database]
ports:
- port: 3000
name: web
protocol: http
healthcheck:
url: http://localhost:3000/health
commands:
migrate:
run: npm run db:migrate
working_dir: /workspace/webapp
seed:
run: npm run db:seed
working_dir: /workspace/webapp
ready: [migrate, seed]Python Django Project
version: 1
platform:
os: linux/amd64
sources:
- repo: github.com/acme/django-api
branch: main
env:
DJANGO_SETTINGS_MODULE: config.settings.development
DATABASE_URL: postgres://postgres:postgres@localhost:5432/django
setup:
- name: Install Python dependencies
run: pip install -r requirements.txt
retries: 2
- name: Install pre-commit hooks
run: pre-commit install
services:
- name: database
run: docker compose up -d postgres
healthcheck:
url: tcp://localhost:5432
- name: django
run: python manage.py runserver 0.0.0.0:8000
depends_on: [database]
ports:
- port: 8000
name: web
protocol: http
healthcheck:
url: http://localhost:8000/health/
commands:
migrate:
run: python manage.py migrate
working_dir: /workspace/django-api
seed:
run: python manage.py loaddata fixtures/seed.json
working_dir: /workspace/django-api
ready: [migrate]
agent:
instructions:
- .claude/CLAUDE.mdiOS App with Simulator
version: 1
platform:
os: darwin/arm64
sources:
- repo: github.com/acme/ios-app
branch: main
setup:
- name: Install CocoaPods dependencies
run: pod install
retries: 2
healthcheck:
command: test -d Pods
simulators:
- platform: ios
bundle_id: com.acme.ios-app
build: |
xcodebuild -workspace App.xcworkspace -scheme App \
-destination "id=$IOS_SIMULATOR_UDID" \
-derivedDataPath .build build
xcrun simctl install $IOS_SIMULATOR_UDID \
.build/Build/Products/Debug-iphonesimulator/App.app
xcrun simctl launch $IOS_SIMULATOR_UDID com.acme.ios-app
agent:
instructions:
- .claude/CLAUDE.mdMulti-Repo Setup
version: 1
platform:
os: linux/amd64
sources:
- repo: github.com/acme/frontend
workspace: /workspace/frontend
branch: main
- repo: github.com/acme/shared-lib
workspace: /workspace/shared-lib
branch: main
env:
NODE_ENV: development
setup:
- name: Install shared library
run: cd /workspace/shared-lib && npm install && npm run build
retries: 2
- name: Install frontend dependencies
run: cd /workspace/frontend && npm install
retries: 2
- name: Link shared library
run: cd /workspace/frontend && npm link ../shared-lib
services:
- name: dev-server
run: npm run dev
working_dir: /workspace/frontend
ports:
- port: 3000
name: web
protocol: http
healthcheck:
url: http://localhost:3000
agent:
instructions:
- .claude/CLAUDE.md