Skip to main content
← Back to list
01Issue
FeatureIn ProgressSwamp CLIPublic
Assigneesstack72

Relationships

#4031 swamp inbox lists your Swamp Club inbox messages newest first, unread only by default, by date, kind and title, with no reading and no read-state changes yet

Opened by stack72 · 10/27/2026

Summary

Add swamp inbox, which lists the signed-in user's Swamp Club inbox messages: newest first, unread only by default. It shows each message's date, kind and title, and nothing else. Reading is not part of this. The command shows no message body, has no swamp inbox read, and never marks anything read. Its job for now is to show that the inbox exists and what is in it.

This builds on:

  • swamp-club#3990: the contract in design/surfaces/inbox.md and SwampClubClient.listInboxMessages
  • swamp-club#4001: the Swamp Club endpoints, now live

It replaces the listing half of the older swamp-club#2024, which targeted /api/v1/notifications. Build from this issue, not that one.

Behaviour

swamp inbox works outside a swamp repo and is gated, like swamp subscription status. It makes one live call to GET /api/inbox/messages.

Invocation Lists
swamp inbox Unread messages, newest first (status=unread)
swamp inbox --all Read and unread (status=all)
swamp inbox --limit 10 At most 10 (1 to 100; default 20)
swamp inbox --before <id> The page older than message <id>

Log mode:

●  2026-10-26  announcement  swamp 1.42 is out
●  2026-10-25  issue_update  Your issue #3990 shipped
   2026-10-24  points        You earned 50 points

2 unread of 3 shown.
To see older:  swamp inbox --all --before 01JBX5Q8ZK00000000000000ZP
  • ● marks an unread message. Dates are the local calendar date of createdAt. The kind column is padded to its widest value.
  • The To see older: line appears only when nextCursor is not null, and it repeats --all when that was given.
  • With nothing to show:
    • No unread messages. To include read ones: swamp inbox --all
    • with --all: Your inbox is empty.
  • When the page reports dropped > 0, print a warning on stderr: 1 message from Swamp Club did not match the inbox format and was left out. A server drifting from the contract then shows up instead of losing messages silently.

JSON mode prints one document on stdout:

{
  "status": "unread",
  "messages": [
    { "id": "01JBX5Q8ZK0000000000000104", "kind": "announcement", "title": "swamp 1.42 is out",
      "createdAt": "2026-10-26T09:00:00.000Z", "readAt": null }
  ],
  "nextCursor": null,
  "dropped": 0
}

body, link and action are left out of both modes on purpose. They are the reading part, and they arrive with swamp inbox read. Leaving them out also keeps text Swamp Club wrote, other than the title, out of an agent's context.

Errors

The client's existing UserErrors are shown as they are:

  • not signed in: notAuthenticated(), as subscription status shows it
  • a collective API key: "The inbox needs a personal API key; collective keys have no inbox."
  • a server without the inbox: "This Swamp Club server has no inbox."
  • --limit outside 1 to 100, or a --before that is not a ULID: refused before any network call

The server URL is SWAMP_CLUB_URL, else the stored credential's server, as for subscription status.

Design

  • src/libswamp/inbox/list.ts: an inboxList(ctx, deps, input) generator. It yields loading_credentials, then contacting_server, then completed with the page reduced to the fields above, or error. Its deps are { loadCredentials, listMessages(serverUrl, apiKey, options, signal) }. Pass ctx.signal to the client. Export it and its event type from src/libswamp/mod.ts.
  • src/presentation/renderers/inbox_list.ts: createInboxListRenderer(mode), with log and JSON. Use the To …: call-to-action style from the workflow renderer.
  • src/cli/commands/inbox.ts: the command, with the action on the inbox command itself, so swamp inbox read can be added later as a subcommand without changing how swamp inbox behaves. Options: --all, --limit <n:integer>, --before <id:string>.
  • src/cli/mod.ts: register .command("inbox", inboxCommand) beside subscription, and add "inbox" to NON_REPO_COMMANDS.
  • Leave the inbox cache (InboxCacheFileRepository) alone. Updating it belongs to the read and wiring PRs.
  • Don't change the skill. Its rule 4 already covers the notice, and swamp help makes the command discoverable.

Tests

  • src/libswamp/inbox/list_test.ts, using messagesPage from inbox_responses.fixture.json:
    • the default sends status=unread and limit 20
    • --all, --limit and --before are passed through
    • fields are reduced, with no body, link or action
    • dropped and nextCursor are passed through
    • notAuthenticated when there is no key
    • a client UserError passes through
    • ctx.signal is used
    • refused input makes no call
  • src/presentation/renderers/inbox_list_test.ts:
    • log: rows, the unread marker, kind padding, the count line, To see older: with and without --all, both empty states, the dropped warning on stderr
    • JSON: the exact document
  • src/cli/mod_test.ts: inbox is repo-less.
  • src/cli/auth_gate_exemptions_test.ts: pin ["inbox"] as gated.
  • integration/json_mode_conformance_test.ts and cli_help_wording_test.ts pick the command up from mod.ts. Run all of integration/ before verifying.

Do one live check with the compiled binary against swamp-club.com: a staff send to yourself through #4001, then swamp inbox, swamp inbox --all --json, and swamp inbox with a collective key. Record the output in the PR.

Out of scope

  • swamp inbox read, message bodies, links and actions, and marking messages read
  • The background poll and the post-command notice
  • Manual pages (filed separately once reading ships)
02Bog Flow
✓OPEN✓TRIAGED◉IN PROGRESS○SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 4 MOREVERIFICATION_PASSED

In Progress

10/27/2026, 6:18:44 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/27/2026, 5:58:46 PM

Sign in to post a ripple.