- TypeScript 100%
- 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> |
||
|---|---|---|
| extensions/models | ||
| models/@keeb/swamp-club-lab/issues | ||
| vaults/local_encryption | ||
| .gitignore | ||
| .swamp.yaml | ||
| CLAUDE.md | ||
| LICENSE.txt | ||
| manifest.yaml | ||
| README.md | ||
@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_progressandshippedare admin verbs; authors may only move betweenopenandclosed. An invalid transition is a 422. assigneestakes user ids, not usernames — get them from theassigneesmethod.lifecycleis 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, lifecyclebody≤ 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.