tx

Agent SDK

TypeScript SDK for building custom agents with tx task management

API Server Required

The Agent SDK connects to tx via the REST API server. You must start the API server before using the SDK:

tx serve
# Server running at http://localhost:3456

Alternatively, use direct mode with dbPath to skip the API server entirely (requires @jamesaphoenix/tx-core and effect as dependencies).

Installation

npm install @jamesaphoenix/tx-agent-sdk

Or with your preferred package manager:

# pnpm
pnpm add @jamesaphoenix/tx-agent-sdk

# yarn
yarn add @jamesaphoenix/tx-agent-sdk

# bun
bun add @jamesaphoenix/tx-agent-sdk

Quick Start

import { TxClient } from "@jamesaphoenix/tx-agent-sdk"

// HTTP mode (connects to tx API server)
const tx = new TxClient({ apiUrl: "http://localhost:3456" })

// Get the next ready task
const ready = await tx.tasks.ready({ limit: 1 })
if (ready.length === 0) {
  console.log("No tasks ready")
  process.exit(0)
}

const task = ready[0]
console.log(`Working on: ${task.title}`)

// Get context (relevant learnings for this task)
const ctx = await tx.context.forTask(task.id)
for (const l of ctx.learnings) {
  console.log(`- ${l.content}`)
}

// ... do the work ...

// Mark complete and see what was unblocked
const { nowReady } = await tx.tasks.done(task.id)
console.log(`Unblocked ${nowReady.length} tasks`)

// Record what you learned
await tx.learnings.add({
  content: "Use retry logic for flaky network calls",
  category: "best-practices",
})

Connection Modes

The SDK supports two transport modes:

ModeConfigRequiresBest For
HTTPapiUrlRunning tx serveRemote agents, distributed systems
DirectdbPath@jamesaphoenix/tx-core + effectLocal agents, single-machine setups
// HTTP mode
const tx = new TxClient({ apiUrl: "http://localhost:3456" })

// Direct SQLite mode (no server needed)
const tx = new TxClient({ dbPath: ".tx/tasks.db" })

// With authentication
const tx = new TxClient({
  apiUrl: "http://localhost:3456",
  apiKey: process.env.TX_API_KEY,
  timeout: 60000, // 60 second timeout
})

When both apiUrl and dbPath are provided, direct mode takes precedence. Direct mode requires @jamesaphoenix/tx-core and effect as installed dependencies.

HTTP Actor Header

In HTTP mode, TxClient sends x-tx-actor: agent by default. The dashboard sends x-tx-actor: human for interactive task changes. If you call the REST API directly as a human, send x-tx-actor: human on task update and completion requests.

curl -X POST http://localhost:3456/api/tasks/tx-abc123/done \
  -H "x-tx-actor: human"

If your orchestration loop uses tx gate with a linked taskId, keep that review task human-owned. Let the agent stop at the gate, then have the human approve the gate and close the linked task via tx done <id> --human or a REST call with x-tx-actor: human. See tx gate for the full loop recipes.

API Reference

Tasks

tx.tasks.ready(options?)

Get tasks that are ready to be worked on (all blockers completed). Returns tasks sorted by priority score (descending).

const ready = await tx.tasks.ready({ limit: 5 })

if (ready.length > 0) {
  console.log(`Next task: ${ready[0].title}`)
}

Options:

OptionTypeDefaultDescription
limitnumber100Maximum number of tasks to return
labelsstring[]-Only include tasks with these labels
excludeLabelsstring[]-Exclude tasks with these labels
tx ready --limit 5 --json
{
  "tool": "tx_ready",
  "arguments": {
    "limit": 5
  }
}
curl http://localhost:3456/api/tasks/ready?limit=5

tx.tasks.done(id)

Mark a task as done. Returns the completed task and an array of tasks that became ready as a result.

const { task, nowReady } = await tx.tasks.done("tx-abc123")
console.log(`Completed: ${task.title}`)
console.log(`Unblocked ${nowReady.length} tasks`)
tx done tx-abc123
{
  "tool": "tx_done",
  "arguments": {
    "taskId": "tx-abc123"
  }
}
curl -X POST http://localhost:3456/api/tasks/tx-abc123/done \
  -H "x-tx-actor: human"

tx.tasks.create(data)

Create a new task.

const task = await tx.tasks.create({
  title: "Implement auth",
  description: "Add JWT-based authentication",
  score: 100,
  metadata: { component: "auth" },
})

