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.
ss provision # reconcile starsystem.yaml in cwdss provision my-system.yaml # explicit filess provision --dry-run # show plan, don't executess provision --service=caddy # single servicess provision --env=prod # with environment overlayss provision --status # health check provisioned servicesHow it works
Section titled “How it works”ss provision routes each service to the right provisioner based on what the service declaration contains:
| Service shape | Provisioner | What happens |
|---|---|---|
type: process + command: | LocalProcess | Process is spawned detached; PID stored in vault |
type: cdn + _cloudflare: | Cloudflare | CF API creates the resource (custom hostname, DNS records, Pages project) |
type: dns + provision.provider: porkbun | Porkbun | Domain registered + DNS records created/updated |
provision.provider: neon | Neon | Serverless Postgres database provisioned on Neon |
provision.provider: supabase | Supabase | Supabase project provisioned (cloud or local) |
provision.provider: fly | Fly | App deployed to Fly Machines |
provision.provider: railway | Railway | Service deployed on Railway |
provision.provider: cloudflare | Cloudflare | Pages project, R2 bucket, Workers KV, or D1 database |
provision.provider: aws | AWS | S3 bucket, CloudFront distribution, or both (s3-cloudfront) |
| anything else | — | Skipped (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.
The plan
Section titled “The plan”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.
Service shapes
Section titled “Service shapes”Process services
Section titled “Process services”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.
Cloudflare services
Section titled “Cloudflare services”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: trueSupported resource types:
| Resource | What it creates |
|---|---|
custom-hostnames | Cloudflare for SaaS custom hostname (+ sets fallback origin if given) |
dns-zone | DNS records on an existing CF zone (idempotent — updates if content changed) |
pages-project | Cloudflare Pages project + custom domain bindings |
The Cloudflare API token is read from the vault: ss vault set providers:cloudflare api_key <token>.
Credentials
Section titled “Credentials”Provisioners that call external APIs need credentials in the vault before running:
# Neonss vault set-key neon api_key <token>
# Supabasess vault set-key supabase api_key <token>
# Fly.ioss vault set-key fly api_key <fly-token>
# Railwayss vault set-key railway api_key <railway-token>
# Cloudflaress 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)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.
Status checks
Section titled “Status checks”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: pendingA ✗ 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.
Comparison with ss deploy
Section titled “Comparison with ss deploy”ss provision | ss deploy | |
|---|---|---|
| Input | starsystem.yaml file path | --env=<name> overlay |
| Service selection | All services with a known provisioner | Services 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 it | Developers, visual designer, agents | Infra 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.
MCP tools
Section titled “MCP tools”When using ss as an MCP server, the equivalent tools are:
starsystem_provision— full reconciliation run (same asss provision)starsystem_provision_service— single service (same asss provision --service=<id>)starsystem_provision_status— health check (same asss 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)