Skip to content

Tags: swamp-club/swamp

Tags

v20260613.215821.0-sha.de70f299

Toggle v20260613.215821.0-sha.de70f299's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(vault): write secret value to stdout without log formatting (#646) (

#1576)

## Summary

- `vault read-secret` used `logger.info` to output the secret value,
which prepended timestamp, level, and category formatting (e.g.
`10:00:15.092 INF vault·read-secret "value"`) to stdout — breaking
`$(swamp vault read-secret ...)` shell substitution
- Switched to `writeOutput()` for undecorated stdout, matching the
established pattern used by 15+ other renderers
- Added unit tests for both log and JSON output modes

## Test Plan

- [x] Reproduced the bug in a scratch repo: `swamp vault read-secret ...
--force 2>/dev/null | od -c` showed log prefix in stdout
- [x] Verified the fix: same command now shows only the raw secret value
- [x] New unit tests pass: `deno run test
src/presentation/renderers/vault_read_secret_test.ts`
- [x] Full test suite passes (7032 passed, 1 pre-existing unrelated
failure in `http_update_checker_test.ts`)
- [x] `deno check`, `deno lint`, `deno fmt` all pass

Closes #646

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

v20260613.215040.0-sha.f32c9a56

Toggle v20260613.215040.0-sha.f32c9a56's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(cli): deduplicate model type describe output and add --compact m…

