Skip to content

Releases: systeminit/swamp

swamp 20260311.132338.0-sha.398857eb

11 Mar 13:24
Immutable release. Only release title and notes can be modified.
398857e

Choose a tag to compare

What's Changed

  • fix: prevent datastore lock commands from deadlocking on stuck lock (#678)

Fixes #676

Summary

  • datastore lock status and datastore lock release --force called requireInitializedRepo() which acquires the datastore lock via registerDatastoreSync() — causing the breakglass commands to deadlock on the very lock they were meant to inspect or release
  • Added resolveDatastoreForRepo() to src/cli/repo_context.ts — a lightweight function that resolves repo path + datastore config without acquiring the lock. The lock commands now use this instead
  • Refactored requireInitializedRepo() to call resolveDatastoreForRepo() internally, keeping a single source of truth for repo validation and datastore config resolution
  • Zero user impact for normal usage — only the two broken breakglass commands are affected, and they now work

Test Plan

  • New tests for resolveDatastoreForRepo: returns correct config without acquiring lock, throws UserError for non-initialized repos
  • All 2799 tests pass
  • deno fmt --check passes
  • deno lint passes
  • deno check passes
  • Verified no UAT test impact — no UAT tests exercise datastore lock commands

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260311.105043.0-sha.fa48cb0c

11 Mar 10:51
Immutable release. Only release title and notes can be modified.
fa48cb0

Choose a tag to compare

What's Changed

  • fix: gracefully handle non-TTY context in interactive commands (#675)

Fixes #674

Summary

  • Interactive search commands (model search, type search, workflow search, etc.) use Ink for terminal UIs which requires raw mode on stdin. In non-TTY contexts (piped input, CI, AI agents), Ink crashes with "Raw mode is not supported". This was a pre-existing bug — it existed before datastores — but the introduction of the datastore lock made it much worse: the crash now leaks the lock, blocking all subsequent swamp commands for ~60 seconds until timeout.

  • Fix 1 — interactiveOutputMode() helper (src/cli/context.ts): A new function that returns "json" when ctx.outputMode is "json" OR when stdin is not a TTY. Applied surgically to all 10 interactive search commands so they fall back to structured JSON output instead of crashing. Non-interactive commands (version, model get, workflow run, etc.) are unaffected — they keep their normal output mode.

  • Fix 2 — Safety net in main.ts: Added flushDatastoreSync() to the top-level catch block so the datastore lock is released even on unexpected crashes that bypass runCli()'s own error handling. flushDatastoreSync() is idempotent (nulls its state on first call), so calling it a second time is harmless.

Commands updated with interactiveOutputMode:

  • model search, type search, vault search, vault type search
  • workflow search, workflow run search, workflow history search
  • model method history search, model output search, data search

Test Plan

  • All 2797 tests pass (zero failures)
  • deno fmt --check passes
  • deno lint passes
  • deno check passes
  • Verified the global outputMode approach (auto-switching all commands) caused 6 test failures — confirmed the surgical per-command approach is correct
  • Verified non-interactive commands retain log-mode output in non-TTY contexts

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260310.230813.0-sha.fcc69c53

10 Mar 23:09
Immutable release. Only release title and notes can be modified.
fcc69c5

Choose a tag to compare

What's Changed

  • fix: address adversarial review findings for distributed locking and S3 sync (#672)

Summary

Addresses findings from two rounds of adversarial review on the datastore PR.

Changes

Critical: Path traversal in S3 cache sync

  • Added assertSafePath() that validates resolved paths stay within the cache directory
  • Applied to pullFile(), pullChanged(), pushFile(), and getCachePath()
  • Prevents malicious S3 keys (e.g., ../../../home/user/.bashrc) from writing outside the cache

High: Lock theft via unconditional heartbeat overwrites

  • Added nonce-based fencing tokens to distributed locks
  • LockInfo now includes an optional nonce field (UUID generated on acquire)
  • extend() reads the current lock and verifies the nonce matches before writing
  • If another process has acquired the lock (different nonce), the old holder self-revokes
  • This prevents a paused process from overwriting a legitimately acquired lock after recovery

High: Stale lock detection TOCTOU

  • Simplified stale lock cleanup to best-effort delete + conditional write retry
  • The nonce fencing makes this safe: even if we accidentally delete a fresh lock, the old holder's extend() will see the wrong nonce and self-revoke
  • Removed the ineffective double-check pattern that didn't actually close the race window

High: Degraded mode silently allows corruption

  • Lock acquisition failure now throws instead of logging a warning and continuing
  • Concurrent commands without locks would corrupt data; failing fast is the correct behavior

Medium: Hidden file exclusion asymmetry

  • pushChanged() and pushAll() now skip only specific metadata files (.datastore-index.json, .push-queue.json, .datastore.lock) instead of all dot-files
  • Matches pullAll() behavior so hidden files like .gitkeep sync correctly

Medium: S3 bucket name validation

  • Added regex validation for S3 bucket names (3-63 chars, lowercase, alphanumeric/hyphens/dots)
  • Applied to both SWAMP_DATASTORE env var parsing and .swamp.yaml config loading

Medium: S3 client null body check

  • Replaced response.Body! non-null assertion with explicit null check and descriptive error

Medium: SIGINT handler timeout

  • Lock release on Ctrl-C now has a 5-second timeout before force-exiting
  • Prevents the process from hanging if S3 is unreachable

Medium: Force release holder verification

  • swamp datastore lock release --force now re-verifies the lock holder (via nonce) before deleting
  • Prevents accidentally deleting a lock that was legitimately acquired between inspect and delete

Test plan

  • deno check passes
  • deno lint passes
  • deno fmt passes
  • deno run test — 2797 tests pass
  • deno run compile succeeds

Installation

macOS (Apple Silicon):

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

swamp 20260310.230044.0-sha.2610458f

10 Mar 23:01
Immutable release. Only release title and notes can be modified.
2610458

Choose a tag to compare

What's Changed

  • fix: prevent auto-merge race with adversarial review (#673)

Summary

  • Replaces gh pr merge --auto --squash with gh pr merge --squash in the CI auto-merge job
  • The --auto flag enables GitHub's persistent auto-merge, which merges based on branch protection rules rather than the YAML needs: dependencies
  • This caused PR #669 to auto-merge after the normal review passed but before the adversarial review completed

Root cause

The auto-merge job has needs: [test, deps-audit, claude-review, claude-adversarial-review], but --auto tells GitHub "merge this PR whenever branch protection requirements are met." If claude-adversarial-review isn't a required status check in branch protection settings, GitHub merges as soon as the other checks pass — ignoring the YAML dependency.

Fix

Remove --auto so the merge command executes directly when the job runs. Since the job is gated by needs:, it only runs after all four dependencies (including adversarial review) succeed.

Test plan

  • Verify CI workflow passes on this PR
  • Confirm PRs no longer merge before adversarial review completes

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260310.223411.0-sha.153e19a5

10 Mar 22:35
Immutable release. Only release title and notes can be modified.
153e19a

Choose a tag to compare

What's Changed

  • feat: configurable datastores with S3 sync and distributed locking (#669)

Fixes: #492
Fixes: #511

Summary

Swamp's runtime data (model data, workflow runs, outputs, audit logs, telemetry, secrets, bundles) has always lived in .swamp/ inside the repo. This PR makes the storage backend configurable, adding S3 as a first-class option for team collaboration and introducing distributed locking across both backends to prevent data corruption from concurrent CLI invocations.

  • Two backends: filesystem (default, backward-compatible) and S3 (with local cache + automatic sync)
  • Distributed locking: both backends now acquire a lock before command execution and release it after — filesystem uses advisory lockfiles, S3 uses conditional writes
  • New swamp datastore command group: setup, status, sync, and lock management
  • Automatic migration: swamp datastore setup migrates existing data to the new backend
  • Concurrent S3 transfers: pull/push operations run in batches of 10 to minimize sync latency

User Impact

Zero breaking changes for existing users

Existing repos with no datastore configuration continue to work identically. The default datastore is filesystem at {repoDir}/.swamp/, which is exactly where data lives today. The only behavioral difference is that a .datastore.lock file will now be created inside .swamp/ during command execution — this is transparent and auto-cleaned.

New: S3 datastore for team collaboration

Teams can now share runtime data via S3:

swamp datastore setup s3 --bucket my-bucket --prefix my-project --region us-east-1

This pushes existing local data to S3 and updates .swamp.yaml. Every subsequent command automatically pulls changes before execution and pushes changes after. The local cache at ~/.swamp/repos/{repoId}/ is fully disposable — deleting it or cloning the repo on a new machine repopulates from S3 on the next command.

New: external filesystem datastore

Move runtime data outside the repo (e.g., shared NFS mount):

swamp datastore setup filesystem --path /mnt/shared/swamp-data

Migration paths

From To Command
Default .swamp/ External filesystem swamp datastore setup filesystem --path /path
Default .swamp/ S3 swamp datastore setup s3 --bucket name
External filesystem S3 swamp datastore setup s3 --bucket name
S3 External filesystem swamp datastore setup filesystem --path /path
Any backend Default .swamp/ Edit .swamp.yaml, remove datastore field

Each setup command: verifies the target is accessible, migrates existing data, updates .swamp.yaml, and cleans up the source. Use --skip-migration to skip the data copy.

CI/CD: environment variable override

Override the datastore without modifying .swamp.yaml:

export SWAMP_DATASTORE=s3:my-bucket/my-prefix
export SWAMP_DATASTORE=filesystem:/tmp/swamp-data

Resolution priority: SWAMP_DATASTORE env var > --datastore CLI arg > .swamp.yaml > default.

New: lock management commands

If a process crashes without releasing the datastore lock, the lock auto-expires after 30 seconds. For immediate recovery:

swamp datastore lock status # Show who holds the lock
swamp datastore lock release --force # Force-release stuck lock

Design Choices

Why a lock for filesystem too?

Without locking, two concurrent swamp model run invocations on the same repo could corrupt shared state (overlapping writes to data versions, workflow runs, audit logs). Previously this was a silent race condition. Both backends now acquire a lock at command start and release at command end, making concurrent access safe. The filesystem lock uses advisory lockfiles with Deno.open({ createNew: true }) for atomic creation.

Why not lazy S3 pull?

We considered three approaches for S3 sync performance:

  1. Lazy pull (fetch on cache miss) — best latency but complicates offline behavior and requires intercepting all file reads throughout the codebase
  2. Directory-scoped pull (each command declares which subdirectories it needs) — lower transfer volume but fragile annotation maintenance
  3. Concurrent full pull (batch downloads in parallel) — simplest, no behavioral changes

We chose option 3 (concurrent transfers in batches of 10). It's the lowest-risk improvement and doesn't close any doors. Options 1 and 2 can be layered on later if repos grow large enough to warrant them.

Why size + mtime instead of content hashing?

Change detection compares stat.size and stat.mtime rather than computing content hashes. This avoids reading every file on every sync. The write paths (atomicWriteTextFile, Deno.writeFile) always update mtime, so mtime changes reliably detect rewrites even when file size doesn't change. Under the global lock, there are no concurrent writers to create ABA problems.

Shared S3Client

A single S3Client instance is shared between the lock and the sync service for each command invocation. This avoids duplicate credential resolution and connection overhead.

Sync coordinator supports lock-only mode

The datastore_sync_coordinator.ts accepts optional service and lock parameters independently. Filesystem datastores register lock-only (no pull/push). S3 datastores register both. This keeps the coordinator generic without backend-specific branching.

Lock heartbeat and TTL

Both lock implementations use a background heartbeat that refreshes the lock every TTL/3 (default: every 10 seconds for a 30-second TTL). This prevents long-running commands from having their lock expire. If a process crashes, the lock self-expires after the TTL. The SIGINT handler provides best-effort release on Ctrl-C.

Error-path lock release

flushDatastoreSync() is called on both the success path and the error path in runCli(). This ensures locks are released even when commands fail, preventing stuck locks from cascading into subsequent command failures.

Architecture

Follows domain-driven design with clean layer separation:

Domain layer (src/domain/datastore/):

  • DatastoreConfig — discriminated union type for filesystem and S3 configs
  • DatastorePathResolver — interface for routing file paths to the correct tier
  • DatastorePatternMatcher — gitignore-style glob compiler for exclude patterns
  • DatastoreVerifier — interface for health checks
  • DatastoreMigrationService — file copy and verification for backend migration
  • DistributedLock — interface with acquire(), release(), inspect(), withLock()

Infrastructure layer (src/infrastructure/persistence/):

  • DefaultDatastorePathResolver — path resolver with pre-compiled exclude patterns
  • S3Client — AWS S3 SDK wrapper (GetObject, PutObject, DeleteObject, HeadBucket, ListObjects)
  • S3CacheSyncService — local cache management, index-based change detection, concurrent transfers
  • S3Lock — conditional-write lock with heartbeat
  • FileLock — advisory lockfile with heartbeat
  • DatastoreSyncCoordinator — global singleton managing lock + sync lifecycle

CLI layer (src/cli/):

  • resolve_datastore.ts — config resolution from env/CLI/yaml/default
  • repo_context.ts — wires lock and sync into the repo lifecycle
  • commands/datastore_*.ts — status, setup, sync, lock commands
  • presentation/output/datastore_output.ts — log + JSON rendering

Other changes in this branch

This PR also includes changes from earlier commits on this branch (help command, skill updates, extension improvements, bug fixes). The datastore-specific files are listed above; all other changes are from previously-merged work.

Test plan

  • deno check passes (type checking)
  • deno lint passes
  • deno fmt passes (formatting)
  • deno run test passes (2794 tests, 0 failures)
  • deno run compile succeeds
  • Existing repos with no datastore config work identically (default filesystem backend)
  • swamp datastore status reports health for default filesystem datastore
  • swamp datastore setup filesystem --path /tmp/test-ds migrates data and updates .swamp.yaml
  • swamp datastore setup s3 --bucket migrates data to S3 and updates .swamp.yaml
  • swamp datastore sync performs bidirectional sync with S3
  • swamp datastore lock status shows lock holder or null
  • swamp datastore lock release --force force-releases a stuck lock
  • SWAMP_DATASTORE=filesystem:/tmp/test overrides .swamp.yaml config
  • Concurrent CLI invocations block on lock rather than corrupting data
  • Ctrl-C during a command releases the lock (best-effort SIGINT handler)

Installation

macOS (Apple Silicon):

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

swamp 20260310.220229.0-sha.817e290a

10 Mar 22:03
Immutable release. Only release title and notes can be modified.
817e290

Choose a tag to compare

What's Changed

  • fix: increase extension max file count to 150 (#671)

Summary

  • The extension safety analyzer's MAX_FILE_COUNT was set to 100, which blocked pushing larger service extensions like @swamp/aws/ec2 (104 models)
  • Increased the limit from 100 to 150 to accommodate extensions that cover broad service APIs
  • Updated the corresponding test, design doc, and skill reference to match

Test Plan

  • Updated test now creates 151 files and asserts the limit is 150
  • All 111 extension domain tests pass
  • deno fmt --check passes
  • deno lint passes

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260310.214543.0-sha.ace8210d

10 Mar 21:46
Immutable release. Only release title and notes can be modified.
ace8210

Choose a tag to compare

What's Changed

  • fix: allow multi-segment extension names (#670)

Summary

  • The CLI's SCOPED_NAME_PATTERN regex only allowed two-segment extension names (@collective/name), rejecting hierarchical names like @swamp/aws/ec2 or @swamp/aws/accessanalyzer/analyzer
  • The swamp-club API already supports multi-segment names — this was a CLI-only restriction that blocked publishing extensions with deeper path hierarchies
  • Updated the regex from ^@[a-z0-9_-]+\/[a-z0-9_-]+$ to ^@[a-z0-9_-]+\/[a-z0-9_-]+(\/[a-z0-9_-]+)*$ in all 4 locations (manifest validation, pull, rm, yank commands)
  • Added tests for @swamp/aws/ec2 and @swamp/aws/accessanalyzer/analyzer name formats

Test Plan

  • New unit tests for multi-segment names pass
  • All 2788 existing tests pass
  • deno fmt --check passes
  • deno lint passes
  • Verified swamp-club API already accepts multi-segment names (no server-side changes needed)

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260309.181646.0-sha.6cbf8466

09 Mar 18:17
Immutable release. Only release title and notes can be modified.
6cbf846

Choose a tag to compare

What's Changed

  • feat: add swamp help command and wire it into all skills (#663)

Summary

Fixes #657

Adds a hidden swamp help [command...] command and teaches all 8 skills to reference it, giving AI agents a reliable way to verify exact CLI syntax on demand.

Step 1: swamp help command

Added a hidden CLI command that outputs structured JSON schema for any swamp command tree. When an agent runs swamp help model or swamp help workflow run, it gets the complete, up-to-date flags, subcommands, and argument types — no guessing, no trial-and-error.

Why this is the right approach: Skills contain curated Quick Reference tables, but they can drift from the actual CLI as flags are added or renamed. swamp help reads directly from the Cliffy command tree at runtime, so it's always accurate. It's hidden from --help output to avoid cluttering the human-facing CLI, but fully available to agents.

Step 2: Skill references to swamp help

Added prominent **Verify CLI syntax** callouts to all 8 skills:

  • Skills with CRITICAL sections (model, workflow, vault): Added as a bullet in the CRITICAL rules block — the section agents are trained to read first and follow strictly
  • Skills without CRITICAL sections (data, repo, extension-model, issue, troubleshooting): Added as a bold callout right after the intro paragraph, before Quick Reference — the first thing an agent reads after the heading

Why prominent placement matters: An earlier iteration placed subtle blockquotes after Quick Reference tables. These were easy to skim past — an agent confused about flags would scan the table itself, not a quiet note below it. Moving the references into CRITICAL sections and intro blocks ensures agents see them at the point where they're forming their understanding of how to use the CLI.

User Impact

AI agents working with swamp will encounter fewer trial-and-error cycles when constructing CLI commands. Instead of guessing at flags or hallucinating options from the Quick Reference tables, agents can run swamp help <command> to get authoritative syntax. This reduces failed command attempts, speeds up automation workflows, and improves the overall agent experience for users delegating tasks to AI.

Test Plan

  • swamp help outputs full CLI schema as JSON
  • swamp help model scopes output to model subtree
  • swamp help model method run drills into nested commands
  • Unit tests for schema generation and help command
  • All 8 skills updated with prominent references
  • deno run compile succeeds with updated skills embedded

🤖 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/v20260309.181646.0-sha.6cbf8466/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/v20260309.181646.0-sha.6cbf8466/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/v20260309.181646.0-sha.6cbf8466/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/v20260309.181646.0-sha.6cbf8466/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260309.162343.0-sha.1e5e0c55

09 Mar 16:24
Immutable release. Only release title and notes can be modified.
1e5e0c5

Choose a tag to compare

What's Changed

  • fix: audit timeline misses today's entries in UTC+ timezones (#660)

Summary

Fixes #659

swamp audit failed to read the current day's audit file when the local timezone is east of UTC (e.g. CET/UTC+1). The root cause was a mismatch between how audit files are written vs read:

  • Write path (append): Uses the UTC date from the ISO timestamp (entry.timestamp.split("T")[0]), so files are named with UTC dates (e.g. commands-2026-03-09.jsonl).
  • Read path (findByTimeRange): Used setHours(0,0,0,0) (local time) then toISOString() (UTC) to generate filenames. In UTC+ timezones, local midnight converts to the previous UTC day, so today's file was never opened.

Fix

Changed three lines in findByTimeRange to use UTC methods consistently:

  • setHours(0,0,0,0)setUTCHours(0,0,0,0) — start of date range
  • setHours(23,59,59,999)setUTCHours(23,59,59,999) — end of date range
  • setDate(getDate()+1)setUTCDate(getUTCDate()+1) — date iteration step

This ensures the read path generates the same UTC-based date strings as the write path, regardless of the user's local timezone.

User Impact

Users in UTC+ timezones (CET, IST, JST, AEST, etc.) will now see today's audit entries when running swamp audit. Previously, today's entries were silently missing — only older days' data appeared.

Test Plan

  • Added regression test verifying findByTimeRange reads the correct UTC-dated file for same-day queries
  • Added test verifying multi-day UTC date spanning works correctly
  • All 2775 existing tests continue to pass
  • deno check, deno lint, deno fmt all pass

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


Installation

macOS (Apple Silicon):

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

swamp 20260308.214522.0-sha.9aa5b71a

08 Mar 21:46
Immutable release. Only release title and notes can be modified.
9aa5b71

Choose a tag to compare

What's Changed

  • docs: add sync method pattern to extension model skill (#656)

Summary

Closes #627.

Adds sync as a standard CRUD lifecycle method in the swamp-extension-model skill. This teaches Claude to generate sync methods by default when creating CRUD models, enabling drift detection without any changes to swamp core.

Why model-level, not core

A generic swamp status command would need to know:

  • What the identifier field is called (VpcId vs id vs Name vs slug)
  • How to call the provider API to check existence
  • What "not found" looks like (404, empty response, error code)

The model already knows all of this. The model is the domain expert for its service — sync belongs there, not in a generic framework command.

What changed

  • SKILL.md — CRUD lifecycle section updated from create/update/delete to create/update/delete/sync. Explains the key UX distinction: unlike get (which requires the resource ID as an argument), sync reads the ID from stored state, making it zero-arg and suitable for automated drift detection workflows.
  • references/examples.md — Sync method added to the VPC CRUD example. New standalone "Sync Method" section with a generic pattern and a workflow example showing how to orchestrate sync across an entire stack.
  • references/scenarios.md — Sync method added to the S3 bucket CRUD scenario with the workflow updated to include a sync action.

Design decisions

  • sync is non-optional — unlike polling and idempotent creates (which are opt-in), every CRUD model gets sync by default
  • sync does not throw when the resource is gone — it writes a not_found marker, because the purpose is detection, not failure
  • No swamp core changes needed — all primitives already exist (context.dataRepository.getContent(), swamp data list, swamp data search)

Test plan

  • Verify skill files are valid markdown with correct internal links
  • Verify deno fmt --check passes
  • Test that Claude generates sync methods when asked to create a new CRUD model

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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