feat(mail): implement beads-native gt mail claim command

Implement claiming for queue messages using beads-native approach:

- Add claim_pattern field to QueueFields for eligibility checking
- Add MatchClaimPattern function for pattern matching (wildcards supported)
- Add FindEligibleQueues to find all queues an agent can claim from
- Rewrite runMailClaim to use beads-native queue lookup
- Support optional queue argument (claim from any eligible if not specified)
- Use claimed-by/claimed-at labels instead of changing assignee
- Update runMailRelease to work with new claiming approach
- Add comprehensive tests for pattern matching and validation

Queue messages are now claimed via labels:
  - claimed-by: <agent-identity>
  - claimed-at: <RFC3339 timestamp>

Messages with queue:<name> label but no claimed-by are unclaimed.

Closes gt-xfqh1e.11

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gastown/crew/jack
2026-01-14 21:24:57 -08:00
committed by Steve Yegge
parent 012d50b2b2
commit 2ffc8e8712
5 changed files with 592 additions and 267 deletions

View File

@@ -277,27 +277,27 @@ Examples:
}
var mailClaimCmd = &cobra.Command{
Use: "claim <queue-name>",
Use: "claim [queue-name]",
Short: "Claim a message from a queue",
Long: `Claim the oldest unclaimed message from a work queue.
SYNTAX:
gt mail claim <queue-name>
gt mail claim [queue-name]
BEHAVIOR:
1. List unclaimed messages in the queue
2. Pick the oldest unclaimed message
3. Set assignee to caller identity
4. Set status to in_progress
5. Print claimed message details
1. If queue specified, claim from that queue
2. If no queue specified, claim from any eligible queue
3. Add claimed-by and claimed-at labels to the message
4. Print claimed message details
ELIGIBILITY:
The caller must match a pattern in the queue's workers list
(defined in ~/gt/config/messaging.json).
The caller must match the queue's claim_pattern (stored in the queue bead).
Pattern examples: "*" (anyone), "gastown/polecats/*" (specific rig crew).
Examples:
gt mail claim work/gastown # Claim from gastown work queue`,
Args: cobra.ExactArgs(1),
gt mail claim work-requests # Claim from specific queue
gt mail claim # Claim from any eligible queue`,
Args: cobra.MaximumNArgs(1),
RunE: runMailClaim,
}
@@ -311,14 +311,14 @@ SYNTAX:
BEHAVIOR:
1. Find the message by ID
2. Verify caller is the one who claimed it (assignee matches)
3. Set assignee back to queue:<name> (from message labels)
4. Set status back to open
5. Message returns to queue for others to claim
2. Verify caller is the one who claimed it (claimed-by label matches)
3. Remove claimed-by and claimed-at labels
4. Message returns to queue for others to claim
ERROR CASES:
- Message not found
- Message not claimed (still assigned to queue)
- Message is not a queue message
- Message not claimed
- Caller did not claim this message
Examples: