Session consumer claims
WednesdayAI gives plugins a durable, at-least-once work queue over ended sessions: each finished session is materialized as claim rows per registered consumer, and your plugin pulls, leases, and acks them through the SDK. This replaces polling the session store or hooking the volatilesession_end event (an in-process subscriber absent at emit time silently misses the session forever).
The pieces:
- Manifest — declare
sessionConsumersinopenclaw.plugin.json. - SDK —
api.claimSessionWork(opts)/api.ackSessionWork(claimId, result)/ optionalapi.onSessionWorkAvailable({ effectKind }). - Diagnostics —
session_consumer_claimevents surface DLQ, backstop, and skipped-backlog decisions.
src/plugins/manifest.ts (SessionConsumerDeclaration) and src/plugins/types.ts (ClaimedSessionWork, SessionWorkResult), re-exported from openclaw/plugin-sdk. Design decisions: ADR 0041 (claim ledger) and ADR 0062 (seam carries sessionKey + outcome).
Manifest declaration
Your
consumerId is loader-bound — ${manifestId}:${effectKind}[/<subCursor>] — and never caller-supplied. A plugin cannot claim work as another plugin, and unauthorized items (outside your manifest’s scopes/lanes) are skipped before they reach you.
Claiming and acking work
claimSessionWork(opts?) options: { subCursor?, laneId?, limit?, leaseMs?, effectKind? }. It returns null when no durable claims store is wired (fs-jsonl without the degraded store) or no work is available.
The claim payload (ClaimedSessionWork):
ackSessionWork(claimId, result) takes { kind: "processed" } or { kind: "failed", error, retryable }. After maxAttempts (default 5) retryable failures the claim dead-letters (dlq_terminal event).
Async safety
claimSessionWork/ackSessionWork are async storage calls — never call them inside synchronous hook bodies without handling the promise. Claims hold leases (default 30 s): a claim you hold but neither ack nor release blocks re-offer until the lease expires. Batch small: claim → process → ack before claiming again, as in the pump above. Do not hold claims across user-facing request paths.
What not to do:
Diagnostics events
Emitting fromsrc/infra/diagnostic-events.ts, type session_consumer_claim:
backstop_released means a session your consumer never finished was pruned anyway.
Operator-facing behaviour
DeclaringsessionConsumers makes pruning obligation-gated for your lanes: sessions you have not consumed are pinned (bounded by a 30-day backstop). Document this for operators in your plugin README, and point them at Session consumer claims (admin).
Related
- Session consumer claims (admin) — config keys, defaults, prune interaction
- Session store — reading session data
- Plugin manifest — required fields and validation