Releases: systeminit/swamp
swamp 20260406.005701.0-sha.eaa7b026
What's Changed
- fix: detect duplicate node names in topological sort instead of false cyclic dependency (#1111)
Summary
- When forEach expansion produces duplicate step names, the topological sort misreports a phantom cyclic dependency with an empty cycle path. This adds upfront duplicate name detection (
DuplicateNodeNameError) before running Kahn's algorithm, and updatesvalidation_service.tsto catch the new error at both job-level and step-level validation sites.
Closes #1106
Test Plan
- Added 2 unit tests for duplicate detection in
topological_sort_service_test.ts(duplicate pair, multiple duplicates) - All 19 topological sort tests pass
- All 14 validation service tests pass
- Full test suite (4143 tests) passes
deno check,deno lint,deno fmt --checkall pass
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260406.005701.0-sha.eaa7b026/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/v20260406.005701.0-sha.eaa7b026/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/v20260406.005701.0-sha.eaa7b026/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/v20260406.005701.0-sha.eaa7b026/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260406.003153.0-sha.02f218d7
What's Changed
- fix: deduplicate findBySpec/findByTag across orphan model UUIDs (#1109)
Summary
- Fix
findBySpec()andfindByTag()inmodel_resolver.tsto deduplicate by logical data identity instead of physical storage identity, preventing duplicate results when orphan recovery maps multiple model UUIDs to the same model name findBySpecdedup key:data.name(scoped to one model, names are unique)findByTagdedup key:modelName:data.name(spans all models, needs logical model name)- Add tests covering the case where both old and new UUIDs have data for the same data name
Test Plan
- New unit tests:
findBySpecandfindByTagdeduplication with data under both old and new UUIDs (model_resolver_test.ts) - Existing orphan dedup tests still pass
- Full test suite passes (4142 tests)
- Verified with reproduction scenario at
/tmp/swamp-repro-issue-1105/— forEach now correctly returns 1 step instead of 2 -
deno check,deno lint,deno fmtall pass
Closes #1105
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260406.003153.0-sha.02f218d7/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/v20260406.003153.0-sha.02f218d7/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/v20260406.003153.0-sha.02f218d7/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/v20260406.003153.0-sha.02f218d7/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260406.001338.0-sha.44c351d9
What's Changed
- fix: invalidate extension catalog when source directories change (#1108)
Summary
- When a new extension source is added after the catalog is already populated, models from that source are never discovered because
buildIndextrusts the stale catalog. This stores a fingerprint of the configured source directories in the catalog'sbundle_metatable and invalidates the catalog when the fingerprint changes, triggering a full rescan. - Follows the existing pattern used for bundle layout version (#1065) and datastore base path (#1100) invalidation.
Closes #1107
Test Plan
- Added
buildIndex: invalidates catalog when source dirs change (#1107)test that bootstraps a catalog with one model dir, then callsbuildIndexagain with a newadditionalDirsentry and verifies the new source's model is discovered - All 67 existing
user_model_loader_test.tstests pass - All 18
extension_catalog_store_test.tstests pass deno check,deno lint,deno fmt --checkall pass
🤖 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/v20260406.001338.0-sha.44c351d9/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/v20260406.001338.0-sha.44c351d9/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/v20260406.001338.0-sha.44c351d9/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/v20260406.001338.0-sha.44c351d9/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.214040.0-sha.7873a8ea
What's Changed
- fix: exclude datastore-bundles from DEFAULT_DATASTORE_SUBDIRS (#1104)
Summary
- Remove
datastore-bundlesfromDEFAULT_DATASTORE_SUBDIRSto fix S3 datastore sync regression introduced in #1103
Root Cause
PR #1103 added datastore-bundles to DEFAULT_DATASTORE_SUBDIRS alongside driver-bundles and report-bundles. This caused the S3 datastore setup migration to:
- Copy
.swamp/datastore-bundles/(containing S3 extension bundles) to the S3 cache - Delete
.swamp/datastore-bundles/from local on successful migration
On subsequent commands, the datastore loader (which runs during bootstrap before the DatastorePathResolver exists and therefore always reads from local .swamp/) could no longer find the S3 extension bundles. This broke all S3 datastore operations — the extension failed to load, resolveDatastoreConfig couldn't resolve the S3 config, and sync operations failed silently.
Why This Is Correct
The UserDatastoreLoader is explicitly excluded from resolver wiring due to bootstrap ordering — it loads datastore extensions that configure the resolver. So datastore-bundles must always remain in local .swamp/, never in the datastore tier. This mirrors the exclusion of UserDatastoreLoader from the resolver in #1103.
driver-bundles and report-bundles remain in the datastore tier because their loaders do receive the resolver and can find bundles in the cache path.
Test Plan
- Updated resolver tests to verify
datastore-bundlesis NOT recognized as a datastore subdir and resolves to local.swamp/path - All 4140 tests pass
- S3 datastore UAT failure from https://github.com/systeminit/swamp-uat/actions/runs/23987653347/job/69962141207 should be resolved
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.214040.0-sha.7873a8ea/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/v20260404.214040.0-sha.7873a8ea/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/v20260404.214040.0-sha.7873a8ea/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/v20260404.214040.0-sha.7873a8ea/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.210933.0-sha.f086cc8c
What's Changed
- fix: resolve bundle paths through DatastorePathResolver for S3 datastores (#1103)
Summary
- Fix bundle path resolution failure after migrating from filesystem to S3 datastore
- Wire
DatastorePathResolverinto 4 extension bundle loaders (model, vault, driver, report) so bundle reads/writes route through the configured datastore tier - Add catalog invalidation on datastore migration to prevent stale bundle paths
Fixes #1100
Root Cause
All 5 extension bundle loaders (UserModelLoader, UserVaultLoader, UserDriverLoader, UserDatastoreLoader, UserReportLoader) hardcoded bundle paths to local .swamp/bundles/ via join(repoDir, SWAMP_DATA_DIR, SWAMP_SUBDIRS.bundles, ...). The DatastorePathResolver — which already correctly routed data artifacts, workflow runs, secrets, and other datastore-tier paths — was never consulted for bundles.
After S3 datastore migration, bundles existed only in the cache path (~/.swamp/repos/<repo-id>/bundles/) but the loaders still looked in .swamp/bundles/, producing No such file or directory (os error 2).
What Changed
1. DEFAULT_DATASTORE_SUBDIRS (datastore_config.ts)
Added driver-bundles, datastore-bundles, and report-bundles to the default datastore subdirectories list. Without this, the resolver would treat these 3 bundle types as local-only, even when an S3 datastore is configured. (bundles and vault-bundles were already listed.)
2. Bundle Loaders — 4 files
Added optional DatastorePathResolver constructor parameter and a private resolveBundlePath() helper to each loader. The helper delegates to resolver.resolvePath() when available, falling back to the hardcoded local path when absent (backward compatibility for tests, repo init, no datastore configured).
Replaced all hardcoded join(repoDir, SWAMP_DATA_DIR, SWAMP_SUBDIRS.*, ...) bundle path constructions with resolveBundlePath():
- UserModelLoader:
getBundlePath(),bundleWithCache(),importBundle(),populateCatalogFromRegistry(),assertSafePathboundary. ExcludedmigrateOldFlatBundles()which must always read from the old local path. - UserVaultLoader:
bundleWithCache(),importBundle(),assertSafePathboundary - UserDriverLoader:
bundleWithCache(),importBundle(),assertSafePathboundary - UserReportLoader:
bundleWithCache(),importBundle(),assertSafePathboundary
UserDatastoreLoader is explicitly excluded — it loads datastore extensions that configure the resolver (bootstrap ordering). It always uses the local .swamp/ path.
3. CLI Wiring (mod.ts, auto_resolver_adapters.ts)
- Created a lazy resolver factory in
mod.tsthat constructs theDefaultDatastorePathResolveron first loader invocation and caches it for reuse - Passed the factory to model, vault, driver, and report loaders via
setLoader()closures - Datastore loader explicitly excluded with a comment explaining why
- Updated
auto_resolver_adapters.tsto accept an optional resolver for hot-load scenarios
4. Catalog Invalidation (extension_catalog_store.ts, user_model_loader.ts)
The ExtensionCatalogStore (SQLite at .swamp/_extension_catalog.db) stores absolute bundle_path values. After datastore migration, these paths become stale (pointing to old .swamp/bundles/ instead of the new cache path). Added:
getDatastoreBasePath()/setDatastoreBasePath()on the catalog store- Detection in
buildIndex()that compares the stored base path against the current resolver path, auto-invalidating the catalog when they differ
5. Architecture boundary ratchet
The new models -> datastore type-only import (import type { DatastorePathResolver }) creates a mutual dependency with the existing datastore -> models import. Updated the ratchet from 11 to 12.
Test Plan
Automated Tests (all 4140 pass)
-
3 new resolver tests (
default_datastore_path_resolver_test.ts):- Bundle subdirs are recognized as datastore subdirs (all 5 types)
resolvePath()routes bundles to S3 cache path for custom datastores- Filesystem datastore resolves bundles to same local path (no behavioral change)
-
1 new constructor test (
user_model_loader_test.ts):UserModelLoaderaccepts optionalDatastorePathResolver(with and without)
-
All 4140 existing tests pass — the optional resolver with fallback preserves backward compatibility
Manual End-to-End Verification
Reproduced the exact scenario from the issue:
- Initialized scratch repo at
/tmp/swamp-repro-issue-1100/ - Pulled
@swamp/aws/ec2extension — bundles written to.swamp/bundles/2e4ea9ae/ - Ran model method — succeeded (AWS auth error, not file-not-found — confirming bundles load correctly)
- Simulated S3 migration:
- Moved
.swamp/bundles/to/tmp/swamp-s3-cache-1100/bundles/ - Configured filesystem datastore pointing to
/tmp/swamp-s3-cache-1100/in.swamp.yaml
- Moved
- Ran model method with OLD binary (pre-fix) — FAILED with
No such file or directory (os error 2): readfile '/private/tmp/swamp-repro-issue-1100/.swamp/bundles/2e4ea9ae/vpc.js'— confirming the bug - Ran model method with NEW binary (this fix) — SUCCEEDED — the resolver correctly routed to
/tmp/swamp-s3-cache-1100/bundles/2e4ea9ae/vpc.js - Verified catalog auto-invalidation — on first run after migration, catalog detected the base path change, invalidated stale entries, and rebuilt with correct paths. Subsequent runs used the updated catalog without re-invalidation.
Risk Assessment
- Filesystem datastore users: Zero behavioral change — resolver returns the same
.swamp/path - No datastore configured: Resolver is
undefined, falls back to hardcoded path - Datastore loader bootstrap: Explicitly excluded from resolver wiring — datastore extensions always load from local path
- No data migration: Catalog paths are recomputed on each
buildIndex()call; auto-invalidation handles stale entries
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.210933.0-sha.f086cc8c/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/v20260404.210933.0-sha.f086cc8c/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/v20260404.210933.0-sha.f086cc8c/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/v20260404.210933.0-sha.f086cc8c/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.200822.0-sha.4105854c
What's Changed
- docs: strengthen CLAUDE.md skills section with concrete rules (#1102)
Summary
- Replaces the 2-line Skills section in CLAUDE.md with concrete, enforceable rules: directory structure, uppercase SKILL.md, required frontmatter fields, 500-line body limit, no extraneous files, and mandatory
deno fmtafter edits - Renames
terminal-output/skill.md→SKILL.mdto fix the one existing violation
Test Plan
- Verify
deno fmt --checkpasses - Verify
deno lintpasses
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.200822.0-sha.4105854c/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/v20260404.200822.0-sha.4105854c/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/v20260404.200822.0-sha.4105854c/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/v20260404.200822.0-sha.4105854c/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.195432.0-sha.2db397b5
What's Changed
- fix: calculate eval cost from token usage (#1101)
Summary
- Skill trigger eval cost was always reported as $0.00 because promptfoo's Anthropic provider doesn't populate per-result
costfields - Compute estimated cost from aggregate
stats.tokenUsage(prompt + completion tokens) using per-model pricing constants - Adds pricing for all four supported models: sonnet, opus, gpt-4.1, gemini-2.5-pro
Test Plan
- Verified the math: for the latest sonnet eval run (618,252 prompt + 18,041 completion tokens), cost would now show ~$2.12 instead of $0.00
- No functional changes to eval logic — only the cost reporting line
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.195432.0-sha.2db397b5/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/v20260404.195432.0-sha.2db397b5/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/v20260404.195432.0-sha.2db397b5/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/v20260404.195432.0-sha.2db397b5/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.193805.0-sha.f4eb4a34
What's Changed
- fix: detect transitive dep changes and surface rebundle errors in bundle cache (#1099)
Summary
- findStaleFiles() now checks transitive dependency mtimes — when an entry point appears fresh in the catalog, resolves its local imports via
resolveLocalImports()and compares their mtimes against the cached bundle file. This catches edits to imported.tsfiles that don't touch the entry point itself. - bundleWithCache() surfaces real errors instead of silently falling back — distinguishes expected failures (pulled extensions without project config + bare specifiers) from unexpected failures (user extensions with real errors). Unexpected failures log at warn level and don't touch the bundle mtime, so subsequent runs retry bundling.
- Adds
isExpectedBundleFailure()shared helper inbundle.tsto avoid duplicating the deno.json discovery + bare-specifier check across all 4 extension loaders (models, drivers, vaults, datastores). - Updates design/extension.md to document the transitive dependency checking in
buildIndex().
Closes #1094
Test Plan
- Added unit test:
buildIndex detects transitive dependency changes— verifies the catalog path correctly triggers rebundling when only an imported file changes - Added unit test:
bundleWithCache preserves cached bundle on unexpected failure— verifies fallback returns old valid bundle content without contamination from broken source - Added unit tests for
isExpectedBundleFailure()— covers bare specifiers without config (expected), deno.json present (unexpected), npm-only imports (unexpected) - Verified fix against compiled binary in scratch repo: transitive dep changes detected and rebundled; rebundle failures surfaced at warn level with mtime preserved
- All 4136 existing tests pass
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.193805.0-sha.f4eb4a34/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/v20260404.193805.0-sha.f4eb4a34/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/v20260404.193805.0-sha.f4eb4a34/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/v20260404.193805.0-sha.f4eb4a34/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.192757.0-sha.762a7e8f
What's Changed
- feat: add post-execution data inspection guidance to skills (#1098)
Summary
Closes #1093
- Add "Inspecting Factory Method Results" subsection to swamp-model skill showing
data queryas the primary pattern for exploring N artifacts from factory methods - Add data versioning note near "Run Methods" explaining re-runs create new versions, never overwrite
- Add
swamp-data-queryto the "When to Use Other Skills" table in swamp-model skill - Broaden swamp-data-query trigger keywords to include post-execution discovery terms ("inspect results", "method output", "factory results", "browse artifacts", "what did method produce")
Test Plan
-
deno fmt --checkpasses on both modified files - Verified
data querysyntax examples match swamp-data-query skill documentation - Confirmed new trigger keywords don't overlap with swamp-data or swamp-model triggers
- Documentation-only change — no runtime code affected
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.192757.0-sha.762a7e8f/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/v20260404.192757.0-sha.762a7e8f/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/v20260404.192757.0-sha.762a7e8f/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/v20260404.192757.0-sha.762a7e8f/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260404.192115.0-sha.7878223f
What's Changed
- fix: workflow get/validate/evaluate/edit find extension workflows (#1097)
Summary
- The
createWorkflow*Depsfactory functions insrc/libswamp/workflows/hardcodedYamlWorkflowRepository, which only searches local YAML workflows. Extension workflows pulled viaswamp extension pullwere invisible toworkflow get,validate,evaluate, andedit— even thoughworkflow searchandworkflow runfound them correctly. - Changed each factory to accept a
WorkflowRepositoryparameter (theCompositeWorkflowRepositoryfromrepoContext) instead of instantiatingYamlWorkflowRepositorydirectly. Updated the four CLI commands to passrepoContext.workflowRepo.
Closes #1095
Test Plan
- All 4131 existing tests pass
-
deno check,deno lint,deno fmtpass - Verified with compiled binary:
swamp extension pull @webframp/aws-opsthenswamp workflow get @webframp/investigate-outageandswamp workflow validate @webframp/investigate-outageboth succeed (previously returned "Workflow not found") - Filed UAT coverage gap: systeminit/swamp-uat#120
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260404.192115.0-sha.7878223f/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/v20260404.192115.0-sha.7878223f/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/v20260404.192115.0-sha.7878223f/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/v20260404.192115.0-sha.7878223f/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/