Releases: systeminit/swamp
swamp 20260319.184717.0-sha.0e4c970c
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=valuesyntax 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
--inputas--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 --jsonworks as documented - Verify
swamp workflow run <name> --input key=value --jsonworks 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
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 clearUserErrorif a referenced variable is not set. - New
collapseEnvVars(path)— whenswamp datastore setup filesystemwrites to.swamp.yaml, it collapses the$HOMEprefix back to$HOME/...so the stored path is portable by default. - Applied at both read points — env var / CLI
--datastorearg and.swamp.yamlfilesystem 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-storeConfirmed 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
expandEnvVarsandcollapseEnvVars(tilde,$VAR,${VAR}, undefined vars throw, passthrough, roundtrip) - All 3393 existing tests pass
-
deno check,deno lint,deno fmtall 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
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
.tsfiles (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 withoutmodel/extensionexports) 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 producesexport {};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 inresult.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
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-modelskill workflow - Adds Scenario 5 ("Community Extension Found") to the
swamp-extension-modelskill 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 containsextension search,Search before you build, andswamp model type search - All 78 repo service tests pass
- Full test suite passes
-
deno check,deno lint,deno fmtall 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 byswamp extension search "ec2 instance"before attempting to create anything, then found a community extension and usedswamp extension pullto 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
What's Changed
- feat: add swamp-extension-vault skill for custom vault providers (#773)
Summary
- Add the missing
swamp-extension-vaultskill 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-vaultto the skills list in bothCLAUDE.mdand the generated template inrepo_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 withtype,name,description,configSchema,createProvider) - Export contract matches the
UserVaultSchemainsrc/domain/vaults/user_vault_loader.tsexactly VaultProviderinterface matchessrc/domain/vaults/vault_provider.tsexactly- Key difference from datastores correctly documented:
createProvidertakes 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
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.jsondependency management - Fixes a critical bug where an unrelated
package.jsonin the directory tree breaks allnpm:prefixed extension imports (#617) - Resolves
no-import-prefixlint conflicts by enabling bare specifiers viapackage.json(#758) - Supersedes the documentation workaround in #693
Problem
Two related issues were affecting users:
-
Issue #617: A user added
package.jsonto their repo root for@anthropic-ai/claude-code. This caused Deno to switch tonode_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. -
Issue #758: Extensions using
npm:andjsr:inline specifiers conflict with Deno'sno-import-prefixlint rule, forcing every file to include// deno-lint-ignore no-import-prefixsuppress comments. Users wanted to use bare specifiers viapackage.jsoninstead.
What changed
src/domain/models/bundle.ts
- Added
packageJsonDir?: stringtoBundleOptions— mutually exclusive withdenoConfigPath - When
packageJsonDiris set: uses--node-modules-dir=auto(works with bothnpm installanddeno install), setscwdon the subprocess so Deno auto-detectspackage.json - When NO project config is used: now passes
--node-modules-dir=noneto prevent any ambientpackage.jsonin the directory tree from interfering withnpm:prefixed imports - Added
isZod4InPackageJson()— readsdependencies/devDependenciesfor zod 4.x, externalizes bare"zod"specifier when found - Added
joinimport from@std/path
src/cli/commands/extension_push.ts
- Added
findPackageJson()— same walk-up pattern asfindDenoConfig, returns the directory containingpackage.json - Added
requireNodeModules()— validatesnode_modules/exists, throwsUserErrorwith clear instructions if missing - Added bare specifier gate: only uses a detected
package.jsonwhen at least one extension entry point contains bare specifiers (viasourceHasBareSpecifiers). This prevents an unrelatedpackage.json(e.g., for tooling) from being mistakenly treated as the extension's project config findDenoConfigis completely untouched — zero regression risk for the deno.json path- Updated
bundleOptionsderivation to includepackageJsonDir
Detection logic
Detection is sequential, not interleaved, to guarantee deno.json always wins:
- Walk up from manifest to repo root looking for
deno.json(full walk) - Only if no
deno.jsonfound: walk up looking forpackage.json - Only if
package.jsonfound AND extension has bare specifiers: use it - 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=nonerationale, and updated zod externalization/runtime caching sectionsswamp-extension-model/SKILL.md— Updated import and version pinning rules to includepackage.jsonswamp-extension-model/references/examples.md— Addedpackage.jsonimport style example withnode_modules/requirement noteswamp-extension-model/references/publishing.md— Updated "Detect project config" step to cover both config typesswamp-extension-driver/SKILL.md— Updated pin versions ruleswamp-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 errorsdeno lint— all files cleandeno fmt --check— all files cleandeno 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.jsoncontainingzod@4.3.6and@aws-sdk/client-secrets-manager@3.1010.0 - Extension source uses bare specifiers (
from "zod",from "@aws-sdk/client-secrets-manager") - Ran
npm install(NOTdeno install) swamp extension fmt manifest.yaml— passedswamp 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 installinstead ofnpm 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.jsonand bare specifier extension, nonpm install swamp extension push manifest.yaml --dry-runfailed 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.jsoncontaining 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.jsonimport map + bare specifiers (nopackage.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.jsonandpackage.json - Debug log confirmed only
deno.jsonwas detected —package.jsonwas not even checked
7. Inline deps, no config files
- Extension with
npm:zod@4.3.6imports, nodeno.json, nopackage.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— succeededswamp model type search letsencrypt— found@stack72/letsencrypt-certificate
9. --node-modules-dir=auto compatibility
- Verified
deno bundle --node-modules-dir=autoauto-initializesnode_modules/.deno/metadata when onlynpm installwas run - This is what makes
npm installwork (without it,deno bundlefails with "Did you forget to rundeno install?")
10. Regex safety (from previous PR, still passing)
rewriteZodImportsdoes NOT matchzod-utils,zodiac,npm:zod@3, orzod@3- Only matches zod 4.x or unversioned bare
"zod"
Test plan
- CI passes (type check, lint, fmt, tests)
- Verify
swamp extension push --dry-runworks for extension withpackage.json+ bare specifiers - Verify unrelated
package.jsondoes not break extensions withnpm:imports - Verify
deno.jsonpath 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 ...swamp 20260319.011305.0-sha.1d5b7af1
What's Changed
- docs: improve extension datastore skill workflow clarity (#771)
Summary
- Replace flat "Verify" section in the
swamp-extension-datastoreskill with a numbered Development Workflow section - Adds explicit validation checkpoints and "if X fails, do Y" error recovery feedback loops
- Addresses
tessl skill reviewsuggestions 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:
- Add an explicit numbered workflow section that sequences the full create-configure-verify cycle
- 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
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— AddeddenoConfigPathoption toBundleOptions. 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. AddedresolveZodFromConfig()to read the deno.json import map and externalize the mapped zod version. UpdatedrewriteZodImports()regex to handle bare"zod"specifiers (not justnpm:zod), with safety guard to only match zod 4.x.extension_quality_checker.ts— Added optionaldenoConfigPathparameter. When provided, uses--config <path>instead of--no-configfor bothdeno fmtanddeno lint.extension_push.ts— AddedfindDenoConfig()that walks up from the manifest directory to the repo root (.swamp.yaml/.gitboundary) looking fordeno.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— AddedsourceHasBareSpecifiers()check before re-bundling. When source has bare specifiers (e.g.,from "zod"instead offrom "npm:zod@4") and a cached bundle exists, the loader uses the cached bundle instead of attempting a re-bundle that would fail without thedeno.jsonimport map. This handles pulled extensions that were built with a project config — the archive includes pre-built bundles but not thedeno.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 fordenoConfigPathparameterextension_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 viamodel type search
Docs
design/extension.md— Documented project-aware bundling, zod externalization details, and runtime bundle cachingdesign/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 inreferences/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 pushandswamp extension fmthonor the project config automatically. - Extensions without
deno.json: Zero change in behavior. Existing extensions withnpm: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 zodinstanceofchecks work correctly. - Pulled extensions: Extensions built with a
deno.jsonproject can be pulled and loaded at runtime without thedeno.json— the pre-built bundle from the archive is used.
Design decisions
- Detection via walk-up, not config field:
deno.jsonis detected by walking up from the manifest directory to the repo root, rather than adding a field tomanifest.yaml. This avoids a schema change and mirrors how tools liketsconfig.jsonand.eslintrcare resolved. - Repo root as boundary: The walk-up stops at
.swamp.yaml/.gitto prevent escaping the project and accidentally picking up an unrelateddeno.json. - 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.xspecifier. This fixes both inline and import-map scenarios with one mechanism. - Conservative regex:
rewriteZodImportsonly matches zod 4.x or unversioned —zod@3is explicitly excluded to prevent silent runtime breakage. - 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 filesdeno lint— 736 files cleandeno fmt --check— 797 files cleandeno run test— 3376 tests passed, 0 failed- Integration test: pull + load
@stack72/letsencrypt-certificate@2026.03.04.1
Manual end-to-end
- Import map path: Created aws-sm extension with
deno.jsonimport map + bare specifiers →swamp extension fmtpassed →swamp extension push --dry-runproduced 203.5KB archive with zod externalized - Inline deps path: Used original aws-sm source with
npm:zod@4.3.6(nodeno.json) → push produced 203.9KB archive with zod externalized (was 277.9KB before the fix) - Pull + runtime load: Pulled
@stack72/letsencrypt-certificate, verified model type loads viaswamp model type search - Cache fallback: Removed
deno.jsonafter building cache, verified vault still loads from cached bundle viasourceHasBareSpecifiersdetection - No deno.json + no cache: Removed both
deno.jsonand cache, confirmed expected error (Import "zod" not a dependency) — verifying the cache fallback is necessary - Regex safety: Verified
rewriteZodImportsdoes NOT matchzod-utils,zodiac,npm:zod@3, orzod@3
Test plan
- CI passes (type check, lint, fmt, tests)
- Verify
swamp extension push --dry-runworks for an extension withdeno.json+ bare specifiers - Verify
swamp extension push --dry-runworks for an extension with inlinenpm:deps (nodeno.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
What's Changed
- feat: add createXxxDeps factories for all 12 Batch 2 commands (#769)
Summary
- Extract
readUpstreamExtensionstosrc/infrastructure/persistence/upstream_extensions.tsso 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 ascreateDataGetDeps()from Batch 1 - Simplify all 12 CLI handlers to ~20-line wrappers: parse args → factory → renderer →
consumeStream() - Rewrite
workflowSchemagenerator 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 passdeno 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
What's Changed
- fix: handle broken extensions with missing source files from older publishes (#768)
Summary
- Skip
_-prefixed directories (_lib/,_internal/) indiscoverFiles()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 bundleerror 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.tsfiles 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.tsalongside a valid model and verifies it never appears inresult.failedorresult.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/