tx

tx claim

Claim a task with a lease to prevent parallel collisions

Purpose

tx claim marks a task as being actively worked on by a specific worker. This prevents multiple agents from picking the same task and duplicating work. Claims use a lease-based model with automatic expiry.

At A Glance

Lease Lifecycle

Rendering diagram…
Claims stay active until they are renewed, released, or allowed to expire.

Collision Block

Rendering diagram…
Claims close the race window after `tx ready` so only one worker keeps the task.

Claim a Task

tx claim <task-id> <worker-id> [options]

Arguments

ArgumentRequiredDescription
<task-id>YesTask ID (e.g., tx-a1b2c3d4)
<worker-id>YesWorker ID (e.g., worker-abc12345)

Options

OptionDescription
--lease <m>Lease duration in minutes (default: 30)
--jsonOutput as JSON
--helpShow help

Examples

# Claim with default 30-minute lease
tx claim tx-abc123 worker-def456

# Claim with 60-minute lease
tx claim tx-abc123 worker-def456 --lease 60

# JSON output
tx claim tx-abc123 worker-def456 --json
import { TxClient } from '@jamesaphoenix/tx-agent-sdk'

const tx = new TxClient({ apiUrl: 'http://localhost:3456' })

// Claim a task with a 60-minute lease
const claim = await tx.claims.claim('tx-abc123', 'worker-1', 60)
// Returns: { id, taskId, workerId, claimedAt, leaseExpiresAt, renewedCount, status }

console.log(`Claimed until ${claim.leaseExpiresAt}`)
{
  "tool": "tx_claim",
  "arguments": {
    "taskId": "tx-abc123",
    "workerId": "worker-1",
    "leaseDurationMinutes": 60
  }
}
# Claim a task with a 60-minute lease
curl -X POST http://localhost:3456/api/tasks/tx-abc123/claim \
  -H "Content-Type: application/json" \
  -d '{"workerId": "worker-1", "leaseDurationMinutes": 60}'

# Claim with default lease duration
curl -X POST http://localhost:3456/api/tasks/tx-abc123/claim \
  -H "Content-Type: application/json" \
  -d '{"workerId": "worker-1"}'

# Get the active claim for a task
curl http://localhost:3456/api/tasks/tx-abc123/claim

Release a Claim

Release a worker's claim on a task, allowing other workers to claim it.

tx claim release <task-id> <worker-id> [options]

Arguments

ArgumentRequiredDescription
<task-id>YesTask ID
<worker-id>YesWorker ID that holds the claim

Options

OptionDescription
--jsonOutput as JSON
--helpShow help

Examples

tx claim release tx-abc123 worker-def456
import { TxClient } from '@jamesaphoenix/tx-agent-sdk'

const tx = new TxClient({ apiUrl: 'http://localhost:3456' })

await tx.claims.release('tx-abc123', 'worker-1')
{
  "tool": "tx_claim_release",
  "arguments": {
    "taskId": "tx-abc123",
    "workerId": "worker-1"
  }
}
# Release a claim
curl -X DELETE http://localhost:3456/api/tasks/tx-abc123/claim \
  -H "Content-Type: application/json" \
  -d '{"workerId": "worker-1"}'

Renew a Claim

Extend the lease on an existing claim. Use this for long-running tasks to prevent the claim from expiring.

tx claim renew <task-id> <worker-id> [options]

Arguments

ArgumentRequiredDescription
<task-id>YesTask ID
<worker-id>YesWorker ID that holds the claim

Options

OptionDescription
--jsonOutput as JSON
--helpShow help

Limits

  • Maximum 10 renewals per claim
  • Fails if the lease has already expired
  • Fails if no active claim exists for this task and worker

Examples

tx claim renew tx-abc123 worker-def456
import { TxClient } from '@jamesaphoenix/tx-agent-sdk'

const tx = new TxClient({ apiUrl: 'http://localhost:3456' })

const renewed = await tx.claims.renew('tx-abc123', 'worker-1')
console.log(`New expiry: ${renewed.leaseExpiresAt}`)
console.log(`Renewals: ${renewed.renewedCount}/10`)
{
  "tool": "tx_claim_renew",
  "arguments": {
    "taskId": "tx-abc123",
    "workerId": "worker-1"
  }
}
# Renew a claim's lease
curl -X POST http://localhost:3456/api/tasks/tx-abc123/claim/renew \
  -H "Content-Type: application/json" \
  -d '{"workerId": "worker-1"}'

Atomic Ready + Claim

For parallel workers, use tx ready --claim to atomically fetch and claim a task in one step. This eliminates the race window between separate tx ready and tx claim calls.

# One command: find the best ready task AND claim it
tx ready --json --limit 1 --claim worker-1 --lease 30

This is the recommended approach for multi-worker setups. See tx ready for full details.

Use Case: Parallel Agent Execution

Without claims, parallel agents might pick the same task:

# Problem: Both agents pick the same task
Agent1: tx ready --limit 1 tx-abc123
Agent2: tx ready --limit 1 tx-abc123  # Same task!

With claims:

# Solution: Claims prevent collision
Agent1: tx claim tx-abc123 worker-1   # Success
Agent2: tx claim tx-abc123 worker-2   # Fails - already claimed
#!/bin/bash
# Use atomic ready+claim to avoid race conditions
WORKER_ID="worker-$$"

while true; do
  RESULT=$(tx ready --json --limit 1 --claim "$WORKER_ID" --lease 30)
  TASK=$(echo "$RESULT" | jq -r '.task.id // empty')
  [ -z "$TASK" ] && break

  claude "Your task is $TASK. Run 'tx show $TASK' for details."
  tx done "$TASK"
done

Two-Step Pattern (Legacy)

#!/bin/bash
WORKER_ID="worker-$$"

while true; do
  TASK=$(tx ready --json --limit 1 | jq -r '.[0].id // empty')
  [ -z "$TASK" ] && break

  # Try to claim - skip if another worker got it
  tx claim "$TASK" "$WORKER_ID" || continue

  # Work on the task
  claude "Your task is $TASK. Run 'tx show $TASK' for details."

  # Complete and release
  tx done "$TASK"
done

Behavior

  1. Claiming creates a lease with an expiry time
  2. Expired leases allow other workers to claim the task
  3. Completing a task (tx done) does not require releasing the claim first
  4. Long tasks should periodically renew with tx claim renew

On this page