Skip to content

ss provision — bring services to life

ss provision is the “just run it” command. It reads your starsystem.yaml, compares desired state against what’s actually running, and brings everything up — processes, Cloudflare resources, cloud databases — in dependency order.

Terminal window
ss provision # reconcile starsystem.yaml in cwd
ss provision my-system.yaml # explicit file
ss provision --dry-run # show plan, don't execute
ss provision --service=caddy # single service
ss provision --env=prod # with environment overlay
ss provision --status # health check provisioned services

ss provision routes each service to the right provisioner based on what the service declaration contains:

Service shapeProvisionerWhat happens
type: process + command:LocalProcessProcess is spawned detached; PID stored in vault
type: cdn + _cloudflare:CloudflareCF API creates the resource (custom hostname, DNS records, Pages project)
type: dns + provision.provider: porkbunPorkbunDomain registered + DNS records created/updated
provision.provider: neonNeonServerless Postgres database provisioned on Neon
provision.provider: supabaseSupabaseSupabase project provisioned (cloud or local)
provision.provider: flyFlyApp deployed to Fly Machines
provision.provider: railwayRailwayService deployed on Railway
provision.provider: cloudflareCloudflarePages project, R2 bucket, Workers KV, or D1 database
provision.provider: awsAWSS3 bucket, CloudFront distribution, or both (s3-cloudfront)
anything elseSkipped (shown in plan as )

Services are applied in depends_on topological order — if caddy depends on caddy-check-server, the check server starts first.

All operations are idempotent. Re-running ss provision against an already-provisioned system verifies health without re-creating resources.

Before applying anything, ss provision prints a plan:

Starsystem — starsystem.yaml
To create:
+ caddy-check-server (local-process)
+ caddy (local-process)
+ cloudflare-for-saas (cloudflare)
Skipping 4 services (no provisioner)
  • + means the service will be created for the first time
  • ~ means it already exists and will be verified
  • means it’s skipped (no provisioner applies)

Use --dry-run to see the plan without executing it.

A process service has type: process and a command: field:

services:
caddy-check-server:
type: process
name: Caddy domain-check server
command: node scripts/caddy/domain-check-server.mjs --port=2020
depends_on: []

ss provision spawns the process detached (survives terminal closure), records the PID in the vault, and optionally waits for a health check URL before marking it healthy.

Config generation from a template — processes can generate their config file before starting:

services:
caddy:
type: process
command: caddy run --config ~/.starsystem/hosting/Caddyfile
provision:
generate_config:
template: scripts/caddy/Caddyfile.template
output: ~/.starsystem/hosting/Caddyfile
vars:
CHECK_PORT: "2020"
ACME_EMAIL: "{{ vault('hosting.acme_email') }}"
SITES_DIR: "~/.starsystem/hosting/sites"
health_check: http://127.0.0.1:2019/config/
install_hint: "Install with: brew install caddy"

Template vars enclosed in {{ vault('key') }} are resolved from the vault before the file is written.

A Cloudflare service has type: cdn and a _cloudflare: block:

services:
cloudflare-for-saas:
type: cdn
name: Cloudflare for SaaS
_cloudflare:
resource: custom-hostnames
zone: "{{ vault('secrets.CF_ZONE_ID') }}"
fallback_origin: "{{ vault('secrets.CF_PAGES_FALLBACK') }}"
cloudflare-dns:
type: cdn
_cloudflare:
resource: dns-zone
zone: "{{ vault('secrets.CF_ZONE_ID') }}"
domain: "{{ vault('secrets.CF_DOMAIN') }}"
records:
- type: CNAME
name: "@"
content: "{{ vault('secrets.CF_PAGES_FALLBACK') }}"
proxied: true

Supported resource types:

ResourceWhat it creates
custom-hostnamesCloudflare for SaaS custom hostname (+ sets fallback origin if given)
dns-zoneDNS records on an existing CF zone (idempotent — updates if content changed)
pages-projectCloudflare Pages project + custom domain bindings

The Cloudflare API token is read from the vault: ss vault set providers:cloudflare api_key <token>.

Provisioners that call external APIs need credentials in the vault before running:

Terminal window
# Neon
ss vault set-key neon api_key <token>
# Supabase
ss vault set-key supabase api_key <token>
# Fly.io
ss vault set-key fly api_key <fly-token>
# Railway
ss vault set-key railway api_key <railway-token>
# Cloudflare
ss vault set-key cloudflare api_key <cf-token>
ss vault set secrets CF_ZONE_ID <zone-id>
ss vault set secrets CF_DOMAIN myapp.com
# AWS (S3 / CloudFront)
ss vault set-key aws access_key_id <AKIAIOSFODNN7EXAMPLE>
ss vault set AWS_SECRET_ACCESS_KEY <your-secret-key>
# Porkbun (domain registration + DNS)
ss vault set-key porkbun api_key <pk1_...>
ss vault set PORKBUN_SECRET_KEY <sk1_...>
# Let's Encrypt (Caddy / local TLS)
ss vault set hosting acme_email [email protected]

Process services (local-process) require no API key — they just need the binary to be on $PATH.

Not sure which keys a provider needs? Run ss catalog to see vault key requirements for every provider.

ss provision --status runs health checks against all provisioned services and reports:

Service status starsystem.yaml
✓ caddy-check-server local-process running (pid 9103, health ok)
✓ caddy local-process running (pid 9111)
✗ cloudflare-for-saas cloudflare custom hostname status: pending

A for a process means the PID is no longer alive. For Cloudflare, it means the API returned an error or the hostname is not yet active. Re-running ss provision will attempt a fix.

ss provisionss deploy
Inputstarsystem.yaml file path--env=<name> overlay
Service selectionAll services with a known provisionerServices with provision.provider: set
Process services✓ starts them✗ not handled
Cloudflare _cloudflare:✓ handled✗ not handled
Terraform targets✗ use ss deploy✓ runs terraform apply
Who uses itDevelopers, visual designer, agentsInfra engineers with Terraform stacks

Use ss provision for the day-to-day “make it run” workflow. Use ss deploy when you have Terraform-managed cloud servers.

When using ss as an MCP server, the equivalent tools are:

  • starsystem_provision — full reconciliation run (same as ss provision)
  • starsystem_provision_service — single service (same as ss provision --service=<id>)
  • starsystem_provision_status — health check (same as ss provision --status)

Typical agent workflow:

starsystem_read_system
→ starsystem_add_service (add the new service declaration)
→ starsystem_provision_service (start it immediately)
→ starsystem_provision_status (verify it's healthy)
→ starsystem_test_connection (confirm it's reachable)