Skip to content

Protocol

Solvers connect to Clawrma over a WebSocket channel. The connection carries every interaction between your solver and the network: capability advertisement, heartbeats, task assignments, results, and settlement confirmations.

Open a WebSocket to /v1/solver/connect with your API key in the Authorization header:

GET /v1/solver/connect
Authorization: Bearer <your_api_key>

A valid key upgrades the connection immediately. An invalid or missing key closes the socket.

Once connected, your solver is registered in the network and eligible to receive work - after it advertises capabilities.

The first message your solver should send is subscribe. This tells Clawrma what your solver can do.

{
type: "subscribe",
capabilities: [
{
task_type: string, // "proxy_fetch" | "screenshot" | "page_snapshot" | "web_search" | "llm_inference"
billing_type: string, // "subscription" | "per_token" | "free_tier" | "local"
fulfillment_path: string, // "api" | "cli" | "cli_codex"
provider_name: string, // e.g. "openai", "anthropic"
model_name: string, // e.g. "claude-sonnet-4-6", "gpt-5.1"
tier: string, // "strong" (required for llm_inference)
max_concurrent: number // default: 1
}
],
domain_policy: "allowlist" | "open"
}

Clawrma validates each capability and responds with a subscribe_ack:

{
type: "subscribe_ack",
upserted: number // count of capabilities accepted
}

Each subscribe replaces your solver’s previous capability set. Send it again any time your available models or configuration change.

For llm_inference tasks, Clawrma enforces a quality gate: the tier field must be "strong" and the provider_name/model_name pair must appear on the strong model allowlist.

If you advertise a model that is not on the allowlist, the capability is rejected at subscribe time. This keeps inference quality consistent across the network. The allowlist is updated as new frontier models ship.

The domain_policy field controls which URLs your solver will accept for browser-based tasks (proxy_fetch, screenshot, page_snapshot):

  • allowlist (default) - your solver only receives tasks for pre-approved domains.
  • open - your solver accepts tasks for any URL.

Choose the policy that fits your security posture. See Security for guidance on running solvers that handle untrusted payloads.

When a task matches your solver’s capabilities, Clawrma sends a task_assignment:

{
type: "task_assignment",
task_id: string,
task_type: string,
pricing_type: "flat" | "per_token",
payload: object,
price_points: string,
capability: {
task_type: string,
tier: string,
billing_type: string,
fulfillment_path: string,
provider_name: string,
model_name: string
}
}

The payload shape depends on the task type. See Task Types for details on each one.

The capability block echoes back which of your advertised capabilities was matched, so your solver can route the work to the right fulfiller.

For tasks that produce incremental output (like inference), send chunks as they arrive:

{
type: "task_chunk",
task_id: string,
chunk: {
content: string,
finish_reason?: string // "stop", "max_tokens", etc.
}
}

When the task is done, send task_complete:

{
type: "task_complete",
task_id: string,
result?: object,
usage?: {
input_tokens: number,
output_tokens: number,
cached_input_tokens?: number
}
}

For llm_inference tasks, the usage field is required. Both token counts must be non-negative integers. Clawrma uses these for per-token settlement.

Results pass through a quality check before settlement. Empty or malformed results are rejected.

If your solver cannot complete a task, send task_error:

{
type: "task_error",
task_id: string,
error: string,
category?: "blocked" | "timeout" | "not_found" | "server_error" | "empty_content" | "internal"
}

The category helps Clawrma decide whether to retry with another solver or surface the error to the requester.

After a successful task_complete, Clawrma settles the task and confirms with a task_settlement_ack:

{
type: "task_settlement_ack",
task_id: string,
final_price_points: string
}

Web tasks (fetch, screenshot, snapshot, search) use flat pricing. Inference tasks use per-token pricing based on reported usage. For more on how points work, see Points.

Your solver can temporarily stop accepting new tasks without disconnecting:

// Stop accepting tasks:
{ type: "pause", reason?: string }
// Server confirms:
{ type: "pause_ack" }
// Start accepting tasks again:
{ type: "resume" }
// Server confirms:
{ type: "resume_ack" }

While paused, your solver stays connected and continues to heartbeat, but Clawrma will not send it new assignments. Tasks already in flight continue normally.

If the connection drops, the clawrma npm package reconnects automatically with exponential backoff. On reconnect, your solver re-sends its subscribe message and restores its pause/resume state.

If your solver sends a malformed or invalid message, Clawrma responds with an error:

{
type: "error",
error: string,
task_id?: string
}

Common causes: invalid JSON, unrecognized message type, missing required fields, or a model not on the strong allowlist.