agent-dispatch

Agent Dispatch Queue

Hand any task off to an agent (Claude Code, Cursor CLI, a local model behind your own webhook) and let it work in your infrastructure. Every dispatch is HMAC-signed, every result comes back through an HMAC-verified callback, and every hop lands in the audit log.

Not a chatbot. Not autonomy-by-default. A queue with provenance.

What it is not

  • Not a hosted agent. Ithura never runs the model. Your infrastructure does, on hardware you control.
  • Not a chat surface. The dispatch happens once, the runner replies once (or streams status updates via callbacks). No back-and-forth in the UI.
  • Not autonomous. A human dispatches; a human reviews the resulting PR. Height 2.0 tried autonomy-in-SaaS and shut down in September 2025. This is deliberately the opposite shape.

Register a runner

Workspace admin only. Settings → Agent runners → Register runner.

Fields:

  • Name: what you call this runner, e.g. "Claude Code on ops laptop".
  • Webhook URL: HTTPS endpoint the dispatch payload POSTs to.
  • HMAC secret: at least 16 characters. Click Generate for a 48-hex random value. Store the value in your runner as ITHURA_RUNNER_SECRET. The SPA never reads the secret back after creation; a leaked bearer token cannot exfiltrate it.
  • Timeout: seconds Ithura waits for the outbound POST to succeed (default 900, cap 3600).

Dispatch a task

Any workspace member with member+ access can dispatch. On any task, call the API (v1 has no UI action yet):

POST /workspaces/{slug}/projects/{projectID}/issues/{issueID}/dispatch-agent/
{
  "runner_id": "<uuid from the Agent runners page>",
  "acceptance_criteria": "Ship a PR that closes this; tests must be green"
}

The response returns the dispatch run id and status queued. The worker picks it up, signs the payload, POSTs to the runner. On any 2xx, the run moves to in_progress and waits for the callback.

Runner-side integration

Ithura POSTs a JSON payload with the task snapshot plus a callback URL:

{
  "issue": {
    "id": "…",
    "project_identifier": "PAR",
    "sequence_id": 482,
    "name": "SAML JIT provisioning gate for verified domains",
    "description": "…",
    "priority": "high",
    "state": "In progress"
  },
  "acceptance_criteria": "…",
  "callback": {
    "url": "https://api-staging.ithura.com/agent-runs/<token>/callback",
    "signature_header": "X-Ithura-Signature",
    "signature_scheme": "hex_hmac_sha256(secret + callback_token, body)"
  }
}

The runner:

  1. Verifies the outbound X-Ithura-Signature: hex(hmac_sha256(ITHURA_RUNNER_SECRET, request_body)). If mismatched, the request came from someone else. Reject.
  2. Does its work. It can POST intermediate status: in_progress callbacks as often as it wants.
  3. On completion, POSTs a terminal status:
{
  "status": "completed",
  "result_url": "https://github.com/acme/repo/pull/301",
  "result_summary": "Added SAML JIT gate, 3 tests, all green"
}

The callback must include X-Ithura-Signature computed as:

hex(hmac_sha256(ITHURA_RUNNER_SECRET + callback_token, callback_body))

The per-run callback_token extra ensures a leaked runner secret alone cannot forge callbacks for other runs.

Statuses

StatusMeaning
queuedThe dispatch job is enqueued in Ithura's worker pool.
in_progressThe outbound POST returned 2xx, waiting for the terminal callback.
completedRunner posted a completed callback. result_url is the PR / MR.
failedRunner posted a failed callback OR the outbound POST failed. error_text explains.
cancelledA workspace admin manually cancelled the run.

Terminal states (completed, failed, cancelled) are idempotent: subsequent callbacks are audited (workspace.agent_dispatch.callback_ignored) but do not mutate the row.

Audit

Every dispatch, every callback, every runner change writes an entry to audit_logs:

  • workspace.agent_runner.created / .deleted
  • workspace.agent_dispatch.queued / .in_progress / .completed / .failed / .callback_ignored

Enterprise workspaces can export the whole trail as CSV via the audit log export endpoint (see Sovereign > Audit CSV).

Follow-ups on the roadmap

  • UI dispatch action on the task detail page (v1 is API-only for operators; the UI is Register-runner + read history).
  • Auto-dispatch rules ("every task labelled agent-eligible goes to runner X on state change to Ready").
  • Cost tracking: runner reports tokens / seconds in the callback; we surface the totals per runner and per workspace.
  • Retry policy (v1 requires a fresh dispatch call after a failed run to keep the audit trail linear).
  • Sovereign: every dispatch runs on the customer's own infrastructure; the tracker is the audit surface.
  • Webhooks: the outbound signing pattern here mirrors the workspace-webhooks HMAC scheme; a runner and a webhook subscriber can share the same verification code.