…ode (#1575)

## Summary

Fixes #615 — `model type describe --json` was duplicating all
output specs into every method (40% bloat, 220KB for a 16-method type)
and carrying a redundant `inputs` field identical to `arguments`.

- **Hoist `dataOutputSpecs` to type level** in `TypeDescribeData`,
removing per-method duplication. Matches the domain model where specs
are defined on the type, not per-method.
- **Add `--compact` flag** producing a minimal digest (~3-5KB): method
names, descriptions, argument property names/types/required, output spec
names only. Designed for the agent discovery hot path.
- **Drop `inputs` field** from `MethodDescribeData` (was a byte-for-byte
duplicate of `arguments`).
- Update all renderers (`type_describe`, `model_get`,
`model_method_describe`, `model_search`) and generators (`describe`,
`get`, `create`, `method_describe`).
- Update swamp, swamp-getting-started, and terminal-output skills to
recommend `--compact --json` for discovery.

## Test Plan

- [x] New unit tests for `toMethodDescribeData` (no specs/inputs),
`buildDataOutputSpecs`, type-level specs in describe output, compact vs
full JSON rendering
- [x] All existing tests updated for new output shape
- [x] `deno check` / `deno lint` / `deno fmt` / `deno run test` — 7037
tests pass, 0 failures
- [x] `deno run compile` succeeds
- [x] Filed UAT issue: swamp-club/swamp-uat#266
- [x] Filed docs issue: #651

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Magistr <umag@users.noreply.github.com>

Co-authored-by: Magistr <umag@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

v20260613.165506.0-sha.df3947ba

Toggle v20260613.165506.0-sha.df3947ba's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(reports): make reports.require failures loud (#640) (#1574)

## Summary

Fixes #640, where a pulled extension report named in a
workflow's `reports.require` was silently skipped — no error, no
warning, no artifact — while `--report <name>` and local extension
reports worked.

The root symptom is that an unresolvable required report was dropped
from the candidate set with zero diagnostics. This PR makes
`reports.require` a real contract and closes two adjacent silent-skip
paths found during investigation.

### Changes

1. **Loud unresolvable requires** (`report_execution_service.ts`): after
the lazy-promotion pass, any `reports.require` name still absent from
the registry now logs a warning naming the report and the remedy, emits
a `report_failed` event, persists a searchable error artifact (so `swamp
report search` surfaces it), and counts as a failure — which fails a
`swamp model method run`, matching how a required report that loads then
throws already behaves. Names also in `reports.skip` are exempt. A new
`emitUnresolvableRequireFailures` parameter lets the method+model scope
callers dedup the warning.

2. **Surfaced swallowed errors**: report-runner catch blocks in
`workflow_report_runner.ts` and `method_report_runner.ts` now log at
`warn` instead of `debug`, so a broken required bundle is visible at the
default log level (errors are still swallowed so a broken report can't
mask the run result).

3. **`reportFilterOptions` defaults to `{}`** in
`WorkflowExecutionService.run`/`resume`. `swamp workflow resume` never
threaded the CLI report flags, so resumed runs silently skipped **all**
workflow- and step-scope reports, required ones included. An absent
filter now means "no filtering", not "no reports".

### Behavior change (intentional)

A model definition or workflow with a missing/typo'd required report
changes from **silent success** to a **failed run**. This is the point
of the fix — a required report that never runs should not pass silently.

### Note on the original report

We could not reproduce the silent skip on Linux, at the reporter's exact
build (873563f) or at HEAD — the pulled
`@webframp/terraform-drift-report` auto-executes via `require` on cold
and warm catalog runs. `--report` is a pure narrowing filter over the
same candidate set, so the reported symptom pair implies the repo state
changed between runs (likely an `extension pull` repairing a broken
catalog entry). A diagnostics request is posted on the issue; regardless
of the original trigger, every path here is now loud.

## Test Plan

- New unit tests in `report_execution_service_test.ts`: unresolvable
require emits `report_failed` + counts a failure + persists an error
artifact + does not throw + sibling reports still run;
`emitUnresolvableRequireFailures=false` suppresses the duplicate; skip
exempts the name; persistence failure still reports the failure.
- New regression tests in `execution_service_test.ts`: `run()` executes
workflow-scope required reports with no `reportFilterOptions`; step
context defaults the options to `{}`. Two CONTRACT tests updated to
reflect that the builtin workflow summary now emits on a bare
`service.run()`.
- Manual verification against a real pulled
`@webframp/aws/terraform-drift` repo with the compiled binary: drift
report still runs exactly once per run; a workflow/model requiring a
nonexistent report now warns, emits `report_failed`, writes a `report
search`-visible artifact, and exits non-zero.
- `deno check`, `deno lint`, `deno fmt`, `deno run compile` clean. Full
suite green except pre-existing unrelated failures on `main` (filed as
#645).

Docs: `design/reports.md` updated; manual-docs follow-up filed as
swamp-club Lab #648. UAT coverage gap filed as swamp-club/swamp-uat#264.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: MELLENS <mellens@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

v20260612.100934.0-sha.2903cf62

Toggle v20260612.100934.0-sha.2903cf62's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore: streamline CLAUDE.md (#1569)

## Summary

Deduplication and accuracy pass over CLAUDE.md (169 → 155 lines,
single-file diff):

- **Removed the skill-creator duplication.** The Skills section mandated
loading `skill-creator` as a hard prerequisite, then inlined ~22 lines
of content that skill already owns (structure diagram, frontmatter
rules, 500-line limit, no-extraneous-files). That paid the context cost
twice per session and created a drift hazard. The mandate stays, along
with the genuinely repo-specific rules: uppercase `SKILL.md` and `deno
fmt` after skill markdown edits.
- **Verification commands stated once.** The check/lint/fmt commands
appeared in Code Style, Commands, and Verification; `deno run compile`
appeared in both Source Control and Verification. The Verification
section is now the single canonical checklist.
- **Added the skill testing workflow.** New skills-section note covering
`npx tessl skill review` (≥ 90% average) and `deno run
eval-skill-triggers` (promptfoo), accurately scoped: CI gates the
bundled skills (`swamp`, `swamp-getting-started`) on these; for other
skills they're hygiene, not a gate. Pointer to `design/skills.md` for
the full pipeline.
- **Reordered sections** so Commands flows into Verification and
Architecture sits next to Testing.

Earlier revisions of this branch also removed the `terminal-output`
skill and updated the vendored `skill-creator` to latest upstream; both
were reverted after review. terminal-output's SKILL.md is the only home
of the output design-system conventions (not covered by
`design/rendering.md`), and the new upstream skill-creator prescribes an
eval workflow that competes with this repo's tessl/promptfoo pipeline —
each needs its own follow-up before landing.

## Test Plan

- `deno fmt --check` — clean
- `deno lint` — clean
- `deno run test` — 6898 passed, 0 failed
- Verified the removed CLAUDE.md rules are stated in the vendored
skill-creator (frontmatter, 500-line limit, no extraneous files)
- Verified CI scoping claims against `scripts/review_skills.ts`
(BUNDLED_SKILLS) and `evals/promptfoo/generate_config.ts` (hardcoded
skill list)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

v20260611.205205.0-sha.ad439a70

Toggle v20260611.205205.0-sha.ad439a70's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(extensions): allow extensions to declare resource specs (#1573)

## Summary

Closes #619.

- Adds an optional `resources` field to `UserExtensionSchema`, allowing
`export const extension` to declare new resource specs on the target
model type
- Extends `modelRegistry.extend()` with a `resources?` parameter that
merges with conflict detection (same pattern as methods, checks, and
reports)
- Updates `processSecondaryExport()` to pass extension-declared
resources through to `extend()`

Previously, extensions could add methods and checks but not resource
specs — if an extension method needed a different output shape than the
target model's existing resources, the only option was to build a
standalone model. Now extensions can declare their own resources and
write to them.

## Test Plan

- Added 4 unit tests for `ModelRegistry.extend()` with resources: merge,
conflict detection, preservation when absent, and adding to a model with
no existing resources
- Added 2 integration tests in `user_model_loader_test.ts`: extension
resource merge via loader, and conflict detection via loader
- Verified end-to-end in a scratch repo (`/tmp/swamp-repro-issue-619`):
- **Before**: `swamp model method run my-widget audit` fails with
`Undeclared resource spec 'audit' in model 'repro/widget'. Declared
resource specs: state`
- **After**: succeeds, writes audit data to the extension-declared
`audit` resource with correct schema, garbage collection, and tags
- `deno check`, `deno lint`, `deno fmt`, `deno run test`, `deno run
compile` all pass

Co-authored-by: Mark Jentz <jentz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

v20260611.204926.0-sha.696db232

Toggle v20260611.204926.0-sha.696db232's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(extensions): allow extensions to declare resource specs (#1573)

## Summary

Closes #619.

- Adds an optional `resources` field to `UserExtensionSchema`, allowing
`export const extension` to declare new resource specs on the target
model type
- Extends `modelRegistry.extend()` with a `resources?` parameter that
merges with conflict detection (same pattern as methods, checks, and
reports)
- Updates `processSecondaryExport()` to pass extension-declared
resources through to `extend()`

Previously, extensions could add methods and checks but not resource
specs — if an extension method needed a different output shape than the
target model's existing resources, the only option was to build a
standalone model. Now extensions can declare their own resources and
write to them.

## Test Plan

- Added 4 unit tests for `ModelRegistry.extend()` with resources: merge,
conflict detection, preservation when absent, and adding to a model with
no existing resources
- Added 2 integration tests in `user_model_loader_test.ts`: extension
resource merge via loader, and conflict detection via loader
- Verified end-to-end in a scratch repo (`/tmp/swamp-repro-issue-619`):
- **Before**: `swamp model method run my-widget audit` fails with
`Undeclared resource spec 'audit' in model 'repro/widget'. Declared
resource specs: state`
- **After**: succeeds, writes audit data to the extension-declared
`audit` resource with correct schema, garbage collection, and tags
- `deno check`, `deno lint`, `deno fmt`, `deno run test`, `deno run
compile` all pass

Co-authored-by: Mark Jentz <jentz@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

v20260611.195256.0-sha.f625a295

Toggle v20260611.195256.0-sha.f625a295's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat: remote execution — orchestrator/worker fan-out, replacing execu…

…tion drivers (#535) (#1547)

## Summary

Implements remote execution per `design/remote-execution.md` (swamp
issue #535): a single orchestrator fans workflow steps out across
disposable **workers** — swamp binaries that dial home with a token,
enroll, and execute dispatched method bodies with every durable
capability proxied back to the orchestrator. Execution drivers
(`raw`/`docker`, `driver:`/`driverConfig:`) are removed; isolation is
now a worker deployment property selected with step placement.

### Control plane
- Symmetric RPC protocol (`rpc.*` frames) shared by orchestrator and
worker over the existing serve WebSocket; the legacy client protocol on
the same listener is unchanged.
- Worker gateway: enrollment (`<name>.<secret>` tokens, constant-time
compare, enroll-once with reconnect-for-lifetime), per-worker
reconnection grace windows, sliding data-plane session credentials, pool
snapshots for scheduling.
- Built-in models persisted as ordinary swamp data: `swamp/worker`,
`swamp/enrollment-token` (vault-stored plaintext, `unused → enrolled →
expired` + revocable), `swamp/step-lease` — all with bounded retention;
transitions serialized in the orchestrator process.

### Data plane
- Bearer-authenticated HTTP routes on the serve listener (h2 via ALPN
under TLS): immutable artifact reads with strong ETags, lease-scoped
writes through the existing data writers (declared-spec enforcement for
free), per-request-durable line appends, writer sessions, bundle +
co-located-asset fetch by content fingerprint.

### Worker runtime
- `swamp worker connect <url> --token …` — repo-less dial-home with
backoff reconnect.
- Remote `MethodContext` proxy adapters covering the full capability
inventory: reads/queries/vault/definitions/outputs over the control
socket, bytes over the data plane, spool-on-finalize `getFilePath`,
prefetched extension assets for synchronous `extensionFile()`, loud
`UnsupportedOnRemoteWorkerError` for sync members. Method author APIs
unchanged.
- Per-dispatch environment snapshot (identity denylist:
HOME/PATH/USER/…) applied and restored on every exit path; dispatches
execute serially per worker.

### Scheduling & workflow integration
- Step YAML gains `target:` / `labels:` / `platform:`; placed steps
dispatch at the execution seam while checks, reports, output records,
and follow-up actions stay at the orchestrator. `forEach` fans instances
out across matching workers.
- Direct target → labels → platform matching, deterministic tiebreak,
queue-when-busy, fail-fast when unschedulable; no-write drops
re-dispatch, write-then-drop fails the run.

### CLI
- `swamp worker token create|list|revoke`, `swamp worker list`, `swamp
worker connect` — log + json modes.

### Removal
- `ExecutionDriver`, the registry/resolution chain, docker driver +
runner, the driver extension kind, `--driver` flags, and
`driver`/`driverConfig` schema fields are gone; old YAML fails with an
actionable error. Bundling/fingerprinting machinery is retained (remote
dispatch ships it).

### CLI run-through-server
- `swamp workflow run`/`swamp model … method run` gain `--server <url>`:
repo-less dispatch through the serve WebSocket, streaming events through
the same renderers as a local run (lossless wire codec via
`deserializeEvent`), Ctrl-C cancels server-side, exit codes match local.
Additive terminal `done` protocol frame; direct-type-execution steps now
work over serve.

## Test plan
- [x] ~200 new unit tests across protocol, gateway, capability service,
data plane, dispatch service, scheduler, worker runtime, built-in
models, CLI
- [x] End-to-end integration test: real WebSocket enrollment through the
built-in token model against a real datastore + vault; dispatched method
exercising writes/appends/reads/vault round-trip/environment shipping;
lease lifecycle as queryable data; scheduling matrix; cancel
propagation; data-plane auth; bad-token rejection
- [x] `deno check`, `deno lint`, `deno fmt`, full `deno run test`, `deno
run compile`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

v20260611.191548.0-sha.f7ad0aff

Toggle v20260611.191548.0-sha.f7ad0aff's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(doctor): fix orphan cross-attribution for nested scoped extensions (

#628) (#1570)

## Summary

- Fix `extractTopLevelRoot()` to handle nested scoped extension names
with 3+
  segments (e.g. `@swamp/aws/iam`, `@swamp/aws/s3`)
- The function hardcoded a 2-segment assumption for scoped names,
causing
  sibling nested extensions to extract to the same root directory and
  cross-attribute each other's files as false orphans
- Add `extensionName` parameter so the function uses the actual segment
count
  to determine the correct per-extension root depth

Closes #628

## Test Plan

- [x] Unit tests for `extractTopLevelRoot` with 3-segment scoped names
- [x] Integration test verifying sibling nested extensions don't
cross-attribute
  orphans
- [x] All existing tests updated and passing
- [x] Reproduced the bug in a scratch repo
(`/tmp/swamp-repro-issue-628`) and
  verified the compiled binary reports 0 false orphans after the fix
- [x] `deno check`, `deno lint`, `deno fmt`, `deno run test` all pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: crudec <crudec@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

v20260611.191237.0-sha.88c2e772

Toggle v20260611.191237.0-sha.88c2e772's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix(doctor): fix orphan cross-attribution for nested scoped extensions (

#628) (#1570)

## Summary

- Fix `extractTopLevelRoot()` to handle nested scoped extension names
with 3+
  segments (e.g. `@swamp/aws/iam`, `@swamp/aws/s3`)
- The function hardcoded a 2-segment assumption for scoped names,
causing
  sibling nested extensions to extract to the same root directory and
  cross-attribute each other's files as false orphans
- Add `extensionName` parameter so the function uses the actual segment
count
  to determine the correct per-extension root depth

Closes #628

## Test Plan

- [x] Unit tests for `extractTopLevelRoot` with 3-segment scoped names
- [x] Integration test verifying sibling nested extensions don't
cross-attribute
  orphans
- [x] All existing tests updated and passing
- [x] Reproduced the bug in a scratch repo
(`/tmp/swamp-repro-issue-628`) and
  verified the compiled binary reports 0 false orphans after the fix
- [x] `deno check`, `deno lint`, `deno fmt`, `deno run test` all pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: crudec <crudec@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

v20260611.184910.0-sha.6472398a

Toggle v20260611.184910.0-sha.6472398a's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
feat(extensions): add --channel flag to yank and unyank commands (#1567)

## Summary

Adds `--channel <stable|beta|rc>` to `swamp extension yank` and `swamp
extension unyank` so maintainers can scope yank/unyank to a specific
release channel instead of affecting all channels at once.

- Without `--channel`: preserves today's all-channel behavior (backward
compatible)
- With `--channel stable`: yanks/unyanks only versions on the stable
channel, leaving beta/rc discoverable
- Channel validated using existing `ReleaseChannel.isValid()`
- Confirmation prompts and log/JSON output reflect the channel scope

Requires backend support from swamp-club/swamp-club#668.

Closes #626

## Test Plan

- [x] Updated unit tests for `extensionYank` and `extensionUnyank`
service functions
- [x] Added channel-scoped test cases verifying channel is threaded to
deps
- [x] Updated `ExtensionApiClient` tests — channel included in POST body
when provided, omitted when null
- [x] All 6906 tests pass (`deno run test`), type check, lint, format
clean
- [x] Binary compiles (`deno run compile`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Magistr <umag@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>