Parameters:

FieldTypeRequiredDescription
titlestringYesTask title
descriptionstringNoDetailed description
parentIdstringNoParent task ID for hierarchy
scorenumberNoPriority score (higher = more urgent)
metadataRecord<string, unknown>NoArbitrary key-value metadata
tx add "Implement auth" --score 100
{
  "tool": "tx_add",
  "arguments": {
    "title": "Implement auth",
    "description": "Add JWT-based authentication",
    "score": 100
  }
}
curl -X POST http://localhost:3456/api/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Implement auth", "description": "Add JWT-based authentication", "score": 100}'

tx.tasks.get(id)

Get a task by ID, including full dependency information.

const task = await tx.tasks.get("tx-abc123")
console.log(task.title, task.isReady)
console.log(`Blocked by: ${task.blockedBy.join(", ")}`)
console.log(`Blocks: ${task.blocks.join(", ")}`)
console.log(`Direct group context: ${task.groupContext ?? "(none)"}`)
console.log(`Effective group context: ${task.effectiveGroupContext ?? "(none)"}`)

tx.tasks.update(id, data)

Update a task's fields. Only provided fields are changed.

await tx.tasks.update("tx-abc123", {
  status: "active",
  score: 200,
})

tx.tasks.setGroupContext(id, context)

Set direct task-group context on a task. Related ancestors/descendants inherit it through effectiveGroupContext.

await tx.tasks.setGroupContext("tx-root001", "Shared auth rollout context")

tx.tasks.clearGroupContext(id)

Clear direct task-group context from a task.

await tx.tasks.clearGroupContext("tx-root001")

tx.tasks.delete(id, options?)

Delete a task. Fails if the task has children unless cascade: true is set.

// Delete a single task
await tx.tasks.delete("tx-abc123")

// Delete task and all descendants
await tx.tasks.delete("tx-abc123", { cascade: true })

tx.tasks.list(options?)

List tasks with pagination and filtering.

// List all tasks
const all = await tx.tasks.list()

// Filter by status
const active = await tx.tasks.list({ status: "active" })

// Multiple statuses
const working = await tx.tasks.list({ status: ["active", "planning"] })

// Full-text search
const results = await tx.tasks.list({ search: "auth" })

// Paginate
const page1 = await tx.tasks.list({ limit: 10 })
if (page1.hasMore) {
  const page2 = await tx.tasks.list({ limit: 10, cursor: page1.nextCursor! })
}

Options:

OptionTypeDefaultDescription
cursorstring-Pagination cursor from nextCursor
limitnumber20Maximum tasks to return
statusTaskStatus | TaskStatus[]-Filter by status
searchstring-Full-text search across title and description

tx.tasks.block(id, blockerId)

Add a blocker dependency. Circular dependencies are rejected.

// "deploy" can't start until "build" is done
await tx.tasks.block("tx-deploy", "tx-build")

tx.tasks.unblock(id, blockerId)

Remove a blocker dependency.

await tx.tasks.unblock("tx-deploy", "tx-build")

tx.tasks.tree(id)

Get a task and all its descendants as a flat array.

const tree = await tx.tasks.tree("tx-root")
console.log(`${tree.length} tasks in tree`)

Learnings

Unified Memory Primitive

The tx.learnings.* and tx.context.* SDK methods map to the unified tx memory primitive. The SDK API names are unchanged for backwards compatibility, but the underlying functionality is part of the memory system. Use tx memory add with -t learning tags at the CLI level for the equivalent workflow.

tx.learnings.search(options?)

Search learnings using BM25 text search. Returns results with relevance scores.

// Search by keyword
const results = await tx.learnings.search({ query: "authentication" })

// Get recent learnings (no query)
const recent = await tx.learnings.search({ limit: 5 })

// Filter by category
const practices = await tx.learnings.search({
  query: "error handling",
  category: "best-practices",
})

Options:

OptionTypeDefaultDescription
querystring-Search query (omit for recent)
limitnumber10Maximum results
minScorenumber-Minimum relevance score (0-1)
categorystring-Filter by category
tx memory search "authentication"
{
  "tool": "tx_learning_search",
  "arguments": {
    "query": "authentication",
    "limit": 10
  }
}
curl "http://localhost:3456/api/learnings?query=authentication&limit=10"

tx.learnings.add(data)

Create a new learning to persist knowledge for future agents.

