Releases: systeminit/swamp
swamp 20260317.105237.0-sha.7095a535
What's Changed
- fix: resolve stack overflow when loading extension bundles with large npm deps (#731)
Summary
Fixes #728.
- Root cause:
String.fromCharCode(...new TextEncoder().encode(js))spreads every byte of a bundle onto the call stack as a function argument. Large inlined npm dependency trees (e.g.,@octokit/rest,@slack/web-api) produce bundles of hundreds of KB, exceeding V8's maximum call stack size. - Cached bundles: Restore
toFileUrl()imports (the pre-#724 approach) with on-disk zod rewriting so old cached bundles are fixed permanently. - Fallback path: Add
uint8ArrayToBase64()which processes bytes in 8KB chunks, avoiding the stack overflow for the no-repo-dir codepath. - All three loaders fixed:
UserModelLoader,UserDriverLoader,UserVaultLoaderall had the identical bug from #724.
Test plan
-
deno check— type checking passes -
deno lint— linting passes -
deno fmt— formatting passes -
deno run test— 3033/3033 tests pass -
deno run compile— binary compiles - New
uint8ArrayToBase64unit tests (small input, empty input, 1MB input) - Manual verification:
swamp repo init→swamp extension pull @bixu/github→swamp model type search --jsonloads all 4 Octokit-based models without warnings
🤖 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/v20260317.105237.0-sha.7095a535/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/macOS (Intel):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.105237.0-sha.7095a535/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (x86_64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.105237.0-sha.7095a535/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (aarch64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.105237.0-sha.7095a535/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260317.010646.0-sha.40d70e64
What's Changed
- feat: auto-trust collectives from user membership (#727)
Summary
- Cache the user's collective memberships in
auth.jsonduringauth loginandauth whoami, then merge them into the trusted collectives list at CLI startup - Removes friction of manually adding each collective to
trustedCollectivesin.swamp.yaml— if you're a member of a collective, its extensions auto-resolve automatically - Adds
trustMemberCollectivesoption to.swamp.yamlfor opt-out
Design Decisions
Cache at login time, not per-invocation. Calling the whoami API on every CLI invocation would add latency. Instead, collectives are cached in auth.json during auth login (already makes a whoami call) and refreshed on auth whoami. This means membership changes require a swamp auth whoami to take effect — an acceptable tradeoff for zero-latency startup.
Merge, don't replace. Membership collectives are merged with the explicit trustedCollectives list (deduplicated via Set). This means explicit config is never lost, and membership adds to it additively.
Opt-out via trustMemberCollectives: false. Defaults to true (absent = true). When set to false, only the explicit trustedCollectives list is used — exactly matching the previous behavior. This gives security-conscious users full control.
Graceful degradation. If not authenticated, auth.json is missing/unreadable, or the collectives field doesn't exist (old auth.json), the feature silently falls back to the current behavior with no errors.
User Impact
Before: Users who are members of collectives (e.g., their org's @myorg collective) had to manually add myorg to trustedCollectives in every repo's .swamp.yaml to get auto-resolution working. Without this, swamp model create @myorg/some-type my-model would fail with "Unknown model type".
After: After logging in, membership collectives are automatically trusted. Extensions from any collective the user belongs to auto-resolve on first use with zero configuration.
Changes
| File | Change |
|---|---|
src/domain/auth/auth_credentials.ts |
Added collectives?: string[] to AuthCredentials |
src/cli/commands/auth_login.ts |
Cache collectives from whoami response during login |
src/cli/commands/auth_whoami.ts |
Refresh cached collectives on whoami |
src/infrastructure/persistence/repo_marker_repository.ts |
Added trustMemberCollectives?: boolean to RepoMarkerData |
src/cli/mod.ts |
Added resolveTrustedCollectives() to merge membership + explicit collectives; load auth at startup |
src/cli/mod_test.ts |
8 new tests for resolveTrustedCollectives |
src/infrastructure/persistence/auth_repository_test.ts |
2 new tests for collectives round-trip |
| Skills & design docs (5 files) | Updated to document membership-based trust and trustMemberCollectives opt-out |
Test Plan
-
deno check— all modified files pass type checking -
deno lint— no lint errors -
deno fmt --check— formatting clean -
deno run test src/cli/mod_test.ts— 51 tests pass (8 newresolveTrustedCollectivestests) -
deno run test src/infrastructure/persistence/auth_repository_test.ts— 7 tests pass (2 new) - Manual E2E test:
- Compiled binary with
deno run compile - Created fresh repo in
/tmp/swamp-test-autotrustwithswamp repo init - Ran
swamp auth whoami→ cached collectives["swamp", "system-initiative", "stack72"]inauth.json - Ran
swamp model create @stack72/unifi-traffic test-traffic→ auto-resolved and installed@stack72/ubiquityextension successfully - The
stack72collective was NOT in.swamp.yaml'strustedCollectives— it was trusted purely via membership
- Compiled binary with
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.010646.0-sha.40d70e64/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/macOS (Intel):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.010646.0-sha.40d70e64/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (x86_64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.010646.0-sha.40d70e64/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (aarch64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.010646.0-sha.40d70e64/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260317.005011.0-sha.2f69cc55
What's Changed
- fix: data GC never fully removes expired data from disk (#722)
Summary
Fixes #720
swamp data gc reported expired data but never reclaimed any disk space. The deleteExpiredData() method only called removeLatestMarker(), which removed the latest symlink but left all version directories and content files on disk.
This was a two-part problem:
- Phase 1 (expired data cleanup) only performed a soft-delete — no version directories were removed, zero bytes freed
- Phase 2 (
collectGarbage()) always protects the latest version, and the single-versiondelete()path recreates thelatestmarker, effectively undoing Phase 1's soft-delete
User impact
Before this fix, running swamp data gc would report expired entries but disk usage would remain unchanged. Users had no way to reclaim space from expired data without manually deleting directories from the datastore.
After this fix, swamp data gc fully removes expired data directories, correctly reports versionsDeleted and bytesReclaimed, and actually frees disk space.
What changed
-
data_lifecycle_service.ts: ReplacedremoveLatestMarker()(soft-delete) withdelete(type, modelId, dataName)(hard-delete) indeleteExpiredData(). Before deleting, stats each version's content file to report accurate bytes reclaimed. UpdatedLifecycleGCResultdoc comments to reflect the new behavior. -
data_lifecycle_service_test.ts: AddeddeleteandgetContentPathmocks toMockDataRepository. Added two new tests:- Verifies expired data triggers
delete()(notremoveLatestMarker()) and reports correctversionsDeleted - Verifies dry run does not call
delete()
- Verifies expired data triggers
Why this is correct
The no-version delete(type, modelId, dataName) path in UnifiedDataRepository does a clean Deno.remove(dataNameDir, { recursive: true }) — it removes the entire data directory without recreating any markers. After Phase 1 hard-deletes expired entries, Phase 2's findAllForModel() naturally skips them since their directories no longer exist. No changes needed to collectGarbage() or the delete() implementation.
Test plan
-
deno check— type checking passes -
deno lint— no lint errors -
deno fmt— properly formatted -
deno run test— all 2997 tests pass (including 2 new tests) -
deno run compile— binary compiles successfully
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.005011.0-sha.2f69cc55/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/macOS (Intel):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.005011.0-sha.2f69cc55/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (x86_64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.005011.0-sha.2f69cc55/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (aarch64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.005011.0-sha.2f69cc55/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260317.003631.0-sha.7ef34bda
What's Changed
- docs: update skills and design docs for auto-resolution feature (#726)
Summary
- Add "Automatic Resolution" section to
design/extension.mdcovering trusted collectives, resolution algorithm, hot-loading, re-entrancy guard, and architecture - Add
trustedCollectivesconfig option todesign/repo.mdand expand.swamp.yamlexample in repo structure reference - Update extension-model skill with auto-resolution notes and new example decision flow showing auto-resolve in action
- Add auto-resolution troubleshooting entries to both model and extension-model troubleshooting references
- Add vault type auto-resolution note to vault skill
Test plan
-
deno fmtpasses on all changed files -
deno run compilesucceeds with updated skills embedded
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.003631.0-sha.7ef34bda/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/macOS (Intel):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.003631.0-sha.7ef34bda/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (x86_64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.003631.0-sha.7ef34bda/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (aarch64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.003631.0-sha.7ef34bda/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260317.001439.0-sha.adf8dd48
What's Changed
- feat: automatic extension resolution with trusted collectives (#725)
Summary
Closes #665
When users clone a repo with model or vault configurations referencing extension types that aren't installed locally, commands fail with cryptic "Unknown model type" or "Unsupported vault type" errors. This PR adds lazy auto-resolution: when swamp encounters an unknown type whose collective is on a trusted allowlist, it transparently searches the extension registry, installs the matching extension, hot-loads it into the live registries, and continues execution — no manual swamp extension pull needed.
What changes
- New
trustedCollectivesconfig in.swamp.yaml— defaults to["swamp", "si"]so official extensions auto-resolve out of the box. Users can add more collectives or set[]to disable. ExtensionAutoResolverdomain service — standalone service with port interfaces (ExtensionLookupPort,ExtensionInstallerPort,AutoResolveOutputPort) that keeps the domain layer clean of CLI/presentation imports.resolveModelType()/resolveVaultType()helper functions — drop-in replacements formodelRegistry.get()at 7 choke points across CLI commands and the workflow execution service.- Hot-loading support —
UserModelLoader.loadModels()andUserVaultLoader.loadVaults()gain askipAlreadyRegisteredoption so re-running model discovery after install doesn't error on already-registered types. - Vault auto-resolution in
VaultService.fromRepository()— resolves missing@-prefixed vault types beforeregisterVault(), keepingregisterVault()itself sync. - Clear UX output — users always see what's happening: searching, installing, installed (with model count), or actionable error messages for not-found/network failures. Both log and JSON output modes supported.
Design decisions
-
Standalone helper, not embedded in registries —
ModelRegistryandVaultTypeRegistryremain pure sync data structures. Resolution is a domain service that choke points call explicitly. This is more DDD-aligned: the registry is a repository (stores/retrieves), resolution is a domain service (orchestrates). -
Port interfaces for clean architecture — The domain service defines
ExtensionLookupPort,ExtensionInstallerPort, andAutoResolveOutputPortinterfaces. Concrete adapters in the CLI layer wire the HTTP client,installExtension(), model loaders, and output renderers. This keeps domain → CLI/presentation dependency arrows pointing the right direction. -
Two-step type-to-extension resolution — First tries direct lookup by progressively stripping trailing segments (e.g.,
@swamp/aws/ec2/instance→ try@swamp/aws/ec2, then@swamp/aws). Falls back to search with collective filter if direct lookup fails. This handles both exact extension names and partial matches. -
Always install latest — Auto-resolution always installs the latest version unless the user has explicitly pinned via
extension pull @name@version. This is the right default for trusted collectives where you control releases. -
Re-entrancy guard — A
Set<string>of types currently being resolved prevents infinite loops if transitive dependencies trigger further resolution. -
Collective not allowlisted = silent skip — No auto-resolution is attempted for non-allowlisted collectives. The existing "Unknown model type" error shows as-is. This is intentional — we don't want to suggest the feature exists for untrusted collectives.
User impact
- Zero-friction onboarding: Clone a repo that uses
@swamp/digitalocean/droplet, runswamp model method run, and it just works — the extension installs automatically on first use. - No breaking changes: Existing repos work identically. The default
trustedCollectives: ["swamp", "si"]only kicks in for@swamp/*and@si/*types. Users who don't use extensions see no difference. - Explicit opt-out: Set
trustedCollectives: []in.swamp.yamlto disable entirely. - Transparent operation: Every auto-resolution step is logged so users understand why a command takes longer the first time.
Testing
Automated tests (14 new)
- Skips non-allowlisted collectives (silent, no output)
- Resolves via direct lookup (strips segments correctly)
- Tries intermediate candidates before shorter ones (
@swamp/aws/ec2before@swamp/aws) - Falls back to search when direct lookup fails
- Shows
notFoundoutput when nothing matches - Shows
networkErroroutput on fetch failures (TypeError, timeouts) - Re-entrancy guard prevents infinite loops
- Handles non-
@prefixed types (e.g.,swamp/echo/v2) - Skips types without a collective (single-word types)
resolveModelTypereturns existing definitions without resolverresolveModelTypereturns undefined for unknown types without resolverresolveVaultTypereturns true for existing vault typesresolveVaultTypereturns false for unknown types without resolverresolveVaultTypeskips non-@types
Manual end-to-end test
Compiled the binary, initialized a fresh repo in /tmp, and ran:
swamp model create @swamp/digitalocean/droplet my-droplet
Result: auto-resolved @swamp/digitalocean from the registry, installed @swamp/digitalocean@2026.03.16.1, hot-loaded 32 models, and successfully created the my-droplet definition — all in one command with clear status output:
INF extension·auto-resolve Extension type "@swamp/digitalocean/droplet" not found locally, searching registry...
INF extension·auto-resolve Found extension "@swamp/digitalocean" (DigitalOcean infrastructure models)
INF extension·auto-resolve Installing "@swamp/digitalocean"@"2026.03.16.1"...
INF extension·auto-resolve Installed "@swamp/digitalocean"@"2026.03.16.1" (32 models registered)
Created: my-droplet (@swamp/digitalocean/droplet)
Full suite
All 3018 tests pass (14 new + 3004 existing), including architecture boundary and DDD layer rule tests.
Verification
deno check— passesdeno lint— passesdeno fmt— passesdeno run test— 3018 passed, 0 faileddeno run compile— binary compiled successfully
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.001439.0-sha.adf8dd48/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/macOS (Intel):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.001439.0-sha.adf8dd48/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (x86_64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.001439.0-sha.adf8dd48/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/Linux (aarch64):
curl -L https://github.com/systeminit/swamp/releases/download/v20260317.001439.0-sha.adf8dd48/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260316.225105.0-sha.210fdbaf
What's Changed
- fix: resolve dual Zod instance in compiled binary (#724)
Summary
Fixes #723.
In the compiled binary (deno compile), extension bundles with externalized import { z } from "npm:zod@4" resolve to a different Zod module instance than swamp's own embedded Zod. This causes instanceof z.ZodType checks, z.toJSONSchema(), and _zod property lookups to fail — even though both are the same Zod version (4.3.6). Works fine in dev mode (deno run) because Deno resolves both to the same cached module.
Problem
The --external npm:zod@4 flag in deno bundle was meant to make extensions share swamp's Zod instance. In dev mode, the dynamic import("npm:zod@4") in the bundle resolves to the same cached module. But in the compiled binary, deno compile resolves it to a separate module instance, breaking:
schema instanceof z.ZodType→falsez.toJSONSchema(schema)→Cannot read properties of undefined (reading '_zod')- Any cross-instance Zod operations (
.passthrough(),.default(), etc.)
Fix
Post-process extension bundles to replace external Zod imports with references to swamp's Zod instance exposed via globalThis.__swamp_zod:
Before (bundle output):
import { z } from "npm:zod@4";After (rewritten):
const { z } = globalThis.__swamp_zod;Changes
src/domain/models/bundle.ts: AddinstallZodGlobal()(setsglobalThis.__swamp_zodto swamp's Zod module) andrewriteZodImports()(regex replaces Zod imports — handles named, aliased, star imports, versioned/unversioned specifiers). Applied inbundleExtension()for non-selfContained bundles.src/domain/models/user_model_loader.ts: CallinstallZodGlobal()before loading bundles; applyrewriteZodImportsat import-time for old cached bundles.src/domain/drivers/user_driver_loader.ts: Same pattern.src/domain/vaults/user_vault_loader.ts: Same pattern.src/domain/models/bundle_test.ts: 9 new tests — unit tests forrewriteZodImports(named, aliased, star, unversioned, multiple, non-zod untouched, idempotency, single-quoted) and end-to-end test verifyingz.toJSONSchema()works on bundled schemas.
Design decisions
- Rewrite at both bundle-time AND import-time: Bundle-time ensures new cached bundles are correct. Import-time catches old cached bundles that still have raw
importstatements. The rewrite is idempotent. - selfContained bundles are unaffected: They inline Zod and never have external imports.
- No changes to extension author workflow: Extensions still write
import { z } from "npm:zod@4"— the rewrite is transparent.
Alternatives rejected
- Stop externalizing Zod: Bloats every bundle by ~500KB and doesn't fix the problem — swamp's own code still uses its
zforinstanceof/toJSONSchema. - Duck-typing instead of
instanceof: Much larger change surface across 6+ files, fragile, loses Zod's built-in schema capabilities. - Import maps: Don't work in compiled binaries.
Test plan
-
deno check— type checking passes -
deno lint— linting passes -
deno fmt— formatting passes -
deno run test— 3004/3004 tests pass -
deno run compile— binary compiles - Standalone PoC validates approach in both dev mode and compiled binary
- Manual test with compiled binary:
swamp extension pull @dougschaefer/cisco-collaboration-endpoints→swamp model type describeshows JSON schema without_zoderrors
🤖 Generated with Claude Code
Co-authored-by: Douglas Schaefer dougschaefer6@users.noreply.github.com
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260316.225105.0-sha.210fdbaf/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/v20260316.225105.0-sha.210fdbaf/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/v20260316.225105.0-sha.210fdbaf/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/v20260316.225105.0-sha.210fdbaf/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260316.173839.0-sha.1abd500d
What's Changed
- feat: per-model datastore locks for concurrent model operations (#713)
Summary
Replaces the single global datastore lock with per-model locks so that operations on different models can run concurrently. This fixes the core issue where running model method run on one model blocked all other model operations, even on completely unrelated models.
- Introduces per-model lock files at
data/{modelType}/{modelId}/.lock— operations on different models no longer block each other - Refactors the sync coordinator from module-level singletons to a
Map<string, SyncEntry>supporting multiple concurrent locks - Adds model-scoped S3 sync (
pullChangedForModel) so S3 datastores only pull/push the relevant model's files - Extracts model references from workflows to acquire only the locks needed, with automatic fallback to global lock for dynamic CEL references
- Updates breakglass commands (
lock status,lock release --model) to show and manage per-model locks
Closes #706
Why per-model locks?
The global lock was designed for simplicity, but it creates an O(n) bottleneck for fleet operations. When managing 100+ VMs where each method call takes 30-90 seconds, a single global lock means:
- Before: Running
healthCheckonprod-vm-1blocks a quickcheckServiceondev-vm-2— the second command waits or times out - After: Both run concurrently because they acquire separate locks (
data/command/shell/prod-vm-1/.lockanddata/command/shell/dev-vm-2/.lock)
Structural commands (data gc, repo init, model create/delete) still use the global lock, and per-model lock acquisition checks for a held global lock first — so data integrity is preserved.
Impact on users
model method runon different models runs concurrently (the primary win)workflow runacquires only the locks for models referenced in the workflowmodel evaluateandworkflow evaluateuse per-model locks for single-model/workflow evaluation- S3 datastores benefit equally — model-scoped pull on lock acquisition, brief global lock only during push (seconds, not minutes)
- No breaking changes — the lock file format and CLI interface are unchanged; existing repos work without migration
- Deadlock prevention — locks are always acquired in sorted order when multiple models are involved
What changed
| File | Change |
|---|---|
datastore_sync_coordinator.ts |
Refactored to Map<string, SyncEntry> with named lock support |
repo_context.ts |
Added requireInitializedRepoUnlocked(), createModelLock(), acquireModelLocks() |
s3_cache_sync.ts |
Added pullChangedForModel() for model-scoped S3 sync |
model_method_run.ts |
Uses per-model lock instead of global lock |
workflow_run.ts |
Extracts model refs, acquires per-model locks (falls back to global for dynamic refs) |
model_evaluate.ts |
Single-model evaluate uses per-model lock; --all keeps global |
workflow_evaluate.ts |
Single-workflow evaluate uses per-model lock; --all keeps global |
datastore_lock.ts |
lock status scans per-model locks; lock release --model added |
datastore_output.ts |
Shows lock scope (global vs per-model) in status output |
model_reference_extractor.ts |
New: extracts model references from workflows for lock targeting |
Test plan
- All 2968 existing tests pass
-
deno check,deno lint,deno fmtclean - New unit tests for coordinator, repo context helpers, and model reference extractor
- Manual verification: two concurrent
model method runon different models both proceed without blocking, each with its own.lockfile - Binary compiles successfully
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260316.173839.0-sha.1abd500d/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/v20260316.173839.0-sha.1abd500d/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/v20260316.173839.0-sha.1abd500d/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/v20260316.173839.0-sha.1abd500d/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260316.173713.0-sha.6dc69231
What's Changed
- docs: add z.infer type casts to readResource skill examples (#721)
Summary
- Update all
readResource()examples in theswamp-extension-modelskill to usez.infer<typeof Schema>casts instead of accessing properties on untypedRecord<string, unknown> - Fix outdated vault resolution docs in
api.md— vault expressions have been automatically resolved since #712, not "returned as-is" - Add
typealiases (VpcData,DropletData,CustomerData,BucketData) next to each Zod schema so the cast pattern is immediately visible
Why this is the right fix for #716
The issue asks for typed readResource() to eliminate as any casts in extension models. The root cause isn't a missing framework feature — it's that the skill examples Claude uses to generate extension models were accessing readResource() results without type narrowing. Since extension models already define Zod schemas for their resources, z.infer<typeof Schema> derives the TypeScript type at zero runtime cost (erased during bundling). The as cast is safe because data was already validated against that same schema on write.
By fixing the examples, Claude will generate typed code from the start, and extension authors won't hit the lint violations described in #716.
Closes #716
Test plan
- Verify examples in
api.md,examples.md, andscenarios.mdare consistent — everyreadResource()call has a correspondingz.infertype alias and cast - Verify vault resolution docs in
api.mdmatch actual behavior from #712
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260316.173713.0-sha.6dc69231/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/v20260316.173713.0-sha.6dc69231/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/v20260316.173713.0-sha.6dc69231/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/v20260316.173713.0-sha.6dc69231/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260316.163214.0-sha.4955f3d2
What's Changed
- fix: resolve multi-line imports in local_import_resolver (#719)
Summary
- Fix
IMPORT_PATTERNregex inlocal_import_resolver.tsto match across newlines (.*?→[\s\S]*?), resolving #715 - The clover code generator writes multi-line imports (e.g.,
import {\n createResource,\n deleteResource,\n} from "./_lib/aws.ts"), which the previous single-line regex silently skipped - This caused shared dependencies like
_lib/aws.tsto be excluded from extension packages duringswamp extension push, making all@swamp/aws/*extensions fail on pull withModule not founderrors
Changes
src/domain/models/local_import_resolver.ts: ChangedIMPORT_PATTERNfrom/(?:import|export)\s+.*?from\s+["'](\.\.?\/[^"']+)["']/gto/(?:import|export)\s+[\s\S]*?from\s+["'](\.\.?\/[^"']+)["']/gso the regex matches import/export statements that span multiple linessrc/domain/extensions/extension_import_resolver_test.ts: Added test case"resolveLocalImports resolves multi-line imports"that creates a_lib/aws.tsdependency imported via a multi-line import statement and verifies it is correctly discovered
Test plan
- New multi-line import test passes
- All 8 import resolver tests pass
- Full test suite passes (2979 tests)
-
deno check— type checking passes -
deno lint— linting passes -
deno fmt— formatting passes -
deno run compile— binary compiles successfully
Fixes #715
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260316.163214.0-sha.4955f3d2/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/v20260316.163214.0-sha.4955f3d2/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/v20260316.163214.0-sha.4955f3d2/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/v20260316.163214.0-sha.4955f3d2/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/swamp 20260316.161521.0-sha.7fc8a69a
What's Changed
- fix: skip auth check in
extension push --dry-run(#718)
Summary
swamp extension push --dry-runnow works without authentication- Auth loading (step 3) and collective membership validation (step 4) are wrapped in a
!dryRunguard so they only run for real pushes - Unblocks CI validation workflows that don't have swamp-club credentials
What changed
In src/cli/commands/extension_push.ts, the auth check and collective membership validation previously ran unconditionally before the dry-run exit point. Since --dry-run only builds the archive locally and never contacts the registry, authentication is unnecessary.
The credentials variable is now typed as | undefined and only populated when not in dry-run mode. The existing non-dry-run code paths (steps 13 and 17) already have their own if (!options.dryRun) guards, so credentials are never accessed in dry-run mode.
Trade-off
Dry-run will skip collective ownership validation. This is acceptable because:
- Dry-run validates the build, not permissions — its purpose is to verify the extension compiles and packages correctly
- The real push still enforces collective membership — no security bypass
- CI pipelines just need to verify the extension archives correctly without needing registry credentials
Test plan
-
deno checkpasses -
deno lintpasses -
deno fmtpasses -
deno run testpasses -
deno run compilepasses -
swamp extension push <manifest> --dry-runsucceeds without auth -
swamp extension push <manifest>without auth still fails with "Not authenticated"
Fixes #717
🤖 Generated with Claude Code
Installation
macOS (Apple Silicon):
curl -L https://github.com/systeminit/swamp/releases/download/v20260316.161521.0-sha.7fc8a69a/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/v20260316.161521.0-sha.7fc8a69a/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/v20260316.161521.0-sha.7fc8a69a/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/v20260316.161521.0-sha.7fc8a69a/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/