AI Agent - Autonomous Worker
The Opbox AI Agent is a server-side autonomous task processor. It picks up tasks from the AgentTask queue, runs an agentic tool-calling loop, and writes the result back. Two execution paths compete for the same queue - whichever claims first wins.
Architecture
| Path | Runtime | How it works |
|---|---|---|
| In-process worker | Inside the main app | Calls the resolved provider directly (Anthropic Messages API for provider=anthropic; OpenAI-compatible /v1/chat/completions for provider=openclaw with the opbox-specific headers + optional CF Access pair). Tool execution runs in-process. Credentials resolve through BYOK Credentials, which honours the OpenClaw-takes-precedence rule. OpenAI direct provider is not yet supported by the worker. |
| Agent Bridge | Separate Node.js process | Spawns Claude Code CLI as a child process. Communicates via stdin/stdout NDJSON. Connects back to Opbox via MCP. See Agent Bridge. |
Both paths use the same AgentTask queue, the same atomic-claim lease state machine, the same autonomy enforcement, the same cost ledger. The only difference is which process runs the agentic loop.
Task Lifecycle
PENDING → CLAIMED → PROCESSING → DONE
↘ FAILED / TIMED_OUT / CANCELLED
| State | Meaning |
|---|---|
| PENDING | Task created, awaiting a worker. |
| CLAIMED | A worker has claimed the task; lease (30 min) is held. |
| PROCESSING | The agentic loop is running. |
| DONE | Loop completed successfully. Result written. |
| FAILED | Loop errored or budget gate rejected. |
| TIMED_OUT | Terminal timeout after the retry/wall-clock policy is exceeded. |
| CANCELLED | Cancelled by an admin via the UI/API. |
Trigger Sources
Tasks are created automatically by fire-and-forget triggers in existing routes. The sourceType field records which trigger fired:
| Trigger | sourceType |
|---|---|
| Step assignment to agent | ASSIGNMENT |
| @-mention of agent in comment | MENTION |
| Auto-assignment on step entry | ASSIGNMENT |
| Webhook from external system (pipeline ingest) | WEBHOOK |
| Cron-driven recurring task | CRON |
| Self-spawned (depth ≥ 1) within an agentic loop | SELF |
Manual creation via POST /api/agent-tasks | MANUAL |
| Chat-initiated (chat-to-agent handoff) | CHAT |
A trigger only fires when the agent member is the assignee or mentioned party.
AgentTask Schema
| Field | Type | Description |
|---|---|---|
id | string | Task ID |
workspaceId | string | Workspace scope |
agentUserId | string | The Opbox Agent member identity |
createdById | string | The user who triggered the task (or null for cron/webhook) |
title / prompt | string | Human-readable label and the actual instruction |
status | enum | See lifecycle above |
priority | enum | LOW / NORMAL / HIGH |
result | string? | Final output (rendered as a comment on the source matter step) |
errorMessage | string? | On FAILED / TIMED_OUT |
progressText | string? | Live progress (updated by the bridge during execution) |
costUsd / durationMs / toolCallCount | metrics | Captured on completion |
sourceType / sourceId / sourceMatterId / sourceStepId | linkage | What triggered the task |
depth / parentTaskId | int / string? | Self-spawning depth (max 5) |
claimToken | string? | SHA-256 hash of the active claim token - required for progress/complete calls |
claimedAt / startedAt / completedAt / timeoutAt | timestamps | Lifecycle markers |
Bridge API (MCP API Key Auth)
These endpoints are auth via Authorization: Bearer cp_live_... + X-MCP-Client header (same as MCP routes). No session cookies.
| Endpoint | Method | Purpose |
|---|---|---|
/api/agent-tasks/[taskId]/claim | POST | Atomic claim. Returns plaintext claimToken + task details including autonomy level. |
/api/agent-tasks/[taskId]/progress | PATCH | Update progressText. Requires claimToken. |
/api/agent-tasks/[taskId]/complete | PATCH | Transition to DONE/FAILED. Accepts result, costUsd, durationMs, toolCallCount. Runs shared post-completion side effects. |
Admin API (Session Auth)
| Endpoint | Method | Purpose |
|---|---|---|
/api/agent-tasks | GET | List tasks (pagination, status filter). ADMIN/OWNER. |
/api/agent-tasks | POST | Create a manual task. ADMIN/OWNER + CSRF. |
/api/agent-tasks/[taskId] | GET | Full task details. |
/api/agent-tasks/[taskId] | PATCH | Cancel (PENDING/CLAIMED/PROCESSING only). ADMIN/OWNER + CSRF. |
/api/agent-tasks/[taskId]/retry | POST | Retry FAILED/TIMED_OUT. Creates a new task with parentTaskId. ADMIN/OWNER + CSRF. |
UI Surface
/agent-taskspage under Automations - paginated list with status filters and detail drawer.AutomationsSidebar.tsx- live queue counter and recent-tasks drawer.
Atomic Claim Lease
Both worker paths claim a task through the same atomic claim primitive. The lease lasts 30 minutes. If the worker crashes mid-task, the lease expires and the task becomes claimable again for a fresh/resume claim.
agent_queue_extend (MCP tool) lets a worker push the lease forward when it knows it'll need longer. Useful for doc-generation runs that legitimately take 5+ minutes.
Adaptive Briefing
agent_queue_get_briefing (MCP tool) returns a context-shaped briefing for the claimed task. For doc-gen tasks, the briefing includes:
- Matter payload (summarised)
- Step config and current data
- Coverage gate result (PASS/WARN/FAIL)
- Detected variables / sections / tables on the template
The agent uses the briefing to decide how to proceed without separate tool calls for each piece of context.
Security Controls
| Control | Detail |
|---|---|
| Default autonomy level | L0 (read-only). Both in-process worker and MCP claim endpoint default to 0 unless the workspace agent config explicitly raises it. |
| Autonomy enforcement | A single autonomy enforcer runs before every tool call on both paths. |
| Injection scanning | Prompt-injection scanning runs on tool results, page-context payloads, MCP bridge results, and manual task prompts. |
| Task depth limit | Maximum self-spawning depth: 5. Prevents runaway loops. |
| Task lease | 30 minutes; expired leases are claimable again. |
| Concurrency cap (in-process) | 3 concurrent tasks. |
| Result size cap | 50KB per tool result. |
| Iteration cap (in-process) | 25 agentic-loop iterations. |
| API key role gate | POST /api/agent/api-keys requires ADMIN/OWNER. Autonomy 0-3 is validated on input. |
| Rate-limit asymmetry | MCP bridge enforces per-tool-tier + per-key global limits. In-process worker uses iteration cap and task timeout only. |
Cost Tracking
Every model call inside the loop writes one AiCostLedger row (operationType: "agent"). The total per-task cost is summed at completion and stored in AgentTask.costUsd. The keySource follows the BYOK resolver chain - if the workspace has an org-level Anthropic key, the cost is attributed to ORG_KEY; if it has a workspace override, WORKSPACE_KEY.
Per-task budget gating runs before the loop starts. If the workspace is over its hard cap, the task fails immediately with BUDGET_EXCEEDED.
MCP Tool Surface for the Queue
Five MCP tools cover the queue lifecycle: agent_queue_list, agent_queue_claim, agent_queue_get_briefing, agent_queue_release, and agent_queue_extend. These let an external bridge (or any MCP client with adequate autonomy) drain the queue from outside the main app.
See Also
- Agent Bridge - how Claude Code CLI is spawned to drain the queue.
- Document Generation - the v1.1 doc-gen runtime that runs as agent tasks.
- Autonomy Levels - per-level tool access matrix.
- MCP Setup - how to mint API keys for the bridge.