await tx.learnings.add({
  content: "Use bcrypt for password hashing, not SHA256",
  sourceType: "manual",
  sourceRef: "tx-abc123",
  category: "security",
  keywords: ["passwords", "hashing", "bcrypt"],
})

Parameters:

FieldTypeRequiredDescription
contentstringYesThe learning content
sourceTypestringNo'manual', 'run', 'compaction', or 'claude_md'
sourceRefstringNoReference to the source (e.g. task ID)
categorystringNoCategory for filtering
keywordsstring[]NoKeywords for search indexing
tx memory add "Use bcrypt for password hashing, not SHA256"
{
  "tool": "tx_learning_add",
  "arguments": {
    "content": "Use bcrypt for password hashing, not SHA256",
    "category": "security"
  }
}
curl -X POST http://localhost:3456/api/learnings \
  -H "Content-Type: application/json" \
  -d '{"content": "Use bcrypt for password hashing, not SHA256", "category": "security"}'

tx.learnings.get(id)

Get a learning by its numeric ID.

const learning = await tx.learnings.get(42)
console.log(learning.content)

tx.learnings.helpful(id, score?)

Record that a learning was helpful, boosting its outcome score. Higher outcome scores cause learnings to rank higher in future searches.

await tx.learnings.helpful(42)
await tx.learnings.helpful(42, 0.8) // partial helpfulness

Context

tx.context.forTask(taskId)

Get contextual learnings for a task. Uses the task's title and description to find relevant learnings. This is the primary mechanism for injecting memory into agent prompts.

const ctx = await tx.context.forTask("tx-abc123")
console.log(`Found ${ctx.learnings.length} relevant learnings`)

for (const l of ctx.learnings) {
  console.log(`- [${(l.relevanceScore * 100).toFixed(0)}%] ${l.content}`)
}

Returns SerializedContextResult:

FieldTypeDescription
taskIdstringThe task ID queried
taskTitlestringThe task's title
learningsSerializedLearningWithScore[]Relevant learnings with scores
searchQuerystringThe generated search query
searchDurationnumberSearch time in milliseconds
tx memory context tx-abc123
{
  "tool": "tx_context",
  "arguments": {
    "taskId": "tx-abc123"
  }
}
curl http://localhost:3456/api/context/tx-abc123

Runs

Run-level heartbeat primitives for orchestration loops and watchdogs.

tx.runs.list(options?)

List recent runs with filtering and cursor pagination.

const recent = await tx.runs.list({
  limit: 20,
  status: ["failed", "running"],
})

tx.runs.get(runId)

Get a run with parsed transcript messages and captured stdout/stderr logs.

const detail = await tx.runs.get("run-abc12345")
console.log(detail.run.status)
console.log(detail.messages.length)

tx.runs.transcript(runId)

Get parsed transcript entries for a run.

const messages = await tx.runs.transcript("run-abc12345")
const toolCalls = messages.filter((message) => message.type === "tool_use")

tx.runs.stderr(runId, options?)

Read stderr for a run, optionally tailing the last N lines.

const stderr = await tx.runs.stderr("run-abc12345", { tail: 50 })
console.log(stderr.content)

tx.runs.errors(options?)

Aggregate recent run errors, span errors, and error events.

const errors = await tx.runs.errors({ hours: 24, limit: 10 })

tx.runs.heartbeat(runId, data?)

Record transcript/log progress for a running run.

await tx.runs.heartbeat("run-abc12345", {
  transcriptBytes: 2048,
  deltaBytes: 256,
})

tx.runs.stalled(options?)

List currently running runs that appear stalled.

const stalled = await tx.runs.stalled({
  transcriptIdleSeconds: 300,
  heartbeatLagSeconds: 180,
})

tx.runs.reap(options?)

Reap stalled runs by cancelling the run and optionally resetting task status.

const reaped = await tx.runs.reap({
  transcriptIdleSeconds: 300,
  dryRun: false,
})

Spec

Spec traceability primitives bridge docs, tests, and FCI.

tx.spec.discover(options?)

Refresh doc-derived rules from docs and discover mappings from tags, comments, and manifest entries.

const discover = await tx.spec.discover({
  doc: "PRD-033-spec-test-traceability",
})

tx.spec.link(invariantId, file, name?, framework?)

Create or upsert a manual invariant-to-test mapping.

await tx.spec.link(
  "INV-EARS-FL-001",
  "test/integration/flow.test.ts",
  "flow stays unblocked",
  "vitest"
)

