Skip to content

ssmod field reference

A *.ssmod.yaml file declares one module — a unit of services that ss composes into a workspace. This page is the field-by-field reference for the module schema. For the broader composition model (modules → workspace → environment) see the Workspaces walkthrough.

# yaml-language-server: $schema=https://schema.celestialintelligence.co/ssmod-v1.json
module: dashboard-server # required — module id
label: "Dashboard Server" # optional — human label
description: "Hosted dashboard runtime." # optional — one-line summary
color: "#8b5cf6" # optional — used by topology renderers
requires: # other modules that must compose first
- starsystem
- scribe
paths: # repo-relative source roots (optional)
- packages/dashboard-server
services: # named map of service blocks (see below)
web:
target: { ... }
_artifact: { ... }
_systemd: { ... }
vault: # vault keys this module reads
required:
- WORKOS_API_KEY
- DASHBOARD_SESSION_SECRET
pipelines: [] # optional Starflow pipelines
FieldRequiredNotes
moduleyesThe module id. Used as the prefix when services are referenced as <module>.<service> (e.g. dashboard-server.web).
label, description, colornoDisplay-only metadata. The color shows up in topology views.
requiresnoCompose ordering. ss errors at compose time if a required module isn’t present.
pathsnoSource roots for IDE tooling. Doesn’t affect deploy.
servicesusuallyThe substantive surface — see below.
vault.requirednoDocuments which secrets the module reads from the workspace+env app-secret namespace. Used by ss workspace doctor (the vault-required check) and the --fix flag (auto-promotes provider keys when names match).
pipelinesnoStarflow pipeline declarations.

Each service has a target (where it runs) and provisioning helpers (_artifact, _systemd) depending on the target type.

services:
web:
target:
type: external # see "Target types" below
host: 5.161.83.131
remote_user: root
_host_requires: # platform pre-flight; ss verifies these on the host
node: "22"
packages: [curl]
_artifact: # build + ship a tarball (target: external or local-process)
workspace_packages: ["@celestial/dashboard-server"]
transitive: true
build_script: "build:with-dashboard"
staging_files:
- { from: packages/dashboard/dist, to: dashboard-dist }
cmd: "/usr/bin/node ./node_modules/@celestial/dashboard-server/dist/server.js"
deploy_to: /opt/dashboard-server
keep_revs: 5
_systemd: # systemd unit (target: external)
description: "celestial hosted dashboard"
restart: on-failure
restart_sec: 10
env:
PORT: "8788"
env_from_vault:
- WORKOS_API_KEY
- DASHBOARD_SESSION_SECRET
type:Used forRequired adjuncts
externalA VPS / bare-metal host you SSH intohost, remote_user; usually _artifact + _systemd
local-processA process running on the operator’s local machineusually _local (cmd, args, port)
cloudflare-pagesStatic site on CF Pagesproject, production_branch, custom_domains?
web-frontendNEW — composite hosting target (DNS + reverse-proxy + TLS + systemd)see web-frontend
asset-hostingMulti-tenant CDN bucket (Cloudflare R2 today)bucketName?, publicDomain?
auth-tenantWorkOS organizationname, domains?
dnsDomain + records via Porkbun / CFprovision: { provider, domain, records }
database, app, web, tls, storage, email, queue, observabilityprovider-specific job typessee ss catalog

Used when target.type is external or local-process. ss builds a tarball from declared workspace packages, ships it, vendors deps, restarts the systemd unit.

_artifact:
workspace_packages: ["@celestial/dashboard-server"]
transitive: true # auto-vendor transitive workspace deps
build_script: "build:with-dashboard" # npm script to run for each seed (default "build")
staging_files: # extra files to drop into the bundle root
- { from: packages/dashboard/dist, to: dashboard-dist }
runtime_files: # files copied with their repo-relative path
- migrations/
cmd: "/usr/bin/node ./node_modules/@celestial/X/dist/server.js"
deploy_to: /opt/X # remote install root
keep_revs: 5 # how many past releases to keep on the host

