Skip to content

Releases: systeminit/swamp

swamp 20260319.184717.0-sha.0e4c970c

19 Mar 18:48
Immutable release. Only release title and notes can be modified.
0e4c970

Choose a tag to compare

What's Changed

  • docs: document --input key=value syntax in skills (#780)

Summary

  • Update swamp-model and swamp-workflow skills to document the --input key=value syntax as the preferred form for simple scalar inputs
  • Keep JSON blob syntax (--input '{}') as a documented alternative for complex structures (arrays, nested objects)
  • Fix options tables that described --input as --input <json> to --input <value>

Context

A user filed #760 requesting --arg key=value support, not knowing that --input key=value already works. Every example in our skills only showed the JSON blob form, making the key-value syntax invisible. This PR fixes that documentation gap.

Files changed

  • .claude/skills/swamp-model/SKILL.md — Quick reference, examples, options table
  • .claude/skills/swamp-model/references/examples.md — Runtime inputs section
  • .claude/skills/swamp-model/references/scenarios.md — Runtime inputs scenario
  • .claude/skills/swamp-workflow/SKILL.md — Quick reference, examples, options table
  • .claude/skills/swamp-workflow/references/scenarios.md — Nested workflow example

Test plan

  • Verify swamp model method run <name> <method> --input key=value --json works as documented
  • Verify swamp workflow run <name> --input key=value --json works as documented
  • Verify JSON form still works: --input '{"key": "value"}'
  • Verify dot notation works: --input config.timeout=30

Closes #760

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.184717.0-sha.0e4c970c/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/v20260319.184717.0-sha.0e4c970c/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/v20260319.184717.0-sha.0e4c970c/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/v20260319.184717.0-sha.0e4c970c/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.180241.0-sha.12ca0b71

19 Mar 18:03
Immutable release. Only release title and notes can be modified.
12ca0b7

Choose a tag to compare

What's Changed

  • feat: support environment variable expansion in datastore paths (#779)

Summary

Fixes #775

The filesystem datastore path in .swamp.yaml was stored as an absolute path (e.g. /Users/blake.irvin/.swamp/hello-swamp), which breaks portability when the repo is cloned on a different machine or user account.

This PR adds environment variable expansion to datastore paths, so .swamp.yaml can store portable paths like $HOME/.swamp/hello-swamp that resolve correctly at runtime on any machine.

What changed

  • New expandEnvVars(path) — expands ~, $VAR, and ${VAR} references from the environment at runtime. Throws a clear UserError if a referenced variable is not set.
  • New collapseEnvVars(path) — when swamp datastore setup filesystem writes to .swamp.yaml, it collapses the $HOME prefix back to $HOME/... so the stored path is portable by default.
  • Applied at both read points — env var / CLI --datastore arg and .swamp.yaml filesystem path both expand env vars before use.

Why general env var expansion (not just $HOME)

We considered special-casing only $HOME/~, but teams may use other env vars too — $XDG_DATA_HOME for XDG compliance, $SWAMP_DATA_ROOT for shared NFS mounts, or $PROJECT_DATA_DIR in CI. General $VAR/${VAR} expansion covers all these cases with the same small amount of code.

Manual verification

Compiled the binary, then:

$ mkdir /tmp/swamp-env-test && cd /tmp/swamp-env-test
$ swamp repo init
$ swamp datastore setup filesystem --path ~/.swamp/env-test-store

Confirmed .swamp.yaml stores the portable path:

datastore:
  type: filesystem
  path: $HOME/.swamp/env-test-store

Confirmed swamp datastore status resolves it correctly:

Datastore Status
  Type:    filesystem
  Path:    /Users/stack72/.swamp/env-test-store
  Health:  ● healthy (1ms)

Test plan

  • 14 new unit tests for expandEnvVars and collapseEnvVars (tilde, $VAR, ${VAR}, undefined vars throw, passthrough, roundtrip)
  • All 3393 existing tests pass
  • deno check, deno lint, deno fmt all clean
  • Manual end-to-end test with compiled binary

🤖 Generated with Claude Code

Co-authored-by: Blake Irvin blakeirvin@me.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.180241.0-sha.12ca0b71/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/v20260319.180241.0-sha.12ca0b71/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/v20260319.180241.0-sha.12ca0b71/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/v20260319.180241.0-sha.12ca0b71/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.173738.0-sha.1a4711da

19 Mar 17:38
Immutable release. Only release title and notes can be modified.
1a4711d

Choose a tag to compare

What's Changed

  • fix: silence spurious warnings for type-only .ts files in extension models (#778)

Summary

Fixes #776.

  • When extension models use a modular file structure with type-only .ts files (e.g., my_model/types.ts), bundleExtension() threw on the empty output because TypeScript erases interfaces and type aliases at compile time. This surfaced as noisy warnings during model loading even though the models worked fine.
  • Replace the throw with a minimal export {}; module so the existing loader skip logic (which already silently skips files without model/extension exports) handles these files naturally.
  • The fix is in the shared bundleExtension() function, so it applies to all 4 loaders (models, vaults, drivers, datastores) with no loader changes needed.

User impact

Users with modular extension models that include helper type files (interfaces, type aliases) will no longer see confusing "deno bundle produced empty output" warnings. No behavior change for valid models.

Test plan

  • New unit test: bundleExtension returns minimal module for type-only files — verifies empty bundle produces export {}; instead of throwing
  • New integration test: UserModelLoader silently skips type-only .ts files in subdirectories — verifies type-only files in a model subdirectory don't appear in result.failed
  • All existing tests pass (deno run test, deno check, deno lint, deno fmt)

🤖 Generated with Claude Code

Co-authored-by: Blake Irvin blakeirvin@me.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.173738.0-sha.1a4711da/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/v20260319.173738.0-sha.1a4711da/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/v20260319.173738.0-sha.1a4711da/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/v20260319.173738.0-sha.1a4711da/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.155838.0-sha.5364c61c

19 Mar 15:59
Immutable release. Only release title and notes can be modified.
5364c61

Choose a tag to compare

What's Changed

  • feat: search community extensions before creating custom models (#777)

feat: search community extensions before creating custom models

Summary

  • Rewrites Rule #1 in the CLAUDE.md template from "Extension models for service integrations" to "Search before you build", with explicit steps: search local types → search community extensions (swamp extension pull) → install if found → only then create custom
  • Adds a community search step to the swamp-model skill workflow
  • Adds Scenario 5 ("Community Extension Found") to the swamp-extension-model skill showing the happy path where a community extension exists

User Impact

Previously, agents only saw guidance to "create an extension model" in the CLAUDE.md Rules section. The swamp-extension-model skill documented the search-first flow, but agents only loaded that skill after deciding to create a model — too late. Now agents see the search-first guidance immediately in Rule #1, prompting them to run swamp extension search before building anything custom.

Test Plan

  • New unit test: RepoService.init generates CLAUDE.md with extension search guidance — asserts generated CLAUDE.md contains extension search, Search before you build, and swamp model type search
  • All 78 repo service tests pass
  • Full test suite passes
  • deno check, deno lint, deno fmt all pass
  • deno run compile — binary recompiled
  • Manual verification: Asked an agent to "create me a model that I can use to create an aws ec2 instance" — the agent correctly ran swamp model type search "ec2" followed by swamp extension search "ec2 instance" before attempting to create anything, then found a community extension and used swamp extension pull to install it

Closes #757

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.155838.0-sha.5364c61c/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/v20260319.155838.0-sha.5364c61c/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/v20260319.155838.0-sha.5364c61c/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/v20260319.155838.0-sha.5364c61c/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.021849.0-sha.a5b52081

19 Mar 02:19
Immutable release. Only release title and notes can be modified.
a5b5208

Choose a tag to compare

What's Changed

  • feat: add swamp-extension-vault skill for custom vault providers (#773)

Summary

  • Add the missing swamp-extension-vault skill to complete the full set of extension content type skills
  • Previously only 3 of 4 extension types had creation skills: swamp-extension-model, swamp-extension-driver, swamp-extension-datastore — vaults were the gap
  • Add swamp-extension-vault to the skills list in both CLAUDE.md and the generated template in repo_service.ts

What's included

The new skill at .claude/skills/swamp-extension-vault/ contains:

File Purpose
SKILL.md Main skill doc — quick start template, export contract (type, name, description, configSchema, createProvider), VaultProvider interface (get, put, list, getName), configuration via .swamp.yaml, development workflow, discovery/loading rules, key rules, cross-references
references/api.md Full VaultProvider and VaultConfiguration interface documentation sourced from vault_provider.ts
references/examples.md Three complete working examples: in-memory vault, HTTP API vault, encrypted file vault with AES-GCM
references/troubleshooting.md Common issues: type not found, config validation, stale bundles, auth failures, network errors

Why this is correct

  • Follows the exact same structure as swamp-extension-datastore (closest analogue — both are TypeScript files exporting a named const with type, name, description, configSchema, createProvider)
  • Export contract matches the UserVaultSchema in src/domain/vaults/user_vault_loader.ts exactly
  • VaultProvider interface matches src/domain/vaults/vault_provider.ts exactly
  • Key difference from datastores correctly documented: createProvider takes two args (name, config) vs datastores' single (config) arg
  • Scores 100% on npx tessl skill review
  • All 77 repo_service tests pass with the template update

Impact

  • AI coding assistants (Claude, Cursor, etc.) can now guide users through creating custom vault providers without needing to reverse-engineer the interface from source code
  • Completes the extension skill matrix — all 4 extension content types now have dedicated creation skills

Test Plan

  • npx tessl skill review .claude/skills/swamp-extension-vault — 100% (description 100%, content 100%)
  • deno run test src/domain/repo/repo_service_test.ts — 77/77 pass
  • No conflicts with upstream changes (resolved cleanly after but pull)

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.021849.0-sha.a5b52081/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/v20260319.021849.0-sha.a5b52081/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/v20260319.021849.0-sha.a5b52081/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/v20260319.021849.0-sha.a5b52081/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.020120.0-sha.17c0bda6

19 Mar 02:02
Immutable release. Only release title and notes can be modified.
17c0bda

Choose a tag to compare

What's Changed

  • feat: add package.json support and fix ambient package.json interference (#772)

Summary

  • Extensions can now live inside existing Node/TypeScript projects with package.json dependency management
  • Fixes a critical bug where an unrelated package.json in the directory tree breaks all npm: prefixed extension imports (#617)
  • Resolves no-import-prefix lint conflicts by enabling bare specifiers via package.json (#758)
  • Supersedes the documentation workaround in #693

Problem

Two related issues were affecting users:

  1. Issue #617: A user added package.json to their repo root for @anthropic-ai/claude-code. This caused Deno to switch to node_modules/ resolution mode, breaking all extension bundling with:

    error: Could not find a matching package for 'npm:@octokit/rest@22.0.1' in the node_modules directory.
    
  2. Issue #758: Extensions using npm: and jsr: inline specifiers conflict with Deno's no-import-prefix lint rule, forcing every file to include // deno-lint-ignore no-import-prefix suppress comments. Users wanted to use bare specifiers via package.json instead.

What changed

src/domain/models/bundle.ts

  • Added packageJsonDir?: string to BundleOptions — mutually exclusive with denoConfigPath
  • When packageJsonDir is set: uses --node-modules-dir=auto (works with both npm install and deno install), sets cwd on the subprocess so Deno auto-detects package.json
  • When NO project config is used: now passes --node-modules-dir=none to prevent any ambient package.json in the directory tree from interfering with npm: prefixed imports
  • Added isZod4InPackageJson() — reads dependencies/devDependencies for zod 4.x, externalizes bare "zod" specifier when found
  • Added join import from @std/path

src/cli/commands/extension_push.ts

  • Added findPackageJson() — same walk-up pattern as findDenoConfig, returns the directory containing package.json
  • Added requireNodeModules() — validates node_modules/ exists, throws UserError with clear instructions if missing
  • Added bare specifier gate: only uses a detected package.json when at least one extension entry point contains bare specifiers (via sourceHasBareSpecifiers). This prevents an unrelated package.json (e.g., for tooling) from being mistakenly treated as the extension's project config
  • findDenoConfig is completely untouched — zero regression risk for the deno.json path
  • Updated bundleOptions derivation to include packageJsonDir

Detection logic

Detection is sequential, not interleaved, to guarantee deno.json always wins:

  1. Walk up from manifest to repo root looking for deno.json (full walk)
  2. Only if no deno.json found: walk up looking for package.json
  3. Only if package.json found AND extension has bare specifiers: use it
  4. Otherwise: no project config (default behavior with --node-modules-dir=none)

This design prevents the scenario where a package.json at a closer directory level would shadow a deno.json higher up.

Bundling permutations

Scenario deno bundle flags Quality check flags
deno.json found --config <path> --config <path>
package.json found, bare specifiers --node-modules-dir=auto, cwd set --no-config
package.json found, npm: imports --no-lock --node-modules-dir=none --no-config
No config found --no-lock --node-modules-dir=none --no-config

Design docs and skills

  • design/extension.md — Complete rewrite of project-aware bundling section with decision matrix table, bare specifier gate explanation, --node-modules-dir=none rationale, and updated zod externalization/runtime caching sections
  • swamp-extension-model/SKILL.md — Updated import and version pinning rules to include package.json
  • swamp-extension-model/references/examples.md — Added package.json import style example with node_modules/ requirement note
  • swamp-extension-model/references/publishing.md — Updated "Detect project config" step to cover both config types
  • swamp-extension-driver/SKILL.md — Updated pin versions rule
  • swamp-extension-datastore/SKILL.md — Updated pin versions rule

User impact

Extensions in Node/TypeScript projects (new capability)

Users with package.json and bare specifiers can now swamp extension push without creating a deno.json wrapper. Requires node_modules/ from npm install or deno install.

Unrelated package.json no longer breaks extensions (bug fix)

Users who add a package.json to their repo for unrelated tooling (e.g., @anthropic-ai/claude-code, husky, prettier) will no longer see their extension bundling break. The --node-modules-dir=none flag prevents Deno from switching to node_modules/ resolution mode.

Lint conflict resolution (improvement)

Users can now use bare specifiers via package.json (or deno.json) to avoid the no-import-prefix lint rule conflict, eliminating the need for suppress comments on every import line.

Existing extensions (no change)

Extensions with deno.json — unchanged (detection code untouched). Extensions with inline npm: deps and no config — unchanged (same flags plus --node-modules-dir=none safety net). Pulled extensions — unchanged (cached bundle preference already handles bare specifiers).

Testing performed

Automated (3376 tests, 0 failed)

  • deno check — zero type errors
  • deno lint — all files clean
  • deno fmt --check — all files clean
  • deno run test — 3376 tests passed, 0 failed
  • Integration test: pull + load @stack72/letsencrypt-certificate@2026.03.04.1

Manual end-to-end (6 scenarios)

1. package.json + bare specifiers + npm install

  • Created fresh swamp repo with package.json containing zod@4.3.6 and @aws-sdk/client-secrets-manager@3.1010.0
  • Extension source uses bare specifiers (from "zod", from "@aws-sdk/client-secrets-manager")
  • Ran npm install (NOT deno install)
  • swamp extension fmt manifest.yaml — passed
  • swamp extension push manifest.yaml --dry-run — produced 203.5KB archive
  • Debug log confirmed: Found package.json project at /private/tmp/swamp-ext-test
  • swamp vault type list — vault loaded successfully at runtime

2. package.json + bare specifiers + deno install

  • Same setup but used deno install instead of npm install
  • Push dry-run produced identical 203.5KB archive
  • Vault loaded at runtime

3. package.json without node_modules/ (error case)

  • Created repo with package.json and bare specifier extension, no npm install
  • swamp extension push manifest.yaml --dry-run failed with clear error:
    No node_modules/ found at /private/tmp/swamp-ext-test. Run 'npm install' or 'deno install' to install dependencies before pushing.

4. Unrelated package.json + npm: imports (issue #617 scenario)

  • Created repo with package.json containing only @anthropic-ai/claude-code
  • Extension uses npm:zod@4.3.6 (NOT bare specifiers)
  • Ran npm install
  • Debug log confirmed: Ignoring package.json at /private/tmp/swamp-ext-test (extension uses npm: prefixed imports)
  • Push dry-run produced 203.4KB archive — bundling succeeded with --node-modules-dir=none

5. deno.json regression check

  • Created repo with deno.json import map + bare specifiers (no package.json)
  • Push dry-run produced 203.4KB archive
  • Debug log confirmed: Found deno.json at /private/tmp/swamp-ext-test/deno.json
  • Behaviour identical to previous PR

6. deno.json takes precedence over package.json

  • Created repo with BOTH deno.json and package.json
  • Debug log confirmed only deno.json was detected — package.json was not even checked

7. Inline deps, no config files

  • Extension with npm:zod@4.3.6 imports, no deno.json, no package.json
  • Push dry-run produced 203.4KB archive
  • Zod externalized via source scanning

8. Pull + load existing extension

  • swamp extension pull @stack72/letsencrypt-certificate@2026.03.04.1 — succeeded
  • swamp model type search letsencrypt — found @stack72/letsencrypt-certificate

9. --node-modules-dir=auto compatibility

  • Verified deno bundle --node-modules-dir=auto auto-initializes node_modules/.deno/ metadata when only npm install was run
  • This is what makes npm install work (without it, deno bundle fails with "Did you forget to run deno install?")

10. Regex safety (from previous PR, still passing)

  • rewriteZodImports does NOT match zod-utils, zodiac, npm:zod@3, or zod@3
  • Only matches zod 4.x or unversioned bare "zod"

Test plan

  • CI passes (type check, lint, fmt, tests)
  • Verify swamp extension push --dry-run works for extension with package.json + bare specifiers
  • Verify unrelated package.json does not break extensions with npm: imports
  • Verify deno.json path is unchanged (regression check)
  • Verify swamp extension pull + runtime load works for existing published extensions

Closes #617
Closes #758
Supersedes #693

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.020120.0-sha.17c0bda6/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/v20260319.020120.0-sha.17c0bda6/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/v20260319.020120.0-sha.17c0bda6/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/v20260319.020120.0-sha.17c0bda6/swamp-linux-aarch64 -o swamp
chmod +x ...
Read more

swamp 20260319.011305.0-sha.1d5b7af1

19 Mar 01:14
Immutable release. Only release title and notes can be modified.
1d5b7af

Choose a tag to compare

What's Changed

  • docs: improve extension datastore skill workflow clarity (#771)

Summary

  • Replace flat "Verify" section in the swamp-extension-datastore skill with a numbered Development Workflow section
  • Adds explicit validation checkpoints and "if X fails, do Y" error recovery feedback loops
  • Addresses tessl skill review suggestions for workflow clarity, bringing the skill score from 94% to 100%

Context

PR #770 updated several extension skills but the datastore skill's workflow clarity scored 2/3 on the tessl review. This PR addresses the two specific suggestions:

  1. Add an explicit numbered workflow section that sequences the full create-configure-verify cycle
  2. Integrate verification commands and error recovery into the workflow with feedback loops

Test plan

  • npx tessl skill review .claude/skills/swamp-extension-datastore — 100% score (was 94%)

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.011305.0-sha.1d5b7af1/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/v20260319.011305.0-sha.1d5b7af1/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/v20260319.011305.0-sha.1d5b7af1/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/v20260319.011305.0-sha.1d5b7af1/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260319.010016.0-sha.bc242ef2

19 Mar 01:01
Immutable release. Only release title and notes can be modified.
bc242ef

Choose a tag to compare

What's Changed

  • feat: support deno.json project config for extension bundling (#770)

Summary

Extensions can now optionally include a deno.json file with an import map alongside their manifest.yaml. When present, swamp extension push uses it for dependency resolution (bundling) and quality checks (lint/fmt rules). This enables the swamp-extensions workflow where each extension is a self-contained Deno project with pinned dependencies, tests, and standard tooling.

Also fixes a pre-existing bug where fully-pinned zod versions (e.g., npm:zod@4.3.6) were silently inlined into bundles instead of being externalized.

What changed

Push path (3 files)

  • bundle.ts — Added denoConfigPath option to BundleOptions. When provided, uses --config <path> instead of --no-lock. Added source scanning for exact zod specifiers (e.g., npm:zod@4.3.6) to fix the pre-existing externalization bug. Added resolveZodFromConfig() to read the deno.json import map and externalize the mapped zod version. Updated rewriteZodImports() regex to handle bare "zod" specifiers (not just npm:zod), with safety guard to only match zod 4.x.
  • extension_quality_checker.ts — Added optional denoConfigPath parameter. When provided, uses --config <path> instead of --no-config for both deno fmt and deno lint.
  • extension_push.ts — Added findDenoConfig() that walks up from the manifest directory to the repo root (.swamp.yaml / .git boundary) looking for deno.json. Threads the result through to the quality checker and all four bundle loops (models, vaults, drivers, datastores).

Runtime path (4 files)

  • user_model_loader.ts, user_vault_loader.ts, user_driver_loader.ts, user_datastore_loader.ts — Added sourceHasBareSpecifiers() check before re-bundling. When source has bare specifiers (e.g., from "zod" instead of from "npm:zod@4") and a cached bundle exists, the loader uses the cached bundle instead of attempting a re-bundle that would fail without the deno.json import map. This handles pulled extensions that were built with a project config — the archive includes pre-built bundles but not the deno.json.

Tests

  • bundle_test.ts — 10 new tests: deno.json-aware bundling, bare specifier rewriting ("zod", "zod" star import, aliased), sourceHasBareSpecifiers (7 cases covering npm:, relative, jsr:, node:, bare, scoped)
  • extension_quality_checker_test.ts — 1 new test for denoConfigPath parameter
  • extension_pull_test.ts — 1 new integration test: pulls @stack72/letsencrypt-certificate@2026.03.04.1, verifies bundle extraction, and confirms the model type loads at runtime via model type search

Docs

  • design/extension.md — Documented project-aware bundling, zod externalization details, and runtime bundle caching
  • design/datastores.md — Added note about bare specifier cache fallback
  • Skills — Updated key rules in model, driver, and datastore skills; added import map examples to references/examples.md; updated push workflow steps in references/publishing.md

User impact

  • Extensions with deno.json: Users can write extensions as proper Deno projects with bare specifiers resolved via import maps. swamp extension push and swamp extension fmt honor the project config automatically.
  • Extensions without deno.json: Zero change in behavior. Existing extensions with npm: prefixed imports continue to work identically.
  • Zod externalization fix: Extensions using fully-pinned npm:zod@4.3.6 (like those in swamp-extensions) now correctly externalize zod instead of inlining it. This reduces bundle sizes (~203KB vs ~278KB compressed for the aws-sm extension) and ensures zod instanceof checks work correctly.
  • Pulled extensions: Extensions built with a deno.json project can be pulled and loaded at runtime without the deno.json — the pre-built bundle from the archive is used.

Design decisions

  1. Detection via walk-up, not config field: deno.json is detected by walking up from the manifest directory to the repo root, rather than adding a field to manifest.yaml. This avoids a schema change and mirrors how tools like tsconfig.json and .eslintrc are resolved.
  2. Repo root as boundary: The walk-up stops at .swamp.yaml / .git to prevent escaping the project and accidentally picking up an unrelated deno.json.
  3. Source scanning for zod version: Rather than parsing the full import map, the bundler scans the entry point source for the exact npm:zod@4.x.x specifier. This fixes both inline and import-map scenarios with one mechanism.
  4. Conservative regex: rewriteZodImports only matches zod 4.x or unversioned — zod@3 is explicitly excluded to prevent silent runtime breakage.
  5. Cached bundle preference: Runtime loaders check sourceHasBareSpecifiers() before re-bundling. This is conservative — it prefers a known-good cached bundle over a re-bundle that will fail.

Testing performed

Automated (3376 tests, 0 failed)

  • deno check — zero type errors across all files
  • deno lint — 736 files clean
  • deno fmt --check — 797 files clean
  • deno run test — 3376 tests passed, 0 failed
  • Integration test: pull + load @stack72/letsencrypt-certificate@2026.03.04.1

Manual end-to-end

  1. Import map path: Created aws-sm extension with deno.json import map + bare specifiers → swamp extension fmt passed → swamp extension push --dry-run produced 203.5KB archive with zod externalized
  2. Inline deps path: Used original aws-sm source with npm:zod@4.3.6 (no deno.json) → push produced 203.9KB archive with zod externalized (was 277.9KB before the fix)
  3. Pull + runtime load: Pulled @stack72/letsencrypt-certificate, verified model type loads via swamp model type search
  4. Cache fallback: Removed deno.json after building cache, verified vault still loads from cached bundle via sourceHasBareSpecifiers detection
  5. No deno.json + no cache: Removed both deno.json and cache, confirmed expected error (Import "zod" not a dependency) — verifying the cache fallback is necessary
  6. Regex safety: Verified rewriteZodImports does NOT match zod-utils, zodiac, npm:zod@3, or zod@3

Test plan

  • CI passes (type check, lint, fmt, tests)
  • Verify swamp extension push --dry-run works for an extension with deno.json + bare specifiers
  • Verify swamp extension push --dry-run works for an extension with inline npm: deps (no deno.json)
  • Verify swamp extension pull + runtime load works for existing published extensions

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260319.010016.0-sha.bc242ef2/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/v20260319.010016.0-sha.bc242ef2/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/v20260319.010016.0-sha.bc242ef2/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/v20260319.010016.0-sha.bc242ef2/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260318.232456.0-sha.01a4aa77

18 Mar 23:25
Immutable release. Only release title and notes can be modified.
01a4aa7

Choose a tag to compare

What's Changed

  • feat: add createXxxDeps factories for all 12 Batch 2 commands (#769)

Summary

  • Extract readUpstreamExtensions to src/infrastructure/persistence/upstream_extensions.ts so it can be imported from libswamp without reaching into CLI code
  • Add createXxxDeps() factory functions to all 12 Batch 2 libswamp generators, following the same pattern as createDataGetDeps() from Batch 1
  • Simplify all 12 CLI handlers to ~20-line wrappers: parse args → factory → renderer → consumeStream()
  • Rewrite workflowSchema generator to import Zod schemas directly (pure computation, no deps needed)

Factories added

Command Factory
workflow_schema (no deps — generator does pure computation)
extension_list createExtensionListDeps(repoDir)
telemetry_stats createTelemetryStatsDeps(repoDir, version)
data_list createDataListDeps(repoDir)
data_versions createDataVersionsDeps(repoDir)
vault_list_keys createVaultListKeysDeps(repoDir)
model_validate createModelValidateDeps(repoDir, options?)
workflow_validate createWorkflowValidateDeps(repoDir)
workflow_history_logs createWorkflowHistoryLogsDeps(repoDir)
model_method_history_logs createModelMethodHistoryLogsDeps(repoDir)
model_output_logs createModelOutputLogsDeps(repoDir)
model_output_data createModelOutputDataDeps(repoDir)

Any consumer can now import { dataList, createDataListDeps } from "libswamp/mod.ts" and have a fully working operation without importing domain internals.

Test Plan

  • deno check src/ — passes (0 errors)
  • deno lint — passes (737 files)
  • deno fmt --check — passes (798 files)
  • deno run test — all 3361 tests pass
  • deno run compile — binary compiles successfully

🤖 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/v20260318.232456.0-sha.01a4aa77/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.232456.0-sha.01a4aa77/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.232456.0-sha.01a4aa77/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.232456.0-sha.01a4aa77/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260318.222412.0-sha.ea3d7b68

18 Mar 22:25
Immutable release. Only release title and notes can be modified.
ea3d7b6

Choose a tag to compare

What's Changed

  • fix: handle broken extensions with missing source files from older publishes (#768)

Summary

  • Skip _-prefixed directories (_lib/, _internal/) in discoverFiles() across all four loaders (model, vault, driver, datastore) — these are helper modules imported by entry points, not standalone types that should be individually bundled
  • Strip ANSI escape codes from deno bundle error messages and CLI startup warnings so users see clean text instead of raw escape sequences
  • Validate source completeness during extension pull — after extraction, resolve imports from entry-point .ts files and warn if referenced source files are missing, with guidance to ask the author to re-publish

Context

Extensions published before the multiline import regex fix (commit 4955f3d2, March 16) may have incomplete source files. For example, @stack72/letsencrypt-certificate was published March 4 and is missing _lib/acme.ts because the old single-line regex in local_import_resolver.ts couldn't match multiline imports during publish.

When users pulled these extensions, discoverFiles() found helper files in _lib/ and tried to bundle them independently, which failed because their imports were unresolvable. Users saw raw deno bundle errors with ANSI escape codes — a confusing experience since the pre-built JS bundle actually works fine.

User impact

Before this fix, pulling @stack72/letsencrypt-certificate produced confusing bundle errors with ANSI garbage. After this fix, users see:

WRN Extension has incomplete source files (1 missing). The pre-built bundle will be used.
WRN To fix, ask the extension author to re-publish with swamp 20260316 or later.
WRN   missing: _lib/acme.ts

And swamp model type describe @stack72/letsencrypt-certificate works correctly via the pre-built bundle.

Test plan

  • New test: UserModelLoader skips _-prefixed directories in discoverFiles — creates _lib/helper.ts alongside a valid model and verifies it never appears in result.failed or result.loaded
  • New test: renderExtensionPullMissingSources outputs JSON in json mode — verifies JSON output format for missing source file warnings
  • All 3363 existing tests pass
  • Manual verification: swamp init && swamp extension pull @stack72/letsencrypt-certificate && swamp model type describe @stack72/letsencrypt-certificate — shows missing source warning, no bundle errors, type describe works

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260318.222412.0-sha.ea3d7b68/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.222412.0-sha.ea3d7b68/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.222412.0-sha.ea3d7b68/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.222412.0-sha.ea3d7b68/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/