Skip to content

Releases: systeminit/swamp

swamp 20260318.013358.0-sha.8dff2b77

18 Mar 01:34
Immutable release. Only release title and notes can be modified.
8dff2b7

Choose a tag to compare

What's Changed

  • docs: add extension datastore and driver skills (#752)

Summary

PRs #745-#750 built the full custom datastore/driver extension pipeline (type registries, loaders, extension push/pull, runtime wiring) but shipped with zero skill documentation. Without these skills, AI assistants have no guidance to help users build custom datastores or drivers.

This PR adds:

  • swamp-extension-datastore skill — Full documentation for creating custom datastore backends (GCS, Azure Blob, databases, etc.). Covers DatastoreProvider, DistributedLock, DatastoreVerifier, and DatastoreSyncService interfaces with quick start, working examples, API reference, and troubleshooting.
  • swamp-extension-driver skill — Full documentation for creating custom execution drivers (SSH, Lambda, Kubernetes, etc.). Covers ExecutionDriver, ExecutionRequest, ExecutionResult, and DriverOutput interfaces with quick start, working examples, API reference, and troubleshooting.
  • swamp-repo skill updates — Adds "Custom Datastores" and "Custom Drivers" subsections with .swamp.yaml config format, env var format (SWAMP_DATASTORE='@org/name:{"key":"val"}'), and cross-references to the new skills. Updated "When to Use Other Skills" table.
  • skill_assets.ts — Both new skills (8 files total) registered in BUNDLED_SKILLS so they are installed during swamp repo init and swamp repo upgrade.
  • skill_assets_test.ts — 4 new tests verifying all skill files are discovered and copied correctly.

User Impact

Before this PR, users who wanted to create a custom datastore or driver had to read the TypeScript source code directly — there was no skill to guide them through the workflow, export contract, configuration, or verification steps.

After this PR:

  • AI assistants can guide users through the full create → configure → verify workflow for both datastores and drivers
  • swamp repo init and swamp repo upgrade install the new skills automatically
  • The swamp-repo skill now documents custom datastore/driver configuration alongside the built-in filesystem and S3 options

Why This Is Correct

  • All interface signatures were verified against the actual source files (datastore_provider.ts, distributed_lock.ts, datastore_health.ts, datastore_sync_service.ts, execution_driver.ts, docker_execution_driver.ts, driver_resolution.ts, user_datastore_loader.ts, user_driver_loader.ts, resolve_datastore.ts)
  • Skill structure follows the established pattern from swamp-extension-model and swamp-vault skills
  • Both new skills score 100% on tessl skill review validation (description + content)
  • All 27 skill asset tests pass
  • deno check, deno lint pass with no regressions

Test Plan

  • deno check — no type errors
  • deno lint — no lint issues
  • deno run test src/infrastructure/assets/skill_assets_test.ts — 27/27 pass (4 new)
  • npx tessl skill review .claude/skills/swamp-extension-datastore — 100%
  • npx tessl skill review .claude/skills/swamp-extension-driver — 100%
  • npx tessl skill review .claude/skills/swamp-repo — 100%

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.013358.0-sha.8dff2b77/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.013358.0-sha.8dff2b77/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.013358.0-sha.8dff2b77/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.013358.0-sha.8dff2b77/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260318.010420.0-sha.4aba80d3

18 Mar 01:05
Immutable release. Only release title and notes can be modified.
4aba80d

Choose a tag to compare

What's Changed

  • fix: health-check embedded deno after extraction, fall back to system deno on failure (#750)

Root Cause

When the compiled swamp binary extracts the embedded deno via Deno.writeFile, macOS records the writing process's provenance in com.apple.provenance. In certain conditions — a stale binary left by a prior swamp version, or OS-level security policy differences between how a programmatically-written file vs a user-copied file is treated — the extracted binary gets SIGKILL'd (exit 137) when spawned as a subprocess.

This produced the silent failure reported in the issue:

error: Bundle compilation failed:
  "/path/to/extensions/models/hello.ts": "deno bundle failed for /path/to/hello.ts: "

Exit code non-zero, stderr empty, stdout empty — because the deno subprocess never ran at all.

Why the Previous Fixes Were Wrong

Two prior commits attempted to address this symptom:

  • #748 (5705468c) — treated empty output from deno fmt/deno lint as a pass, to avoid false-positive quality check failures. This masked the SIGKILL rather than fixing it: the quality check silently passed, and the failure surfaced later at bundle time with an even more confusing empty error.
  • #750 (1efdc301) — added --unstable-bundle to the deno bundle invocation, assuming a deno 2.7.x flag change was the cause. Testing confirmed deno 2.7.5 bundles correctly without this flag. The root cause was the bad binary, not a missing flag.

Both commits are reverted in this PR.

Mitigations Added in EmbeddedDenoRuntime

1. Health check after extraction

After writing the binary, swamp immediately runs deno --version. If it fails (SIGKILL, permission error, or any other cause), swamp re-extracts rather than caching a broken path. The health check also runs on the "version already matches" fast path, so a stale/broken binary from a prior swamp version is caught on first use after upgrade.

2. xattr -c after writing (macOS only)

After writing the extracted binary, swamp runs xattr -c <path> to clear extended attributes. This is best-effort — macOS re-adds com.apple.provenance — but may prevent restrictions in configurations where the provenance value written during extraction differs from what macOS expects.

3. System deno fallback

If the extracted binary still fails the health check after a fresh extraction, swamp searches PATH for a system-installed deno and uses it with a warning. If no system deno is found either, a clear error is thrown:

Embedded deno at ~/.swamp/deno/deno failed health check and no system deno found in PATH.
Try: xattr -c ~/.swamp/deno/deno

Also Reverted

File Change
src/domain/models/bundle.ts Removed --unstable-bundle (not needed on deno 2.7.5)
src/domain/extensions/extension_quality_checker.ts Removed empty-output-as-pass logic (was masking failures; health check now catches bad binaries before quality checking runs)

Test Plan

  • Deleted ~/.swamp/deno/, ran swamp extension push --dry-run with newly compiled binary — fresh extraction succeeded, deno --version health check passed, bundle completed
  • Verified ~/.swamp/deno/deno runs cleanly (exit 0) after extraction by new binary
  • Full test suite: 3183 tests pass, 0 failed
  • deno fmt --check and deno lint clean

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.010420.0-sha.4aba80d3/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.010420.0-sha.4aba80d3/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.010420.0-sha.4aba80d3/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.010420.0-sha.4aba80d3/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260318.000231.0-sha.42789cff

18 Mar 00:03
Immutable release. Only release title and notes can be modified.
42789cf

Choose a tag to compare

What's Changed

  • feat: wire custom datastores into repo context (#749)

Summary

PR 3 of 4 in the custom datastore extension series. PRs 1-2 (#735, #745) established the datastore type registry, loader, and extension push/pull. This PR wires registered custom datastore types into the runtime — every switch point in the repo context that previously hardcoded if (type === "filesystem") ... else if (type === "s3") ... now has a third path that delegates to the DatastoreProvider obtained from the registry.

  • Add CustomDatastoreConfig to the DatastoreConfig discriminated union with eagerly-resolved datastorePath/cachePath
  • Handle custom types in resolve_datastore.ts for env var, CLI arg, and .swamp.yaml paths
  • Add custom branches to all 6 repo_context.ts switch points (read-only, locked, unlocked, model lock, model lock acquisition, global lock)
  • Wire custom verifier/sync into datastore status, datastore sync, and datastore lock commands
  • Generalize DatastoreSyncCoordinator to accept any SyncableService, not just S3CacheSyncService
  • 11 new tests covering custom type resolution, config validation, type guard, and error paths

Design decisions and trade-offs

Built-in paths untouched

The filesystem and S3 code paths are not modified — they continue to use their richer interfaces (S3CacheSyncService.pushAll(), pullChangedForModel(), etc.) that the generic DatastoreProvider interface cannot expose. Custom types get the generic pullChanged()/pushChanged() interface. This means custom datastores don't support model-scoped sync (they pull everything), but it avoids breaking the well-tested built-in paths.

Custom check first for type narrowing

Because CustomDatastoreConfig.type is string (it can be any registered type name), TypeScript can't narrow the discriminated union when checking type === "filesystem" first. All switch points check isCustomDatastoreConfig() first, then the built-in types narrow correctly in else if / else branches. This is a compile-time concern only — no runtime cost.

Single provider instance in acquireModelLocks

The custom DatastoreProvider is resolved once at the top of acquireModelLocks and reused for global lock inspection, per-model lock creation, sync service creation, and the flush push lock. This avoids repeated registry lookups and prevents correctness issues with stateful providers that track locks internally.

Sync coordinator label parameter

The coordinator's log messages now use a label parameter ("S3", the custom type name, etc.) instead of hardcoded "S3". Existing S3 users see identical log output — the label defaults to "datastore" but S3 registration passes "S3" explicitly.

No health check on read-only path

The read-only path (requireInitializedRepoReadOnly) does not run a health check for custom datastores — it only ensures the cache directory exists, matching what S3 does. Health checks run in datastore status where they belong. This avoids adding potentially slow network round-trips to every read-only command (search, list, get, validate).

datastore sync for custom types

Custom sync uses the generic pullChanged()/pushChanged() interface (no pushAll/pullAll/sync full-sync methods). The datastore sync command for custom types does pull + push sequentially. This parallels how requireInitializedRepo also registers a sync service with the coordinator, so there is some redundant pull/push — but this matches the existing S3 pattern where the coordinator does incremental sync and the manual command does full sync.

User impact

  • Filesystem users: Zero change. No new code executes.
  • S3 users: Zero behavioral change. Log messages unchanged. Same lock/sync lifecycle.
  • Custom datastore users: Can now configure a custom datastore in .swamp.yaml or via SWAMP_DATASTORE env var and have it work with locking, sync, health checks, and all CLI commands.

Verification

  • deno check — clean (0 errors)
  • deno lint — clean
  • deno fmt — clean
  • deno run test — 3186 passed, 0 failed
  • deno run compile — binary compiles

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.000231.0-sha.42789cff/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.000231.0-sha.42789cff/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.000231.0-sha.42789cff/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.000231.0-sha.42789cff/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.234411.0-sha.5705468c

17 Mar 23:45
Immutable release. Only release title and notes can be modified.
5705468

Choose a tag to compare

What's Changed

  • fix: skip quality-check false positives when deno 2.7.x exits non-zero with no output (#748)

Summary

  • extension push was blocked by spurious quality-check failures on Deno 2.7.5 where both deno fmt --check --no-config and deno lint --no-config exit with a non-zero code but write nothing to stdout or stderr
  • The checker was treating any non-zero exit code as a real quality issue, producing "Formatting" and "Lint" errors with empty "" descriptions
  • Fix: only add a quality issue to the result when the tool produces non-empty output — an empty-output non-zero exit is a deno version-specific no-op, not a real problem

Root cause

Deno 2.7.x introduced a behavioural change where deno fmt --check --no-config and deno lint --no-config can exit 1 with no diagnostic output when run as a subprocess via Deno.Command with piped stdio (confirmed on Deno 2.7.5, macOS aarch64). On Deno 2.6.x the same invocation exits 0 on clean files.

Every known version of deno fmt --check and deno lint that detects a real formatting or lint problem always writes a non-empty diagnostic to stderr. An empty-output non-zero exit is therefore a version-specific no-op rather than a genuine quality failure, so skipping it is safe.

The deno changelog and issue tracker do not document this as an intentional change; it is most likely a regression introduced in the 2.7.x series related to how these tools detect TTY/pipe mode and gate diagnostic output accordingly.

Test plan

  • All 25 extension_quality_checker_test.ts tests continue to pass
  • deno fmt --check — no formatting issues
  • deno lint — no lint errors
  • deno run test — 3183 passed, 0 failed

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.234411.0-sha.5705468c/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.234411.0-sha.5705468c/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.234411.0-sha.5705468c/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.234411.0-sha.5705468c/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.225941.0-sha.96bd3573

17 Mar 23:00
Immutable release. Only release title and notes can be modified.
96bd357

Choose a tag to compare

What's Changed

  • fix: guard against path traversal in extension archive extraction and add driver/datastore tests (#746)

Summary

Addresses two issues raised in PR review:

  • Path traversal during archive extraction (src/cli/commands/extension_pull.ts): After tar extracts an extension archive to a temp directory, each extracted file path is now resolved and validated to confirm it starts within the temp directory. If any entry contains path traversal sequences (e.g. ../../.bashrc) that would escape the temp dir, a UserError is thrown before any further processing occurs.

  • Missing test coverage for driver/datastore content extraction (src/domain/extensions/extension_content_extractor_test.ts): Added 8 unit tests for extractDriverFromSource and extractDatastoreFromSource following the same patterns as the existing vault tests:

    • Extracts type, name, and description
    • Extracts configSchema fields (inline z.object)
    • Skips files without the relevant export (driver / datastore)
    • Skips exports that are missing the required type field

Test Plan

  • All 3183 existing tests continue to pass (deno run test)
  • 8 new unit tests added and passing for driver/datastore extraction
  • deno check passes (no type errors)
  • deno lint passes (no lint errors)
  • deno fmt --check passes (no formatting issues)

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.225941.0-sha.96bd3573/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.225941.0-sha.96bd3573/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.225941.0-sha.96bd3573/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.225941.0-sha.96bd3573/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.223719.0-sha.9003347e

17 Mar 22:38
Immutable release. Only release title and notes can be modified.
9003347

Choose a tag to compare

What's Changed

  • fix: create models dir before writing upstream_extensions.json lock (#747)

Summary

Fixes #734.

When auto-resolving a vault-only extension (e.g. @swamp/1password), the installer fails if the extensions/models/ directory does not exist:

No such file or directory (os error 2): open '/private/tmp/swamp-vault-test/extensions/models/upstream_extensions.json.lock'

The root cause: installExtension always calls updateUpstreamExtensions (which creates upstream_extensions.json.lock inside modelsDir) regardless of whether the extension contains any models. Every other destination directory — vaults, workflows, drivers, datastores, bundles — was already guarded with Deno.mkdir({ recursive: true }) before use, but modelsDir was not.

The fix adds await Deno.mkdir(absoluteModelsDir, { recursive: true }) before the models copyDir call, making it consistent with all other directories.

Steps to Reproduce (from issue)

  1. swamp repo init in a fresh directory (no extensions/models/ exists)
  2. Create a vault config referencing @swamp/1password
  3. Run a vault command that triggers auto-resolution (e.g. swamp vault list-keys <name>)
  4. Extension is found and downloaded, but installation fails

Workaround: mkdir -p extensions/models/ before triggering auto-resolution.

Test Plan

  • Existing updateUpstreamExtensions unit tests pass
  • deno check, deno lint, deno fmt --check all pass

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.223719.0-sha.9003347e/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.223719.0-sha.9003347e/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.223719.0-sha.9003347e/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.223719.0-sha.9003347e/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.221248.0-sha.57baec4a

17 Mar 22:13
Immutable release. Only release title and notes can be modified.
57baec4

Choose a tag to compare

What's Changed

  • perf: defer self-contained bundle creation to first out-of-process execution (#743)

Problem

With 104+ user extension models, swamp model type search (and any other command that loads extensions) took ~46 seconds to start. After the fix in #741 that parallelised the 4 loader types and skipped loading for help/version commands, the remaining bottleneck was in UserModelLoader itself.

At startup, loadModels() eagerly built a self-contained bundle for every model file — a separate deno bundle subprocess per model that inlines all dependencies (including zod) so the bundle can run inside Docker containers without network access. With 104 models, this was 104 sequential subprocesses on every single CLI invocation, regardless of whether Docker execution would ever be used.

Architecture Decision & Tradeoffs

What changed

bundleSource?: string on ModelDefinition (a pre-built JS string stored at load time) has been replaced with bundleSourceFactory?: () => Promise<string> — a memoizing closure that defers the expensive work to the point of actual need.

// Before: runs at startup, for every model, every invocation
modelDef.bundleSource = await bundleExtension(absolutePath, denoPath, { selfContained: true });

// After: closure set at load time, executed only on first Docker execution
let cachedBundle: string | undefined;
modelDef.bundleSourceFactory = async () => {
  if (!cachedBundle) {
    cachedBundle = await bundleExtension(absolutePath, denoPath, { selfContained: true });
  }
  return cachedBundle;
};

Tradeoff: startup cost vs. first-execution cost

Before After
Every CLI invocation Pays bundling cost for all N models Pays nothing
First Docker execution of model A Already paid at startup Pays bundling cost for model A only
Second Docker execution of model A Pre-built Memoized in-process — instant

The first out-of-process execution of a given model will be slightly slower than before — it now bundles on demand rather than having it pre-built. This is the right tradeoff because:

  1. Docker execution is rare relative to everyday CLI usage (type search, model get, data list, etc.)
  2. Cost is proportional to actual need — only the models you actually run out-of-process are ever bundled
  3. Memoization ensures the cost is paid at most once per model per process invocation
  4. The startup tax was paid unconditionally regardless of what command you ran — even read-only commands that never touch Docker

Why only models?

Vaults, drivers, and datastores do not create self-contained bundles at all — they only use the externalized (cached) bundle for in-process execution. This change is model-specific because only models support out-of-process/Docker execution via bundleSource.

User Impact

Measured on a real repo with 104 extension models:

Command Before After
swamp model type search aws ~46 seconds ~2.8 seconds
swamp model get my-model ~46 seconds ~2.8 seconds
swamp data list ~46 seconds ~2.8 seconds
First Docker model run Instant (pre-built) ~same as before (built on demand)

16x speedup for the everyday command path. The remaining ~2.8s is the warm-cache cost of the externalized bundle loading (disk reads + dynamic imports for 104 files), which is a separate optimization opportunity.

Files Changed

File Change
src/domain/models/model.ts bundleSource?: stringbundleSourceFactory?: () => Promise<string>
src/domain/models/user_model_loader.ts Remove eager bundling, set memoizing factory closure
src/domain/models/method_execution_service.ts Await bundleSourceFactory?.() at execution time

Test Plan

  • deno check — type checking passes
  • deno lint — no lint errors
  • deno fmt --check — formatting correct
  • deno run test — 3175 tests passed, 0 failed
  • deno run compile — binary compiled successfully
  • Manual: swamp model type search in 104-model repo — 46s → 2.8s

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221248.0-sha.57baec4a/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221248.0-sha.57baec4a/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221248.0-sha.57baec4a/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221248.0-sha.57baec4a/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.221128.0-sha.4ff54080

17 Mar 22:12
Immutable release. Only release title and notes can be modified.
57baec4

Choose a tag to compare

What's Changed

  • feat: add driver and datastore support to extension push/pull (#745)

Summary

  • Extend the extension system to support packaging and distributing drivers and datastores alongside models, workflows, and vaults
  • Extensions can now be driver-only or datastore-only — no longer require models or workflows
  • This is PR 2 of 4 in the Extension Drivers & Datastores series (builds on #735)

What changed

Manifest schema

  • New optional drivers and datastores array fields
  • Validation accepts at least one of: models, workflows, vaults, drivers, or datastores

Push (extension push)

  • Resolves driver/datastore files from extensions/drivers/ and extensions/datastores/ with transitive import resolution
  • Bundles each entry point to standalone JS
  • Adds drivers/, driver-bundles/, datastores/, datastore-bundles/ to archive
  • Runs safety analysis and quality checks on all TypeScript files
  • Validates collective naming for driver/datastore types
  • Extracts content metadata (type, name, description, configSchema fields)

Pull (extension pull)

  • Extracts and installs driver/datastore files to correct directories
  • Conflict detection for driver/datastore paths and bundle paths
  • Safety analysis on driver/datastore TypeScript files
  • Tracks all files in upstream_extensions.json

Content extraction

  • ExtractedDriver and ExtractedDatastore types
  • Detects export const driver + createDriver and export const datastore + createProvider patterns
  • Config schema field extraction for both

Updated commands

  • extension search, extension update, extension fmt, and auto-resolver all pass driversDir/datastoresDir through install contexts

Documentation

  • design/extension.md — updated archive structure, file extraction table, manifest fields
  • swamp-extension-model skill — updated publishing reference (manifest schema, field reference, content mapping, push workflow, error messages)
  • swamp-repo skill — updated repository structure and .swamp.yaml config reference

User-facing behavior

Users can create and distribute driver-only or datastore-only extensions:

manifestVersion: 1
name: "@myorg/custom-driver"
version: "2026.03.17.1"
drivers:
  - my_driver.ts

swamp extension push bundles and uploads. swamp extension pull installs to the correct directories. The server accepts the new archive directories without changes (they pass through opaquely).

Test plan

  • deno check — type checking passes
  • deno lint — no lint errors (649 files)
  • deno fmt — formatting clean (702 files)
  • deno run test — 3175 passed, 0 failed
  • deno run compile — binary compiles

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221128.0-sha.4ff54080/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221128.0-sha.4ff54080/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221128.0-sha.4ff54080/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.221128.0-sha.4ff54080/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.220019.0-sha.62783440

17 Mar 22:01
Immutable release. Only release title and notes can be modified.
6278344

Choose a tag to compare

What's Changed

  • fix: improve vault create UX for deprecated types and optional config (#744)

Summary

  • Deprecated type hint: When a user passes a renamed vault type (e.g. aws-sm, azure-kv), the error now says "The type 'aws-sm' has been renamed to '@swamp/aws-sm'. Use: swamp vault create @swamp/aws-sm " instead of the generic "Unknown vault type" message. Achieved by exporting RENAMED_VAULT_TYPES from vault_service.ts and checking it in the vault_create error path.
  • Optional --config for extension vaults: Extension vault types no longer require --config to be passed. Omitting it defaults to {}, which is then validated against configSchema if one is defined. Users with config-free extension vaults no longer need to pass --config '{}'.

Test Plan

  • deno fmt --check passes
  • deno lint passes
  • deno task test passes (3175 tests, 0 failed)
  • swamp vault create aws-sm my-vault gives rename hint instead of generic error
  • swamp vault create @swamp/aws-sm my-vault (without --config) defaults to {}

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.220019.0-sha.62783440/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.220019.0-sha.62783440/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.220019.0-sha.62783440/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.220019.0-sha.62783440/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260317.212534.0-sha.5ac636c1

17 Mar 21:26
Immutable release. Only release title and notes can be modified.
5ac636c

Choose a tag to compare

What's Changed

  • fix: use pre-built bundle when dependency freshness check fails (#742)

Closes #737

Summary

When an extension is pulled from the registry, swamp discards the valid pre-built bundle and fails with Module not found if any local dependency file is missing from disk. This fix makes bundleWithCache fall back to the cached bundle when the freshness check fails, rather than attempting a re-bundle that will also fail.

Root cause

bundleWithCache validates cache freshness by resolving all local imports from the .ts source file and comparing mtimes. If a dependency file is missing (because the extension was pushed with an older swamp that had a single-line import regex and missed multi-line import declarations), Deno.stat() throws inside the try block. The catch block then falls through to re-bundle from source — which fails with the same Module not found error.

The @keeb/grafana extension hits this exactly: grafana_instance.ts has a multi-line import for ./lib/grafana.ts. The older push regex only matched single-line imports, so lib/grafana.ts was never included in the archive. The pre-built bundle at .swamp/bundles/grafana_instance.js is perfectly valid (compiled at push time with all deps), but every load attempt discards it and fails.

The catch block comment said "Bundle doesn't exist, stat failed, or import resolution failed — rebundle", conflating two distinct cases:

  1. Bundle file does not exist → rebundle from source ✅ correct
  2. Bundle exists but freshness check threw → rebundle from source ❌ wrong — the bundle is valid

Fix

Track bundleExists before entering the try/catch. If the bundle file exists but the freshness check throws for any reason, use the cached bundle as a fallback and log at debug level. Only attempt a re-bundle when the bundle genuinely doesn't exist.

Applied to all four loaders: model, vault, driver, datastore.

User impact

Before: swamp extension install @keeb/grafana succeeds but swamp model type search grafana fails with deno bundle failed ... Module not found "lib/grafana.ts".

After: The pre-built bundle is used as a fallback. @keeb/grafana/instance appears in search results with no errors.

Verification

  • deno check — passes
  • deno lint — passes
  • deno fmt — passes
  • deno run test — 3161 passed, 0 failed
  • deno run compile — binary compiles
  • Manual: swamp extension install @keeb/grafanaswamp model type search grafana returns @keeb/grafana/instance

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.212534.0-sha.5ac636c1/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.212534.0-sha.5ac636c1/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.212534.0-sha.5ac636c1/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260317.212534.0-sha.5ac636c1/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/