tx.spec.status(options?)

Get current closure state, including phase, FCI, coverage counts, and blocker reasons.

const status = await tx.spec.status({
  doc: "PRD-033-spec-test-traceability",
})

tx.spec.matrix(options?)

Get the invariant-to-test traceability matrix with latest run outcomes.

const matrix = await tx.spec.matrix({
  doc: "PRD-033-spec-test-traceability",
})

tx.spec.run(testId, passed, options?)

Record a single test outcome.

await tx.spec.run(
  "test/integration/flow.test.ts::flow stays unblocked",
  true,
  { durationMs: 42 }
)

tx.spec.batch(data)

Ingest framework-native batch output or pre-parsed result rows.

await tx.spec.batch({
  from: "junit",
  raw: "<testsuites>...</testsuites>",
})

tx.spec.complete(options)

Human sign-off for a HARDEN scope.

await tx.spec.complete({
  doc: "PRD-033-spec-test-traceability",
  signedOffBy: "james",
})

File Learnings

tx.fileLearnings.list(path?)

List all file learnings, optionally filtering by file path.

// List all
const all = await tx.fileLearnings.list()

// Filter by path
const forFile = await tx.fileLearnings.list("src/auth.ts")

tx.fileLearnings.recall(path)

Recall file learnings matching a specific file path. Use this before working on a file to retrieve attached notes.

const notes = await tx.fileLearnings.recall("src/auth.ts")
for (const note of notes) {
  console.log(`${note.filePattern}: ${note.note}`)
}

tx.fileLearnings.add(data)

Associate a note with a file pattern.

await tx.fileLearnings.add({
  filePattern: "src/auth.ts",
  note: "JWT tokens expire after 1 hour, refresh logic is in middleware",
  taskId: "tx-abc123",
})

Messages

Inter-agent communication via channel-based messaging.

tx.messages.send(data)

Send a message to a channel.

await tx.messages.send({
  channel: "worker-1",
  content: "Task tx-abc123 is ready for review",
  sender: "orchestrator",
  ttlSeconds: 3600,
  correlationId: "req-001",
})

Parameters:

FieldTypeRequiredDescription
channelstringYesChannel name
contentstringYesMessage content
senderstringNoSender name (default: 'sdk')
taskIdstringNoAssociated task ID
ttlSecondsnumberNoTime-to-live in seconds
correlationIdstringNoFor request/reply patterns
metadataRecord<string, unknown>NoArbitrary metadata

tx.messages.inbox(channel, options?)

Read messages from a channel inbox.

const msgs = await tx.messages.inbox("agent-1", { limit: 10 })
const fromOrch = await tx.messages.inbox("agent-1", { sender: "orchestrator" })

Options:

OptionTypeDefaultDescription
afterIdnumber-Cursor: only messages with ID > this value
limitnumber-Maximum messages to return
senderstring-Filter by sender
correlationIdstring-Filter by correlation ID
includeAckedbooleanfalseInclude acknowledged messages

tx.messages.ack(id)

Acknowledge a single message.

await tx.messages.ack(42)

tx.messages.ackAll(channel)

Acknowledge all pending messages on a channel.

const { ackedCount } = await tx.messages.ackAll("agent-1")

tx.messages.pending(channel)

Get count of pending (unacknowledged) messages.

const count = await tx.messages.pending("agent-1")

tx.messages.gc(options?)

Garbage collect expired and old acknowledged messages.

const { expired, acked } = await tx.messages.gc({ ackedOlderThanHours: 24 })

Claims

Lease-based task claiming for worker coordination.

tx.claims.claim(taskId, workerId, leaseDurationMinutes?)

Claim a task with an exclusive lease.

const claim = await tx.claims.claim("tx-abc123", "worker-1", 30)
console.log(`Lease expires at ${claim.leaseExpiresAt}`)

tx.claims.release(taskId, workerId)

Release a claim on a task.

await tx.claims.release("tx-abc123", "worker-1")

tx.claims.renew(taskId, workerId)

Renew an existing claim's lease.

const renewed = await tx.claims.renew("tx-abc123", "worker-1")
console.log(`New expiry: ${renewed.leaseExpiresAt}`)

tx.claims.getActive(taskId)

Get the active claim for a task, or null if unclaimed.

const claim = await tx.claims.getActive("tx-abc123")
if (claim) {
  console.log(`Claimed by ${claim.workerId}`)
}

Guards

