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

Relationships

#1569 Datastore-managed configuration for multi-instance serve deployments

Opened by stack72 · 8/10/2026

Problem

When SWAMP runs as a central service (swamp serve), model definitions, workflow definitions, vault configurations, and extension configs are stored as files on the local filesystem (models/, workflows/, vaults/, extensions/). In multi-instance deployments, users must manually synchronize these files between server instances via git — building their own sync mechanism on top of what should be infrastructure that swamp provides.

This is a poor experience because:

  • Every deployment requires custom git-sync tooling or shared filesystem mounts
  • Configuration drift between instances is easy and hard to detect
  • There's no atomic consistency guarantee across config files
  • The datastore already solves this exact problem for runtime data — configs should benefit from the same pipeline

Proposed Solution

Add an opt-in managedConfig: true flag to the datastore section of .swamp.yaml that stores configuration files in the datastore tier, leveraging the existing sync pipeline for automatic distribution across instances.

Configuration

datastore:
  type: "@swamp/s3-datastore"
  managedConfig: true

Datastore Layout

New .swamp/config/ subdirectories added to the datastore tier:

.swamp/config/
  models/{normalized-type}/{id}.yaml
  workflows/workflow-{name}.yaml
  vaults/{vault-type}/{id}.yaml
  extensions/upstream_extensions.json
  pulled-extensions/{@scope/name}/{kind}/*.ts

With namespacing: {datastore}/{namespace}/config/models/...

How It Works

Startup (serve):

  1. Reads .swamp.yaml, detects managedConfig: true
  2. Hydrates the datastore cache (existing hydrateLocalCache()) — now includes config directories
  3. Repository factory wires YAML repos with baseDir pointing to hydrated cache paths
  4. Extension loader reads from managed lockfile and pulled-extensions paths
  5. All loading works unchanged — repos read YAML from a local directory, just a different one
  6. Extension bundles are rebuilt locally from hydrated sources (bundles are always-local derived artifacts)

Write path:

  • YAML repos write to .swamp/config/{type}/... (the cache path)
  • Immediate push to the remote datastore after each config write (config changes are infrequent)
  • Other instances see changes on next hydration/pull

Composite fallback:

  • Top-level directories (models/, workflows/, vaults/) become a read-only fallback layer
  • Repository checks the datastore-managed dir first, falls back to top-level dir
  • Writes always go to the datastore-managed dir
  • Follows the existing CompositeWorkflowRepository pattern

Migration:

  • swamp datastore config migrate copies existing configs into the datastore tier
  • A sentinel file prevents re-migration on subsequent runs

Why This Approach Works

  1. Existing repos accept baseDir: YamlDefinitionRepository, YamlWorkflowRepository, YamlVaultConfigRepository all take a baseDir constructor parameter — just point them at the cache path
  2. Datastore path resolver already routes .swamp/ subdirectories: DefaultDatastorePathResolver routes based on DEFAULT_DATASTORE_SUBDIRS — add the new config subdirs to this list
  3. Precedent exists: auto-definitions/ and definitions-evaluated/ already store YAML files in the datastore tier and sync via the pipeline
  4. Sync lifecycle already covers serve: startup hydration via hydrateLocalCache() and CLI pull-on-start / push-on-end via registerDatastoreSync()
  5. Extension pull is CLI-only: uses requireInitializedRepo() which acquires the distributed lock, serializing concurrent installs — no lockfile merge conflicts

Scope

In scope:

  • Model definitions (models/)
  • Workflow definitions (workflows/)
  • Vault configurations (vaults/) — config YAML only, not encrypted secrets
  • Extension lockfile (upstream_extensions.json)
  • Pulled extension sources (.swamp/pulled-extensions/)

Not in scope:

  • Vault secrets (.swamp/secrets/) — always local, security boundary
  • Extension bundles (.swamp/bundles/) — always local, derived artifacts
  • .swamp.yaml itself — must remain local to bootstrap the datastore config
  • serve.yaml — local per-instance server configuration
  • Hot-reload for remote config changes — instances see changes on restart (follow-up)

Open Questions

  1. Should swamp serve auto-migrate on first start when it detects managedConfig: true but no migration sentinel, or require explicit swamp datastore config migrate?
  2. Does the sync pipeline handle file deletions for these new directories (e.g., deleting a definition on one instance)?
  3. Should extension re-bundling after hydration happen lazily (existing ensureLoaded() pattern) or eagerly at startup?
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW

Triaged

8/10/2026, 3:24:47 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack728/10/2026, 3:21:16 PM

Sign in to post a ripple.