githubEdit

Project Configuration (spuff.yaml)

spuff supports per-project configuration via a spuff.yaml file in your project root. This enables environment as code - defining your development environment declaratively alongside your source code.

See also: Spuff Specification for the formal specification with validation rules and conformance requirements.

Overview

When you run spuff up in a directory containing a spuff.yaml file, spuff will:

  1. Read the project configuration

  2. Apply any resource overrides (size, region)

  3. Provision the VM with the project config embedded

  4. Install bundles, packages, and services automatically

  5. Clone repositories and run setup scripts

File Location

Place spuff.yaml in your project root (same directory as your git repository). spuff will search up the directory tree to find it.

my-project/
├── spuff.yaml          # Project configuration
├── spuff.secrets.yaml  # Secrets (add to .gitignore!)
├── docker-compose.yaml # Services (optional)
└── src/

Complete Example


Configuration Reference

version

Type: string Default: "1"

Spec version for future compatibility.


name

Type: string (optional) Default: Directory name

Custom name for the environment.


resources

Override global VM configuration. CLI flags take precedence over project config.

Precedence: CLI flags > spuff.yaml > ~/.spuff/config.yaml


bundles

Pre-configured language toolchains. Each bundle installs the compiler/runtime plus essential development tools (LSPs, linters, formatters).

Available bundles:

Bundle
Includes

rust

rustup, cargo, rust-analyzer, clippy, rustfmt, mold

go

go, gopls, delve, golangci-lint, air

python

python3.12, pip, venv, uv, ruff, pyright, ipython

node

node 22 LTS, npm, pnpm, typescript, eslint, prettier

elixir

erlang/OTP, elixir, mix, elixir-ls, phoenix

java

openjdk 21, maven, gradle, jdtls

zig

zig, zls

cpp

gcc, clang, cmake, ninja, clangd, gdb, lldb

ruby

ruby, bundler, solargraph, rubocop


packages

Additional system packages to install via apt.


services

Docker services configuration. Uses your project's docker-compose.yaml.

Note: spuff doesn't duplicate docker-compose configuration - it uses your existing compose file.


repositories

Clone additional repositories into the environment.

SSH Agent Forwarding: spuff uses SSH agent forwarding, so your local SSH keys work for cloning private repos.


env

Environment variables set on the VM.

Variable resolution: References to $VAR, ${VAR}, or ${VAR:-default} are resolved from your local environment before being sent to the VM.


setup

Shell commands executed after bundles and packages are installed.

Scripts are executed in order. If any script fails, subsequent scripts are skipped.


ports

Ports for automatic SSH tunneling. When you run spuff ssh, these ports are forwarded from your local machine to the VM.

This allows you to work "locally" (browser, IDE) while connected to the remote VM.


ai_tools

Type: string or list (optional) Default: all

Controls which AI coding tools are installed on the VM.

Available tools:

Tool
Package
Description

claude-code

@anthropic-ai/claude-code

Anthropic's Claude Code CLI

codex

@openai/codex

OpenAI Codex CLI

opencode

opencode-ai

Open-source AI coding assistant

copilot

@github/copilot

GitHub Copilot CLI

CLI override: spuff up --ai-tools claude-code,copilot

Precedence: CLI --ai-tools > spuff.yaml > ~/.spuff/config.yaml > default (all)

See AI Tools documentation for authentication and configuration details.


volumes

Mount remote VM directories locally via SSHFS for bidirectional file editing.

Fields:

Field
Required
Description

source

Yes

Local directory path (relative to spuff.yaml or absolute)

target

Yes

Remote directory path on the VM

mount_point

No

Where to mount remote directory locally

Mount Point Resolution:

  1. If mount_point is specified, use it

  2. If only source is specified, mount over source for bidirectional editing

  3. Otherwise, auto-generate under ~/.local/share/spuff/mounts/<instance>/<path>

Behavior during spuff up:

  1. Remote directory is created on the VM

  2. Local source is synced to remote target via rsync

  3. Remote target is mounted locally via SSHFS

Behavior during spuff down:

  1. All mounted volumes are force-unmounted before VM destruction

  2. This prevents SSHFS from hanging when the remote server disappears

Requirements:

CLI Commands:


hooks

Lifecycle scripts for custom automation.


Secrets Management

spuff.secrets.yaml

Store sensitive values in a separate file that's not committed to git:

Add to .gitignore:

Merge behavior: spuff.secrets.yaml is merged with spuff.yaml, with secrets taking precedence.

Environment Variable Resolution

Reference local environment variables in your config:


CLI Integration

spuff up

When spuff.yaml is present:

spuff status --detailed

Shows project setup progress:

spuff logs

View project setup logs:

spuff ssh

Connects with automatic port tunneling:


Logging

All project setup activities are logged to /var/log/spuff/ on the VM:


Agent API Endpoints

The spuff-agent exposes these endpoints for project management:

Endpoint
Method
Description

/project/config

GET

Current project configuration

/project/status

GET

Detailed setup progress

/project/setup

POST

Start project setup

These are used internally by the CLI but can be accessed directly via SSH tunnel.


Best Practices

  1. Keep spuff.yaml in version control - The environment becomes reproducible

  2. Use spuff.secrets.yaml for secrets - Never commit credentials

  3. Prefer bundles over individual packages - They include LSPs and dev tools

  4. Use docker-compose.yaml for services - Don't duplicate config

  5. Test your setup scripts locally first - Saves provisioning time

  6. Use specific versions in setup scripts - Avoid "works on my machine" issues


Troubleshooting

Project config not detected

Solution: Ensure spuff.yaml is in your project root and you're running spuff up from within the project directory.

Bundle installation failed

Check the bundle-specific log for errors. Common issues:

  • Network connectivity

  • Disk space

  • Package conflicts

Services not starting

Ensure your docker-compose.yaml is valid and doesn't require manual configuration.

Setup script failed

View the specific script's output. The script runs in the user's home directory by default.

Last updated

Was this helpful?