tx.guards.set(options)

Set task creation limits (bounded autonomy).

await tx.guards.set({
  maxPending: 50,
  maxChildren: 10,
  maxDepth: 4,
  enforce: true,
})

Options:

OptionTypeDescription
scopestringGuard scope: 'global' (default) or 'parent:<task-id>'
maxPendingnumberMaximum non-done tasks
maxChildrennumberMaximum direct children per parent
maxDepthnumberMaximum hierarchy nesting depth
enforcebooleantrue = hard block, false = advisory warnings

tx.guards.show()

List all configured guards.

const guards = await tx.guards.show()
for (const g of guards) {
  console.log(`${g.scope}: maxPending=${g.maxPending}, enforce=${g.enforce}`)
}

tx.guards.check(options?)

Check if task creation would pass guard limits without actually creating a task.

const result = await tx.guards.check({ parentId: 'tx-abc123' })
if (!result.passed) {
  console.log('Warnings:', result.warnings)
}

tx.guards.clear(scope?)

Clear guards. Omit scope to clear all.

await tx.guards.clear()               // clear all
await tx.guards.clear('global')       // clear global only
await tx.guards.clear('parent:tx-abc123')  // clear specific parent scope

Verify

tx.verify.set(taskId, cmd, schema?)

Attach a verification command to a task.

await tx.verify.set('tx-abc123', 'bun run test:auth')

// With structured output schema
await tx.verify.set('tx-abc123', 'bun run test:json', 'verify-schema.json')

tx.verify.show(taskId)

Show the verification command attached to a task.

const info = await tx.verify.show('tx-abc123')
// { cmd: 'bun run test:auth', schema: null }

tx.verify.run(taskId, options?)

Run the verification command. Returns structured result with exit code, stdout, stderr, and timing.

const result = await tx.verify.run('tx-abc123')
// { taskId: 'tx-abc123', exitCode: 0, passed: true, stdout: '...', stderr: '', durationMs: 1234 }

// With timeout
const result = await tx.verify.run('tx-abc123', { timeout: 60 })

tx.verify.clear(taskId)

Remove the verification command from a task.

await tx.verify.clear('tx-abc123')

Reflect

tx.reflect.run(options?)

Run a session retrospective. Returns structured metrics, signals, and optionally LLM analysis.

// Data tier (no LLM, instant)
const result = await tx.reflect.run({ sessions: 5 })
console.log(result.throughput)    // { created: 20, completed: 8, net: 12, completionRate: 0.4 }
console.log(result.signals)       // [{ type: 'HIGH_PROLIFERATION', ... }]
console.log(result.stuckTasks)    // [{ id: 'tx-abc123', title: '...', attempts: 4 }]

// Enable analysis when an LLM backend is available
const analyzed = await tx.reflect.run({ sessions: 5, analyze: true })
console.log(analyzed.analysis)    // "Proliferation driven by..."

analyze: true uses Claude Agent SDK when it is available. If not, tx falls back to ANTHROPIC_API_KEY. Without either backend, you still get the structured data tier.

Options:

OptionTypeDefaultDescription
sessionsnumber10Number of recent sessions to analyze
hoursnumber-Time window in hours
analyzebooleanfalseEnable LLM analysis

Returns SerializedReflectResult:

FieldTypeDescription
sessionsobjectSession counts (total, completed, failed, timeout, avgDurationMinutes)
throughputobjectTask throughput (created, completed, net, completionRate)
proliferationobjectProliferation metrics (avgCreatedPerSession, maxCreatedPerSession, maxDepth, orphanChains)
stuckTasksarrayTasks with 3+ failed attempts
signalsarrayMachine-readable signals (type, message, severity)
analysisstring?LLM analysis (when analyze: true)

Error Handling

The SDK uses TxError for all errors, with typed error codes:

import { TxError } from "@jamesaphoenix/tx-agent-sdk"

try {
  await tx.tasks.get("tx-nonexistent")
} catch (err) {
  if (err instanceof TxError) {
    if (err.isNotFound()) {
      console.log("Task not found")
    } else if (err.isValidation()) {
      console.log("Validation error:", err.message)
    } else if (err.isCircularDependency()) {
      console.log("Circular dependency detected")
    }
    console.log("Error code:", err.code)
    console.log("HTTP status:", err.statusCode)
  }
}

Retry Logic

Built-in retry helper for resilient API calls:

import { withRetry } from "@jamesaphoenix/tx-agent-sdk"