The list of @celestial/* workspace packages whose dist/ is shipped inside node_modules/@celestial/<name> in the bundle. The first entry is treated as the “seed” — build_script applies to it (and only it when transitive: true walks the graph for the rest).

transitive: true (optional, default false) — K2

Section titled “transitive: true (optional, default false) — K2”

When true, ss walks each seed’s package.json dependencies, finds every @celestial/* or workspace:* or file:* reference, and auto-vendors them all (with cycle safety). Stops the “I added a workspace dep, prod bundle ERR_MODULE_NOT_FOUND at runtime” footgun.

Without transitive: true, the operator must list every transitive workspace dep explicitly. With it, just list the direct seeds:

# Before (manual transitive list):
workspace_packages:
- "@celestial/dashboard-server"
- "@celestial/shared" # required transitively
- "@celestial/agent-host-ports" # required by shared
- "@celestial/potus" # required by shared
# After:
workspace_packages: ["@celestial/dashboard-server"]
transitive: true

Non-workspace deps (hono ^4.0.0, @aws-sdk/client-s3 ^3) are unaffected — they go through npm install as normal external deps.

build_script (optional, default "build") — new

Section titled “build_script (optional, default "build") — new”

The npm run <build_script> invoked for each seed package during the artifact build. Defaults to "build". Use a non-default script when the package needs extra build steps beyond tsc — bundling a sibling SPA, generating typings, running a code-gen pass.

build_script: "build:with-dashboard"

The script must exist in the seed package’s package.json. When transitive: true, the override applies only to the seed; transitively-vendored packages still run npm run build (so each workspace dep’s plain build script must produce a working dist/).

A list of { from, to } pairs copied into the staged tarball at the bundle root (not into the vendored node_modules/). Use this to land assets next to the runtime CWD — typically a built SPA the server needs to serve from disk.

staging_files:
- from: packages/dashboard/dist # repo-relative source
to: dashboard-dist # bundle-root-relative destination

The to path is anchored under the bundle root. Escapes (../) are rejected at build time.

Copies files from the repo into the bundle preserving their repo-relative path. Use for migrations, configs, lookup tables that the runtime expects to read.

runtime_files:
- migrations/
- config/email-templates.yaml

Where staging_files is “land this at <bundle-root>/X”, runtime_files is “land this at <bundle-root>/<repo-relative-path>”.

  • cmd — the systemd ExecStart command, run inside deploy_to. The classic shape is /usr/bin/node ./node_modules/@celestial/<id>/dist/server.js.
  • deploy_to — the install root on the host. ss creates <deploy_to>/<commit>/ for each release and symlinks current to the active one.
  • keep_revs — how many old releases to retain on disk for rollback. Default 5.

A single ssmod stanza that owns **DNS + reverse-proxy + TLS + systemd

  • health check + instance-row** — the composite of everything a hosted web app needs. Two runtime variants.
services:
dashboard:
target:
type: web-frontend
provider: caddy-on-vps
runtime: node
domain: dashboard.example.com
port: 8788
tls: caddy # | cloudflare | none
health: /health
logPathOwner: caddy # chowned at deploy time
_artifact: { ... } # existing artifact pipeline
_systemd: { ... }

ss provisions:

  • DNS A/CNAME record (via the host’s owning DNS provider — CF, Porkbun)
  • A marker-fenced Caddy block in /etc/caddy/Caddyfile (idempotent byte-exact replace — siblings preserved)
  • The log file pre-created with logPathOwner ownership
  • Health check polled post-reload (expects 2xx within 30s)
  • An instance row in celestial_service_state (Phase J1)
services:
lens:
target:
type: web-frontend
provider: cloudflare-pages
runtime: static
domain: lens.example.com
tls: cloudflare
projectName: example-lens
buildOutputDir: packages/lens/dist

ss provisions:

  • A CF Pages project (find-or-create)
  • DNS CNAME to the project’s .pages.dev subdomain
  • Upload of buildOutputDir
  • Instance row

The tls knob:

  • caddy — Caddy handles ACME (default for runtime: node)
  • cloudflare — CF terminates TLS (default for runtime: static)
  • none — bare HTTP (development only)

Idempotency rule for both variants: rerunning ss apply with identical inputs is a no-op. State is reconciled, not recomputed.

Maps to a systemd unit. Lands at /etc/systemd/system/<service>.service.

_systemd:
description: "celestial hosted dashboard"
restart: on-failure # | always | no
restart_sec: 10
wants: [postgresql.service]
env: # plain env vars
PORT: "8788"
LOG_LEVEL: info
env_from_vault: # resolved from workspace+env app-secrets
- WORKOS_API_KEY
- DASHBOARD_SESSION_SECRET

Vault keys listed in env_from_vault need to exist as app-secrets in the workspace+env namespace. Use ss vault promote to lift them from a provider-key (e.g. workos.api_keyWORKOS_API_KEY); see the vault promote section.

Pre-flight checks ss runs on the deploy target before doing anything mutating.

_host_requires:
node: "22" # major-version match
packages: [curl, jq, git] # apt-style names

Missing requirements abort the deploy with a clear “install X first” error.

Terminal window
# Pre-flight diagnostics — checks transitive deps, vault gaps, ts package
# layout, ESM import-suffix compliance, stale shim, and more. Run before
# every deploy.
ss workspace doctor --workspace-file=<your.ssws.yaml>
# JSON for agents:
ss workspace doctor --workspace-file=<your.ssws.yaml> --json
# Auto-apply mechanical fixes (vault promotions, etc.):
ss workspace doctor --workspace-file=<your.ssws.yaml> --fix
  • BYO-agent runbook — how to drive the above with a 50-line script
  • ADR-011 — artifact-based service deploys (the _artifact design)
  • ADR-027 — jobs over resources (the target.type model)
  • ADR-028 — topology projection (how composed ssmods land in Supabase)