Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLI
Assigneesstack72

Relationships

#1517 Serve config file — read swamp serve configuration from YAML

Opened by stack72 · 8/3/2026· Shipped 8/3/2026

Problem

swamp serve has a growing list of CLI flags: --port, --host, --detach-runs, --auth-mode, --webhook, --no-schedule, --hot-reload, --cert-file, --key-file, --trust-proxy, --trusted-hosts, --admins, --allowed-collectives, --allowed-users, --verify-on-enroll, --restricted-model-types, and more. Operators running serve in production (ASG, Kubernetes, systemd) configure these via launch scripts, ExecStart lines, or container entrypoints — long, fragile command lines that are hard to review and easy to get wrong.

There's no way to version-control the serve configuration alongside the repo. Every deploy copies the same flags from a wiki page or a Terraform template. A change to the webhook secret or auth mode means updating the deployment config, not the repo.

Desired Outcome

Operators can define their serve configuration in a YAML file, commit it to the repo, and start serve with just swamp serve (or swamp serve --config path/to/config.yaml). The config file is the single source of truth for how serve runs. CLI flags override config file values when both are present.

Design

Config file location

Default: .swamp/serve.yaml in the repo root. Override with --config .

If no config file exists and no --config is specified, serve uses CLI flags only — existing behavior unchanged.

Config file format

port: 9090
host: 0.0.0.0

auth:
  mode: token
  admins:
    - "user:admin-token-name"
  allowed-collectives:
    - "engineering"
  restricted-model-types:
    - "command/shell"

tls:
  cert-file: /etc/swamp/server.crt
  key-file: /etc/swamp/server.key

webhooks:
  - route: /hooks/ci
    workflow: deploy-pipeline
    secret: "@env=WEBHOOK_SECRET"
  - route: /hooks/linear
    workflow: triage
    secret: "@env=LINEAR_SECRET"
    scheme: linear

schedule: true
hot-reload: false
detach-runs: true

trust-proxy: false
trusted-hosts:
  - host.[HOST-1]

default-vault: production

Resolution priority

CLI flags take precedence over config file values. This lets operators override a single value without editing the config file:

swamp serve --port 8080 # overrides config file's port: 9090

Resolution order (highest wins):

  1. CLI flag
  2. Config file
  3. Default value

Webhook config format

Today webhooks are a colon-delimited string: --webhook "/hooks/ci:deploy:@env=SECRET:github"

In the config file, webhooks are structured YAML — easier to read and less error-prone:

webhooks:
  - route: /hooks/ci
    workflow: deploy-pipeline
    secret: "@env=WEBHOOK_SECRET"
    scheme: github          # optional, default: github
    header: X-Signature     # required for generic scheme
    prefix: "sha256="       # optional for generic scheme

The config file parser converts these to the same internal WebhookEndpoint objects that parseWebhookFlag produces. Both formats are supported — CLI flags use the colon string, config file uses structured YAML.

What goes in the config file vs .swamp.yaml

.swamp.yaml is the repo marker — it has the swamp version, datastore config, and namespace. These are repo-level settings that affect all commands, not just serve.

serve.yaml is serve-specific — port, auth, webhooks, TLS, scheduling. These only matter when running swamp serve.

The two files are complementary, not overlapping. serve.yaml never contains datastore or vault config.

Implementation

  1. Define a ServeConfig Zod schema that mirrors the CLI flags
  2. Load and parse .swamp/serve.yaml (or --config path) at serve startup
  3. Merge config file values with CLI flags (flags win)
  4. Pass the merged config to the existing serve setup code
  5. Validation: report clear errors for invalid config (unknown keys, wrong types, invalid webhook format)

Error handling

  • Config file not found when --config is specified: hard error, refuse to start
  • Config file not found at default location (.swamp/serve.yaml): silently continue with CLI flags only
  • Config file has invalid YAML: hard error with parse error details
  • Config file has unknown keys: warn but continue (forward compat)
  • Config file has invalid values (e.g. port out of range): hard error with field-level error message

Files to modify

  • src/cli/commands/serve.ts — config loading, merging with CLI flags
  • New: src/serve/serve_config.ts — ServeConfig schema, loader, merger
  • New: src/serve/serve_config_test.ts — parsing, merging, validation tests

Testing

  1. Unit test: parse valid config file with all fields
  2. Unit test: parse config file with minimal fields (just port)
  3. Unit test: CLI flags override config file values
  4. Unit test: missing config file at default location is not an error
  5. Unit test: missing config file with --config is an error
  6. Unit test: invalid YAML produces clear error
  7. Unit test: unknown keys produce warning
  8. Unit test: webhook structured format parsed correctly
  9. Unit test: webhook structured format with scheme/header/prefix
  10. Binary test: serve starts with config file, verify port and auth mode applied
  11. Binary test: serve with config file + CLI flag override, verify flag wins

What this does NOT include

  • Moving datastore/vault config into serve.yaml (stays in .swamp.yaml)
  • Environment variable interpolation in config values (secrets already use @env= syntax in webhook config)
  • Config file hot-reload (serve reads config once at startup)
  • Any behavior changes — this is purely a new way to provide the same configuration

Parent issue: #1448

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 7 MOREREVIEW+ 4 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

8/3/2026, 9:04:19 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack728/3/2026, 6:02:08 PM

Sign in to post a ripple.