swamp extension: the swamp-club Lab over its JSON API (@keeb/swamp-club-lab)
  • TypeScript 100%
Find a file
keeb 1a7a0b0786 Declare Lab response schemas, retry rate limits, 2026.11.04.1
- Declare event, lifecycle entry, relationship, search query and
  assignee schemas instead of empty passthrough objects, so CEL
  expressions validate against them. Shapes follow swamp-club's
  /api/v1/lab routes and were checked against live data.
- Lifecycle entry body may be null, as the Lab stores it.
- Accept the duplicate_of relationship type the server allows.
- search records `truncated` when more issues match than the page.
- Retry 429 (any method) and 503 (GET only) honoring Retry-After.
- delete of an already-gone issue succeeds and clears the record.
- Drop rendered bodyHtml from lifecycle entries as from ripples.
- Move tests beside the model as issues_test.ts; cover every
  resource-writing method against its schema (24 tests).
- Declare license: MIT and the GitHub repository; no-op upgrade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:26:01 -08:00
extensions/models Declare Lab response schemas, retry rate limits, 2026.11.04.1 2026-11-04 10:26:01 -08:00
models/@keeb/swamp-club-lab/issues Declare Lab response schemas, retry rate limits, 2026.11.04.1 2026-11-04 10:26:01 -08:00
vaults/local_encryption Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00
.gitignore Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00
.swamp.yaml Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00
CLAUDE.md Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00
LICENSE.txt Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00
manifest.yaml Declare Lab response schemas, retry rate limits, 2026.11.04.1 2026-11-04 10:26:01 -08:00
README.md Add @keeb/swamp-club-lab extension (2026.09.26.1) 2026-11-04 08:35:25 -08:00

@keeb/swamp-club-lab

The swamp-club Lab — issues, ripples, relationships and the triage trail — driven through its /api/v1/lab JSON API with a personal API key.

swamp issue get shows an issue's body and a ripple count. This extension reads the ripple bodies, the event history, lifecycle entries and relationships, and scripts the writes the CLI does not surface.

Model

Model Method What it does
@keeb/swamp-club-lab/issues get One or more issues with full ripples, events, lifecycle, links
search Search/list issues by text, type, status, source, author
create File an issue
update Patch title/body/status (author) or anything (admin)
delete Hard delete with cascade — admin, requires confirm: true
ripple Post a ripple (comment)
editRipple Replace a ripple's body — author or admin
deleteRipple Delete a ripple — author or admin
relationships An issue's links, marked incoming/outgoing, with their ids
relate Add parent_of / blocked_by / related_to links, fanned out
unrelate Remove one link by id
lifecycle Append a triage-trail entry — admin
assignees Operatives eligible for assignment, with user ids — admin

Setup

Use a personal key (swamp_…). Collective swamp_org_… tokens set a collective context, not a user session, and cannot read issues.

swamp vault create local_encryption lab
jq -r .apiKey ~/.config/swamp/auth.json | swamp vault put lab API_KEY

swamp model create @keeb/swamp-club-lab/issues lab
# then set globalArguments.apiKey: ${{ vault.get(lab, API_KEY) }}

serverUrl defaults to https://swamp-club.com. It must be the canonical host: https://swamp.club 301s there, and a followed 301 turns a POST into a bodiless GET that lands on an HTML page — a write that reports success and changes nothing. The client refuses every redirect and names the fix instead, and checks each response against the exact status that call should return.

Examples

# read ripple bodies
swamp model method run lab get --input '{"numbers":[847]}'
swamp data get lab issue-847 --json | jq -r '.content.comments[] | "--- @\(.authorUsername)\n\(.body)\n"'

# search
swamp model method run lab search --input '{"q":"scoring","status":"triaged","limit":20}'

# ripple
swamp model method run lab ripple --input '{"number":847,"body":"See also #850."}'

# wire an epic in one run
swamp model method run lab relate --input '{"number":847,"links":[
  {"type":"parent_of","targetIssueNumber":853},
  {"type":"parent_of","targetIssueNumber":854}]}'

Data instances are issue-<n>, ripple-<id>, relationships-<n>, lifecycle-<n>-<step>, assignees, and search (or the name you pass).

Behaviour worth knowing

  • 404 means "not found or not visible". The Lab collapses the two on purpose; a hidden issue is indistinguishable from a missing one.
  • Status changes are transitions. triaged, in_progress and shipped are admin verbs; authors may only move between open and closed. An invalid transition is a 422.
  • assignees takes user ids, not usernames — get them from the assignees method.
  • lifecycle is the structured triage trail, not a comment channel. Only append to it when deliberately driving an issue's lifecycle.
  • Limits: title ≤ 256, body and ripple ≤ 65,536, search q ≤ 200, lifecycle body ≤ 100,000. Ripples and issue bodies are profanity-checked; a 422 names the flagged words.

Not covered: the admin SSE feed GET /api/v1/lab/stream — a live stream is not a method run.