Machine settings: config.yaml

Machine settings live in $XDG_CONFIG_HOME/sparkwing/config.yaml, or ~/.config/sparkwing/config.yaml when XDG_CONFIG_HOME is absent. SPARKWING_CONFIG selects another file. A present empty value is invalid. SPARKWING_HOME selects runtime state and does not move machine settings.

Project declarations live in .sparkwing/sparkwing.yaml instead. See Config reference.

SectionsSection anchor link

SectionHolds
profilesNamed controller connections containing controller.url, an optional controller.token, and default: true to select an optional-profile CLI connection.
reposRegistered checkout paths, fallback_paths, auto_register and include_worktrees.
admissionMachine admission mode, budget and custom policy.
runnerController URL, credentials_dir, permitted repos, labels and local capacity preferences.
cacheLocal binary-cache max_bytes and max_entries. Explicit zero disables a bound.
machineAn optional box_id for standalone machine admission.
debugpause_timeout.
runsubmit_env_allow and the opt-in cache_from controller profile.

The shared decoder validates the complete file before a section is used. Unknown keys, duplicate keys, explicit null and additional YAML documents fail with file, key and line information. A reader never accepts another section's invalid settings. Omission remains distinct from an explicit empty, false or zero value where the setting permits it.

profiles:
  prod:
    controller:
      url: https://api.sparkwing.example
      token: swk_...
repos:
  repos:
    - path: /srv/code/app
  fallback_paths:
    - ~/code
  include_worktrees: true
admission:
  mode: auto
  budget: 50%,ignore-external
runner:
  controller: https://api.sparkwing.example
  credentials_dir: /srv/sparkwing/credentials
  repos: [github.com/acme/app]
  max_concurrent: 2
  holder_prefix: desk
  labels: [host=desk, gpu]
  local_admission: true
cache:
  max_bytes: 4GiB
machine:
  box_id: rack-3-host-7
run:
  submit_env_allow: [BUILD_REGION, BUILD_*]

pipeline trigger and Cloud-routed run capture only present variables matching run.submit_env_allow. Empty values remain present. Literal names and terminal _* prefixes are supported; a prefix needs at least two characters and must start with a letter, so _* and A_* are refused as too broad. Credential-shaped and engine-owned names are excluded. The controller encrypts the captured values separately from the run spec and delivers them only to live execution awards. Retries keep the same values. Planning, installation and execution use them, and values of at least 12 characters are masked before processes start. Public run views show only names and an environment digest.

On a machine that runs other people's work, the same run.submit_env_allow is the operator's list of submitted names it accepts. A submitted value under any other name is dropped before a process starts; an empty list accepts none. Cloud Jobs, here-hosted runs and the requester's own personal machines accept every submittable name. Go toolchain and network base names cannot be submitted at all.

Connections come only from this machine file. A project can name a profile but cannot define one. A controller command uses an explicit --profile first, then a saved default when its profile flag is optional, then the local controller. Use --profile= to select local for one invocation. See Controller connections.

Enrollment saves the machine's display name in runner.holder_prefix. sparkwing-runner start --config PATH accepts this saved metadata. The Cloud controller supplies the runner identity and claim holder for each award. Controller-backed concurrency uses this persisted machine identity for box scope, independently of machine.box_id and runner.local_admission. A local controller uses its persisted local peer identity in its private store.

Runner labelsSection anchor link

runner.labels lists custom labels this machine reports for job placement, such as host=desk or gpu. They apply to everything the machine runs: work an enrolled runner claims from a controller, and the machine's own local sparkwing run work. A job with Requires("host=desk") runs locally on a machine whose configuration lists host=desk, and waits on any other machine with a status detail naming the missing label.

Labels are matching preferences the machine reports about itself. They never grant pools, reserved secrets, trust or repository scope; those come from the machine's credentials and the team's access rules. A label that names a granted fact (name=, class=, location=, team=, pool= or local) has no effect: matching uses the granted value instead. The daemon logs a warning for each one when it starts, and sparkwing doctor reports it with its file and line. Validation refuses a blank label and the sparkwing- prefix reserved for Sparkwing Cloud. os= and arch= labels are accepted but never override the platform the machine observes.

The local controller reads runner.labels when it starts. After changing them, run sparkwing daemon restart --force so local runs report the new labels. An enrolled runner reads them when its service starts.

Permissions and writesSection anchor link

The file carries credentials, so reads require an owner-only regular file. Unix uses mode 0600. Windows checks the owning SID and DACL. Symlinks and reparse points are refused.

Settings writers lock config.yaml.lock, reread the file, change their section and atomically replace the file with an owner-only copy. Other sections and their comments survive. A write that would leave a dangling YAML alias fails. Profile mutations also preserve changes to other profiles made during a controller probe or credential revocation.

A command running under a separate SPARKWING_HOME refuses to write the machine's settings. Set SPARKWING_CONFIG to a file inside that home when testing an isolated runtime.

Local secretsSection anchor link

Secret values are separate from the machine settings file. Use Secrets for credential storage and rotation.

Moving from the per-file settingsSection anchor link

There is no automatic import or compatibility reader. Move settings into the final sections above. Remove old agent, logs, fleet, allow_repos, dispatch_wait and profile backend keys. Runner enrollment uses sparkwing runners add and stores its credential in a private file under runner.credentials_dir.

Enrollment leaves an omitted --max-concurrent unset in the file. The shared runner settings resolver defaults it to one. An explicit positive value is saved as supplied. Enrollment and removal validate the complete machine file. Removal reads agent-token as an owner-only regular file and checks its controller and runner selectors before stopping the service or revoking authority.

See the migration guide for controller-profile changes.