const task = await withRetry(() => tx.tasks.get("tx-abc123"), {
  maxAttempts: 3,
  initialDelayMs: 100,
  maxDelayMs: 5000,
  backoffMultiplier: 2,
})

By default, withRetry retries on network errors and 5xx server responses.

Utility Functions

The SDK exports helper functions for common operations:

import {
  filterByStatus,
  filterReady,
  sortByScore,
  getNextTask,
  isValidTaskId,
  isValidTaskStatus,
  parseDate,
  wasCompletedRecently,
} from "@jamesaphoenix/tx-agent-sdk"

// Get the highest-priority ready task from a list
const tasks = (await tx.tasks.list({ limit: 100 })).items
const next = getNextTask(tasks)

// Validate IDs
isValidTaskId("tx-abc123") // true
isValidTaskStatus("active") // true

// Filter tasks client-side
const active = filterByStatus(tasks, "active")
const ready = filterReady(tasks)
const sorted = sortByScore(tasks)

// Date helpers
const recentlyDone = tasks.filter((t) => wasCompletedRecently(t, 24))

Cleanup

When using direct mode, dispose of resources when done:

const tx = new TxClient({ dbPath: ".tx/tasks.db" })
try {
  await tx.tasks.ready()
} finally {
  await tx.dispose()
}

HTTP mode has no resources to dispose. dispose() is safe to call on either mode.

Example: Full Agent Loop

import { TxClient } from "@jamesaphoenix/tx-agent-sdk"

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

async function agentLoop() {
  while (true) {
    // Get next task
    const ready = await tx.tasks.ready({ limit: 1 })
    if (ready.length === 0) break

    const task = ready[0]
    console.log(`Starting: ${task.title}`)

    // Get relevant context
    const ctx = await tx.context.forTask(task.id)
    const contextStr = ctx.learnings
      .map((l) => `- ${l.content}`)
      .join("\n")

    // ... pass task + context to your LLM ...

    // Record what was learned
    await tx.learnings.add({
      content: "Discovered pattern X works for problem Y",
      sourceRef: task.id,
    })

    // Complete the task
    const { nowReady } = await tx.tasks.done(task.id)
    console.log(`Done. ${nowReady.length} tasks unblocked.`)
  }

  console.log("All tasks complete!")
}

agentLoop()

On this page

InstallationQuick StartConnection ModesAPI ReferenceTaskstx.tasks.ready(options?)tx.tasks.done(id)tx.tasks.create(data)tx.tasks.get(id)tx.tasks.update(id, data)tx.tasks.setGroupContext(id, context)tx.tasks.clearGroupContext(id)tx.tasks.delete(id, options?)tx.tasks.list(options?)tx.tasks.block(id, blockerId)tx.tasks.unblock(id, blockerId)tx.tasks.tree(id)Learningstx.learnings.search(options?)tx.learnings.add(data)tx.learnings.get(id)tx.learnings.helpful(id, score?)Contexttx.context.forTask(taskId)Runstx.runs.list(options?)tx.runs.get(runId)tx.runs.transcript(runId)tx.runs.stderr(runId, options?)tx.runs.errors(options?)tx.runs.heartbeat(runId, data?)tx.runs.stalled(options?)tx.runs.reap(options?)Spectx.spec.discover(options?)tx.spec.link(invariantId, file, name?, framework?)tx.spec.status(options?)tx.spec.matrix(options?)tx.spec.run(testId, passed, options?)tx.spec.batch(data)tx.spec.complete(options)File Learningstx.fileLearnings.list(path?)tx.fileLearnings.recall(path)tx.fileLearnings.add(data)Messagestx.messages.send(data)tx.messages.inbox(channel, options?)tx.messages.ack(id)tx.messages.ackAll(channel)tx.messages.pending(channel)tx.messages.gc(options?)Claimstx.claims.claim(taskId, workerId, leaseDurationMinutes?)tx.claims.release(taskId, workerId)tx.claims.renew(taskId, workerId)tx.claims.getActive(taskId)Guardstx.guards.set(options)tx.guards.show()tx.guards.check(options?)tx.guards.clear(scope?)Verifytx.verify.set(taskId, cmd, schema?)tx.verify.show(taskId)tx.verify.run(taskId, options?)tx.verify.clear(taskId)Reflecttx.reflect.run(options?)Error HandlingRetry LogicUtility FunctionsCleanupExample: Full Agent LoopRelated