Skip to content

Releases: systeminit/swamp

swamp 20260424.234336.0-sha.0022d1ca

24 Apr 23:44
Immutable release. Only release title and notes can be modified.
0022d1c

Choose a tag to compare

What's Changed

  • feat(doctor): add swamp doctor audit preflight diagnostic (swamp-club#156) (#1227)

Summary

Adds swamp doctor audit [--tool <name>] — a new preflight diagnostic that verifies the AI-tool audit integration configured in the repo is healthy end-to-end. Non-zero exit on any fail, safe to gate in CI.

doctor is registered as a parent namespace so future diagnostics (doctor datastore, doctor vault, ...) plug in as siblings. Implements swamp-club#156.

Five checks

Check Scope What it catches
binary-on-path all 4 tools AI tool binary missing from PATH
swamp-binary-on-path all 4 tools (+ Kiro baked-path) swamp missing from PATH, or kiro hook's baked absolute path orphaned by brew upgrade
agent-config-loadable per-tool parser config missing, malformed, or broken (e.g. Kiro tools: ["*"])
default-agent-set Kiro only .kiro/settings/cli.json not pointing chat.defaultAgent at swamp
recording-smoke-test all 4 tools upstream normalizer drift — synthetic postToolUse payload piped through swamp audit record --from-hook must land as a row in today's audit JSONL

The headline verification

Temporarily removing "shell" from KIRO_SHELL_TOOL_NAMES in hook_input.ts, recompiling, and running doctor against a freshly-init'd kiro repo produces:

✗ recording-smoke-test  synthetic kiro payload did NOT land in today's audit JSONL
    hint: The hook normalizer in src/domain/audit/hook_input.ts may have drifted from the upstream contract...

4 passed, 1 failed, 0 skipped — OVERALL: FAIL

Reverted before this commit. This is the load-bearing proof that the feature protects against future upstream drift instead of being theatre.

Name override

The issue body says "please NOT doctor". The team picked doctor anyway — the command is a namespace and will grow; the name fits that shape. Acknowledging here for reviewer context.

Scope note on the three cited Kiro bugs

Issue 156 cites three concrete bugs as motivation. Their status in this PR:

  • tools: ["*"] in kiro agent configagent-config-loadable flags it with a hint; NOT fixed here.
  • Missing chat.defaultAgent: "swamp"default-agent-set flags it; NOT fixed here.
  • Hard-coded tool_name === "execute_bash" in Kiro normalizeralready fixed upstream of this PR. src/domain/audit/hook_input.ts:146-150 has KIRO_SHELL_TOOL_NAMES = new Set(["execute_bash", "shell", "execute_cmd"]). This PR's diagnostic catches the class of bug, it does not fix that specific one.

Ancillary changes

  • Extract todaysAuditFilePath helper. src/infrastructure/persistence/jsonl_audit_repository.ts had two duplicate copies of the commands-YYYY-MM-DD.jsonl format string; moved to src/domain/audit/audit_path.ts and consumed by both the writer and the doctor smoke-test reader. Single source of truth for the filename format.
  • Reserve echo swamp-doctor-smoke-test as a sentinel command prefix. The smoke-test writes a real audit row with this prefix; the audit timeline filters it out of the default view. Opt in with swamp audit --include-diagnostic.
  • Add parseAiToolOrThrow in src/cli/ai_tool_parser.ts — central validator for --tool flags, so bogus values fail with a usage error listing valid names.
  • Docs: design/audit.md, design/audit-doctor.md, and a short "verify the audit integration" block in the swamp-repo skill.

Follow-ups

  • UAT coverage tracked in systeminit/swamp-uat#160 (CLI) and systeminit/swamp-uat#161 (adversarial).
  • swamp-club has GitHub issues disabled — content/manual/reference/doctor.md and a "verify the integration" section for each content/manual/how-to/use-swamp-with-*.md need to be routed through the team's docs process.
  • POSIX-only PATH resolution — documented; Windows support deferred.

Test Plan

  • deno check — clean
  • deno lint — clean
  • deno fmt --check — clean
  • deno run test4922 passed, 0 failed, 1 ignored
  • deno run compile — produces working binary
  • Manual smoke-run on freshly-init'd kiro / claude / cursor / opencode repos — all pass
  • Regression injection (remove "shell" from KIRO_SHELL_TOOL_NAMES, recompile, rerun) — smoke-test correctly FAILS on kiro
  • Real-repo test against ~/code/kiro-audit (existing audit history) — passes; sentinel filter confirmed with swamp audit --include-diagnostic
  • CWD-independence adversarial test — ran from CWD=/ with --repo-dir /tmp/..., synthetic row landed in the target repo, not the CWD

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.230602.0-sha.46b67446

24 Apr 23:07
Immutable release. Only release title and notes can be modified.
46b6744

Choose a tag to compare

What's Changed

  • docs(skills): document markDirty in swamp-extension-datastore (#1226)

Summary

Pick up the `markDirty()` addition from #1225 in the skill that guides
authors building custom datastore providers.

  • `references/api.md` — interface block includes `markDirty(): Promise`,
    plus a section describing when it's load-bearing (fast-path implementations
    that cache a clean/dirty watermark) versus when a no-op is correct (sync
    services that unconditionally walk the cache).
  • `references/examples.md` — the working sync service example returns a
    no-op `markDirty` with a comment pointing at the fast-path pattern in
    `design/datastores.md`.

No code changes, docs only — keeps guidance for extension authors in
lock-step with the core interface change that already shipped.

Test Plan

  • `deno fmt` clean per the skill-files rule in CLAUDE.md.

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.224539.0-sha.ce117565

24 Apr 22:46
Immutable release. Only release title and notes can be modified.
ce11756

Choose a tag to compare

What's Changed

  • fix(datastore): signal cache writes to sync service fast path (#1225)

Summary

The s3/gcs zero-diff fast path in DatastoreSyncService maintains a
local-dirty watermark that it flips during its own pushFile-equivalent.
Swamp core writes into the cache directly from the persistence
repositories (UnifiedDataRepository, YamlOutputRepository,
YamlWorkflowRunRepository, YamlEvaluatedDefinitionRepository), which
bypasses that hook — the next pushChanged short-circuits past the
write and the data lives only in the local cache until eviction. Single
writer setups against a low-traffic bucket are most exposed; high
traffic masks the bug because unrelated remote mutations invalidate the
sidecar.

Fix

  • Add a required markDirty() method to DatastoreSyncService (mirrored
    in packages/testing/datastore_types.ts).
  • Every public mutation on the four datastore-tier repositories calls
    notifyDirty() before any cache write begins, so a crash mid-write
    still leaves the watermark dirty — per-method (not per-atomicWrite)
    keeps the repositories clean and the hook is idempotent anyway.
  • Single sync service instance threads through
    requireInitializedRepoUnlockedacquireModelLocks and through the
    serve context (OpenServerState, ConnectionContext,
    WebhookServiceDeps), so an implementation that caches the sidecar
    flag in memory stays coherent across the markDirty hook and the
    pull/push fast-path read. The `acquireModelLocks` param is optional
    for backward compatibility; every caller in the repo now passes one.
  • Document the contract under the Zero-Diff Fast Path section in
    `design/datastores.md`.
  • Filesystem datastores wire no service; `notifyDirty` is a no-op for
    them.

Extension follow-up

The required interface change surfaces as a compile-time signal to
extension authors (`@swamp/s3-datastore`, `@swamp/gcs-datastore`,
swamp-club/166) that they need to implement `markDirty()` — trivial:
it's the same primitive as their internal `pushFile` hook's dirty-flip.

Test Plan

  • New repository contract tests pin `markDirty` invocation on every
    public mutation, including the negative cases (reads, dry-run GC,
    no-op delete) where it must not fire.
  • Existing `datastore_sync_service_test.ts` still passes; 12 stub
    sync services across tests updated to include the new field.
  • `testing_package_compat_test.ts` structurally verifies the
    `@systeminit/swamp-testing` mirror still matches core.
  • `deno check`, `deno lint`, `deno fmt --check`,
    `deno run test` (4854 passed, 0 failed, 1 ignored),
    `deno run compile` all clean.

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.194520.0-sha.bd275a89

24 Apr 19:46
Immutable release. Only release title and notes can be modified.
bd275a8

Choose a tag to compare

What's Changed

  • fix(extensions): complete legacy layout migration on repo upgrade (swamp-club#160) (#1224)

Summary

Closes swamp-club#160.

swamp repo upgrade was silently deleting user working-tree files when it detected extensions tracked at a legacy on-disk layout. The two-phase migration added in #1186 renamed gen-1 paths to gen-2, then deleted the gen-2 files expecting the user to run swamp extension install afterward to restore them. No warning, no prompt, no automatic follow-up.

The fix collapses the split between the two primitives that owned "make extension state correct":

  • extensionInstall now treats legacy-layout entries as needing re-pull (not just missing files), installs them into the per-extension subtree, and sweeps the original legacy paths only after a successful install.
  • repo upgrade invokes extensionInstall directly as its final step.
  • migrateExtensionLayout and its two phase methods are deleted (~280 LOC) along with ExtensionLayoutMigrationSummary, pruneEmptyDirsUp, and the extensionMigration result field.

Net LOC: −170 despite adding the install-pass wiring, a test seam, a shared factory, and several new tests.

User-visible behavior

  • swamp repo upgrade now completes the migration end-to-end. No manual swamp extension install follow-up required for the common case.
  • On install failure (network down, extension yanked, auth missing), legacy files are preserved and the error names the failed extensions with a recovery command.
  • swamp extension install also migrates legacy-layout repos. Previously a silent no-op on legacy state — positive side effect of unifying the two primitives.

Latent bug caught during verification

Running an end-to-end manual test against @swamp/aws/s3 surfaced a second bug: empty _lib/ directories were being stranded after the sweep. Root cause: resolveRepoDir returns "." by default, which propagated through join(".", "path") → "path" (relative), and cleanupEmptyParentDirs's startsWith(stopAtDir) check silently failed against relative paths. The factory now absolutizes repoDir up front so downstream filesystem helpers always see absolute paths. Added a regression test asserting nested parent dirs are pruned.

This one wouldn't have been caught by unit tests alone — my initial unit tests used absolute tmpDir from Deno.makeTempDir, which masked the relative-path issue. Running against a real extension with a nested _lib/ found it immediately.

Test plan

  • deno check — clean
  • deno lint — clean (1081 files)
  • deno fmt — clean (1199 files)
  • deno run test — 4728 pass, 0 fail, 1 ignored (added 8 new tests)
  • deno run compile — binary produced
  • Manual E2E happy path: @swamp/aws/s3 seeded as gen-1 legacy, swamp repo upgrade run; all 11 model files migrated to .swamp/pulled-extensions/@swamp/aws/s3/models/…, filesChecksum anchor matches original pull byte-for-byte (a9378bf483…), legacy paths (including nested _lib/) fully swept.
  • Manual E2E failure path: lockfile referencing @me/launchd-daemon (not in registry); swamp repo upgrade exits non-zero with clear error naming the extension + recovery command; all 4 legacy files preserved on disk.
  • Manual E2E via extension install: same legacy seed; swamp extension install also migrates successfully (positive side effect verified).

Notes for reviewers

  • The swamp extension install behavior change (no-op → auto-migrate on legacy repos) is intentional; documented in the swamp-repo skill.
  • There is no CHANGELOG.md in this repo, so the user-visible release notes live in this PR description.
  • I skipped the integration test against a real/fake registry as out of scope for this PR; unit coverage + manual verification cover the critical paths. A follow-up would be reasonable.
  • Private/auth-gated extensions are not directly verified end-to-end — the factory uses the same ExtensionApiClient as swamp extension install, so coupling should hold, but worth spot-checking if a reviewer has a private extension in a test lockfile.

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.185624.0-sha.633e3ae7

24 Apr 18:57
Immutable release. Only release title and notes can be modified.
633e3ae

Choose a tag to compare

What's Changed

  • fix(datastore): clarify --timeout scope in SyncTimeoutError message (#1223)

Summary

Follow-up to #1222 addressing the two actionable findings from review:

1. CLI UX Review — --timeout remedy was misleading for implicit syncs

The timeout fires from flushDatastoreSync() after every command, not just swamp datastore sync. The previous message led with • Rerun with --timeout <seconds>, which would fail for a user whose timeout fired from e.g. swamp model run (the flag only exists on swamp datastore sync).

Fix: reorder remedies so the env var (universal escape hatch) is listed first and the --timeout flag is explicitly scoped to swamp datastore sync:

```
Datastore push to "@swamp/s3-datastore" timed out after 300000ms. Try one of:
• Set SWAMP_DATASTORE_SYNC_TIMEOUT_MS for the duration of your shell session — applies to every command that triggers sync, including the implicit pull/push around write commands.
• If the timeout fired on an explicit 'swamp datastore sync', rerun with --timeout (e.g. --timeout 1800 for large one-off syncs). The flag is not available on other commands; use the env var above for those.
• If you are on @swamp/s3-datastore or @swamp/gcs-datastore at scale, update to the latest extension — the fingerprint fast path short-circuits zero-diff syncs.
• If a prior process crashed without releasing the lock, run 'swamp datastore lock release --force' (add --model / for a specific model lock).
```

New scope-clarification test pins the contract: the message MUST name swamp datastore sync explicitly and MUST mention the env var covers implicit syncs. That prevents a future well-meaning reword from reintroducing the same trap.

2. Code Review + Adversarial Review — CreateDatastoreSyncDepsOptions not re-exported from barrel

The new interface lived at the internal path src/libswamp/datastores/sync.ts. Any consumer outside the CLI wanting to type an options variable would have had to violate CLAUDE.md's barrel-import convention. One-line fix: add type CreateDatastoreSyncDepsOptions to the export from src/libswamp/mod.ts.

What this does NOT change

  • The precedence chain (CLI flag → config → env var → default) is unchanged.
  • The structured fields of SyncTimeoutError (label, direction, timeoutMs, cause) are unchanged.
  • No behavior change for users who don't hit the timeout.

Test plan

  • deno check — clean
  • deno lint — clean (1094 files)
  • deno fmt — clean
  • deno run test — 4843 passed / 0 failed
  • deno run compile — binary built
  • New test SyncTimeoutError: --timeout remedy is scoped to 'swamp datastore sync' passes

Links


Installation

macOS (Apple Silicon):

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

swamp 20260424.184437.0-sha.44543d36

24 Apr 18:45
Immutable release. Only release title and notes can be modified.
44543d3

Choose a tag to compare

What's Changed

  • feat(datastore): add --timeout flag and enrich SyncTimeoutError (swamp-club#164) (#1222)

Summary

Companion PR to the @swamp/s3-datastore fingerprint fast-path fix for lab/164 (minutes-slow swamp datastore sync at 4k-file scale, even on zero-diff). This PR adds the swamp-core ergonomics: a --timeout CLI flag for one-off sync overrides, and a richer SyncTimeoutError message so users get actionable next steps when the timeout does fire.

Either PR may land first — the enriched error uses version-free wording, so there is no ordering dependency.

What changed

--timeout <seconds> flag on swamp datastore sync

  • Per-invocation override; wins over CustomDatastoreConfig.syncTimeoutMs and SWAMP_DATASTORE_SYNC_TIMEOUT_MS.
  • Validated at the CLI boundary: positive integer, rejected ≤0, capped at 21600s (6h) — generous enough for initial seeding from a slow link, bulk recovery after an outage, or 100k-file migrations, while rejecting fat-finger misconfigs. The env var stays uncapped as the shell-session escape hatch.
  • Scoped to swamp datastore sync only. Write commands that trigger implicit sync keep their existing escape hatch (env var). Adding --timeout everywhere would inflate the CLI surface without commensurate benefit.
  • --help clearly describes precedence so users reach for the right knob.

Enriched SyncTimeoutError message

Before:
```
Datastore push to "@swamp/s3-datastore" timed out after 300000ms. If a prior process crashed without releasing the lock, run 'swamp datastore lock release --force' (add --model / for a specific model lock).
```

After:
```
Datastore push to "@swamp/s3-datastore" timed out after 300000ms. Try one of:
• Rerun with --timeout (e.g. --timeout 1800 for large one-off syncs).
• Set SWAMP_DATASTORE_SYNC_TIMEOUT_MS for the duration of your shell session.
• If you are on @swamp/s3-datastore or @swamp/gcs-datastore at scale, update to the latest extension — the fingerprint fast path short-circuits zero-diff syncs.
• If a prior process crashed without releasing the lock, run 'swamp datastore lock release --force' (add --model / for a specific model lock).
```

Version-free wording keeps the message stable across extension releases. No changes to the error's structured fields (label, direction, timeoutMs, cause).

Internal plumbing

  • resolveSyncTimeoutMs(config, overrideMs?) — new optional parameter at highest precedence. Non-positive overrides silently fall through to the next source.
  • createDatastoreSyncDeps(repoDir, resolver, options?) — new CreateDatastoreSyncDepsOptions interface with syncTimeoutMsOverride.

Docs

design/datastores.md — expanded "Sync Timeout" section with the 4-tier precedence chain and reference to the enriched error. New "Zero-Diff Fast Path (Extension Guidance)" subsection with backend-agnostic wording (fingerprint + dirty-flag sidecar pattern), so future extension authors have a breadcrumb. Notes that sync is not a content-integrity tool — use DatastoreVerifier for that.

What this does NOT do

  • Does not fix the 5-minute zero-diff sync itself — that's the @swamp/s3-datastore fingerprint fast-path PR. This PR is the ergonomics layer.
  • Does not change default behavior for anyone who doesn't pass --timeout or hit the timeout.
  • Does not close the AbortSignal plumbing gap in the s3 extension.

Test plan

  • deno check — clean
  • deno lint — clean (1091 files)
  • deno fmt — clean
  • deno run test — 4822 passed / 0 failed (19 new tests)
  • deno run compile — binary built
  • ./swamp datastore sync --help--timeout flag documented correctly
  • Reporter runs swamp datastore sync --timeout 60 against their 4k-file repo and confirms: (a) validation rejects 0/negative/>21600, (b) enriched error message renders all four remedies, (c) flag override wins over env var when both are set. Tracked on lab/164 as the verification gate.

New tests

File What it covers
src/domain/datastore/datastore_sync_service_test.ts Enriched message contents; version-free extension hint (regex guards against calendar-version and semver); structured field preservation; multi-line JSON round-trip.
src/domain/datastore/datastore_config_test.ts resolveSyncTimeoutMs precedence: override wins over config/env/default; non-positive override falls through; undefined preserves existing precedence.
src/cli/commands/datastore_sync_test.ts parseTimeoutFlag validation: seconds→ms conversion, upper-bound acceptance, zero/negative/over-cap/non-integer/non-number rejection.

Links


Installation

macOS (Apple Silicon):

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

swamp 20260424.182054.0-sha.e40c597d

24 Apr 18:21
Immutable release. Only release title and notes can be modified.
e40c597

Choose a tag to compare

What's Changed

  • feat(drivers): finish repo-level defaultDriver — direct path + definition tier (swamp-club#165) (#1221)

Summary

Closes swamp-club#165. Completes the cleanup gaps left by #1219 so the repo-level defaultDriver priority chain now applies uniformly to both workflow and direct swamp model method run paths. Also fixes a concurrent-read race on the marker load and un-breaks the silently-dropped definition.driver tier.

Three deliverables, one commit:

  • Direct swamp model method run now honors defaultDriver. src/libswamp/models/run.ts routes through resolveDriverConfig with cli/definition/repo tiers. Serve/WS (src/serve/connection.ts) and HTTP SSE (src/serve/open/http.ts) paths inherit for free. A new loadRepoMarker dep on ModelMethodRunDeps is built via the extracted createRepoMarkerLoader helper.
  • Promise-memoize the marker read. Previously WorkflowExecutionService.loadRepoMarker cached the resolved value — two concurrent callers both saw undefined and both hit the file. Now this.markerPromise ??= markerRepo.read(...); .swamp.yaml is read at most once per service instance. The primitive is extracted to src/infrastructure/persistence/repo_marker_loader.ts and reused by all four factories (workflow service, CLI, serve/WS, HTTP SSE).
  • Make the definition tier live. src/domain/workflows/execution_service.ts:523 used to read ctx.driver ?? evaluatedDefinition.driver — dead code, because ctx.driver was always populated by the old upstream resolveDriverConfig call (with "raw" as its fallback), so the RHS never fired and definition.driver was silently dropped. StepExecutionContext now carries unresolved driverTiers: { cli, step, job, workflow, repo } and final resolution happens inside DefaultStepExecutor.executeModelMethod where evaluatedDefinition is in scope.

Behavior changes

  • swamp model method run <m> <meth> in a repo with defaultDriver: docker in .swamp.yaml now runs via docker without --driver. --driver raw override still wins.
  • Model definitions with driver: set at the definition level are now honored during workflow execution. Internal blast radius: zero — grep of extensions/**/manifest.yaml and extensions/**/*.yaml returned no hits. Third-party extensions that set driver: at the definition level will now apply it (this was the documented design from day one but was never wired).
  • Malformed .swamp.yaml now aborts every direct method run with a YAML parse error (previously direct runs didn't read the marker at all). Consistent with workflow behavior and documented in design/execution-drivers.md.

Tests added

  • src/infrastructure/persistence/repo_marker_loader_test.ts — concurrency primitive: two simultaneous calls through a Promise.withResolvers latch, assert exactly one underlying .read() call. Covers null-result caching too.
  • src/domain/models/method_execution_service_test.ts — pre-flight check receives the resolved driver/driverConfig from MethodContext (propagation audit).
  • src/libswamp/models/run_test.ts — four direct-path resolution tests: defaultDriver from marker wins; CLI override wins; raw fallback; definition tier applies when no higher tier set.
  • src/domain/workflows/execution_service_test.ts — existing three workflow-path resolution tests updated to assert on the new driverTiers shape.
  • integration/driver_resolution_test.ts — end-to-end CLI smoke (no docker required): defaultDriver honored, CLI override wins, malformed YAML aborts loudly.

Docs

  • design/execution-drivers.md — added a short note under "Resolution Priority" stating that the priority chain applies uniformly to workflow and direct paths and that malformed .swamp.yaml aborts at start-of-run.
  • Follow-up docs gap (not in this PR): the swamp-club manual reference at content/manual/reference/repository-configuration.md still does not document defaultDriver / defaultDriverConfig — pre-existing gap from #1219. systeminit/swamp-club has GitHub issues disabled; flagging here so the gap can be routed to the swamp-club lab.

Out of scope (per issue body, separate follow-ups)

  • Named-fields refactor of resolveDriverConfig (positional DriverSource | undefined params).
  • WorkflowExecutionService.execute() option forwarding (currently drops driver).
  • Runtime schema validation of RepoMarkerData (the parseYaml(...) as RepoMarkerData cast).
  • UAT coverage for --driver / defaultDriver in systeminit/swamp-uat.

Test plan

  • deno check — passes
  • deno lint — passes
  • deno fmt --check — passes
  • deno run test — 4823/4823 pass
  • deno run compile — binary produced
  • Local smoke: scratch repo with defaultDriver: raw → honored; --driver raw beats defaultDriver: docker; malformed YAML aborts with exit code 1.

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.180844.0-sha.03130a3d

24 Apr 18:09
Immutable release. Only release title and notes can be modified.
03130a3

Choose a tag to compare

What's Changed

  • docs(skills): document bare-specifier vs scorer hermeticity (swamp-club#161) (#1220)

Summary

Closes swamp-club#161. Following #1218 shipping swamp extension quality, authors now discover locally that the scorer strips the tarball's deno.json and writes a controlled one with no imports map — so bare "zod" imports fail with deno doc --json failed: Import "zod" not a dependency before factor scoring even begins. This PR teaches that pattern to authors through the two skills that previously led them into the trap.

Three files, +50/-7 lines:

  • swamp-extension-quality/references/templates.md — the JSDoc entrypoint skeleton was showing bare "zod"; switched to "npm:zod@4" with a rationale bullet explaining hermeticity. An author who copies the template literally now produces an extension that scores.
  • swamp-extension-publish/references/publishing.md — the Import Rules had two contradictory bullets ("npm:zod@4" is "always required" vs. bare specifiers "can be used" with deno.json). Rewritten into one coherent paragraph that carries both load-bearing signals: hermeticity at score time AND zod-specific externalization (why zod in particular is called out, not merely a consequence of hermeticity).
  • swamp-extension-quality/SKILL.md — added a gotcha block under "Essential mechanics authors get wrong" that names the failure mode explicitly, calls out the Deno no-import-prefix default that activates when a deno.json with imports is present (which is every swamp repo's default state, creating a catch-22), and gives concrete mitigations: either global "lint": { "rules": { "exclude": ["no-import-prefix"] } } in deno.json, or per-import // deno-lint-ignore no-import-prefix. Also added a one-sentence cross-link from the new "Self-check your score locally" section and a symptom→fix row to "Common patterns" so a reader landing anywhere in the skill finds the fix.

Test Plan

Three-layer verification:

  • deno fmt --check clean on all three files
  • deno check clean
  • deno lint clean (1088 files)
  • deno run test4803 passed, 0 failed
  • Executable round-trip in /tmp/swamp-issue-161-verify:
    • Bare "zod" import → swamp extension quality throws the exact error documented in the gotcha (deno doc --json failed: Warning Import "zod" not a dependency)
    • Switch to "npm:zod@4" → scorer runs and reports 11/12 (91%) factor results
    • The test also surfaced the Deno no-import-prefix default rule firing as predicted, and the documented mitigation (lint.rules.exclude) unblocked the round-trip — confirming both halves of the gotcha match the tool's actual behaviour.

Follow-up (not in this PR)

The deadlock between the scorer (strips deno.json) and Deno's default lint rules (forbid npm: prefix when an imports map is present) is ultimately a swamp-club server-side concern. A future follow-up issue could make the analyzer honour the tarball's files/deno.json with appropriate hardening — the README/LICENSE promotion logic already does similar. Until then, the gotcha documents the author-side workaround.

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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

swamp 20260424.171017.0-sha.76b653b9

24 Apr 17:11
Immutable release. Only release title and notes can be modified.
76b653b

Choose a tag to compare

What's Changed

  • feat(drivers): repo-level defaultDriver in .swamp.yaml (swamp-club#159) (#1219)

Summary

Closes swamp-club#159. Adds a repo-level defaultDriver (and defaultDriverConfig) to .swamp.yaml so a repo can declare a baseline execution driver once, without touching every workflow or passing --driver on every CLI invocation.

New resolution chain for workflow steps:

cli > step > job > workflow > definition > repo > "raw"
  • RepoMarkerData gains two optional fields (defaultDriver, defaultDriverConfig) — same shape as the existing datastore field.
  • resolveDriverConfig gains an optional 6th repo tier, positioned below definition and above the "raw" fallback.
  • WorkflowExecutionService loads .swamp.yaml once per run() (memoized on the instance so nested workflow calls don't re-read) and passes the repo tier into resolveDriverConfig at the step-context build site.
  • design/execution-drivers.md updated to document the new tier with an example.

Scope: workflow execution only. Direct swamp model method run invocations go through a separate code path that doesn't call resolveDriverConfig today and will still default to "raw" when no CLI override is supplied. Flagged in the adversarial review as ADV-1; can be a follow-up if desired.

Test Plan

  • deno check — passes
  • deno lint — passes
  • deno fmt --check — passes
  • deno run test — 4732 passed / 0 failed / 1 ignored
  • deno run compile — produces a working binary

New tests added:

  • 5 cases in driver_resolution_test.ts covering repo-tier precedence (wins over default, loses to workflow/job/step/cli, skipped when driver undefined but driverConfig set)
  • 1 roundtrip in repo_marker_repository_test.ts with defaultDriver + defaultDriverConfig
  • 3 service-level tests in execution_service_test.ts with a real .swamp.yaml on disk: default applied, CLI overrides, no default → raw

Installation

macOS (Apple Silicon):

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

swamp 20260424.164547.0-sha.31006b67

24 Apr 16:47
Immutable release. Only release title and notes can be modified.
31006b6

Choose a tag to compare

What's Changed

  • feat(extensions): add quality command and opportunistic package cache (swamp-club#163) (#1218)

Summary

Implements swamp-club#163 — a new swamp extension quality <manifest> CLI that scores an extension against the Swamp Club rubric locally, mirroring the server's scorecard pipeline so local results match the score the registry will compute after publish.

  • New CLI command: swamp extension quality manifest.yaml [--json]. Exits non-zero if any factor misses; suitable for CI self-checks.
  • Server-mirrored scorer: extension_rubric_scorer.ts mirrors analysis-factors.ts and the rubric-v2 composition from score.ts — same slow-type code set, same JSDoc coverage shape, same README/LICENSE lookup in the extracted tarball, same 12-point weighting.
  • Parity tests: 24 tests marked [parity] port the upstream swamp-club test suite so logic drift is caught before release.
  • Opportunistic package cache at .swamp/cache/packages/<hash>/: keyed on source inputs (manifest + resolved file contents + deno config). extension quality writes the packaged tarball; extension push checks the cache before packaging and reuses the bytes on a hit. Any source change invalidates the entry by construction — authors who run quality before push don't pay twice, and the bytes scored equal the bytes uploaded.

Opt-in by design

quality is uniformly opt-in: push's behaviour is unchanged, no new flags, no mandatory gate. The swamp-extension-publish and swamp-extension-quality skills gain brief pointers at the new CLI between states 6 and 7 of the publish flow.

Known caveat

repository-verified is a structural check on the CLI side (HTTPS + allowlisted host). The server additionally performs an HTTP HEAD to confirm the repo is public — so a local "earned" can come back "missing" from the registry if the repo URL is malformed or private. The log renderer surfaces this caveat. Follow-up issue: narrow the gap (HTTP HEAD from the CLI, or a shared scoring package between this repo and swamp-club).

Smoke test

Ran against systeminit/swamp-extensions/datastore/s3 — reports 12/12 points, 100%, all factors earned, matching the registry.

Test Plan

  • 10 unit tests for extension_package_cache.ts (hit/miss, determinism, cache invalidation)
  • 39 unit tests for extension_rubric_scorer.ts covering every factor and edge case
  • 24 [parity] tests ported from swamp-club's analysis-factors_test.ts and scorecard_test.ts
  • 6 integration tests in integration/extension_quality_test.ts covering the full CLI pipeline (package → cache → extract → deno doc → compose), including cache hit/miss, source mutation invalidating cache, log and JSON modes
  • Smoke test against real @si/s3-datastore extension — 12/12 (100%), matches registry
  • deno check clean
  • deno lint clean
  • deno fmt --check clean
  • deno run test (4,802 passed, 1 pre-existing flaky unrelated to this change, 1 ignored)
  • deno run compile succeeds

Follow-ups (not in this PR)

  • File issue in systeminit/swamp-uat for CLI UAT coverage (tests/cli/extension/quality/)
  • File issue in systeminit/swamp-club to document the new command in content/manual/how-to
  • Consider a shared scoring package between systeminit/swamp and systeminit/swamp-club to eliminate the current ~100 lines of mirrored logic

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

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