Skip to content

Task Dispatch

How It Works

  1. Create a task with an agent image, instructions, and optional skills/configs
  2. Call dispatch_task(task) -- assembles brief, selects dispatcher, POSTs to it
  3. Dispatcher queues the task, consumer dequeues and spawns the container
  4. Agent boots, downloads brief, checks in, does work, checks back
  5. Dispatcher fires callback to Controller with result

Brief Assembly

The brief is a JSON package containing everything the agent needs:

{
  "task_id": "uuid",
  "task_name": "Code review",
  "skills": [{"slug": "code-review", "instructions": "..."}],
  "configs": [{"slug": "style-guide", "content": "..."}],
  "instructions": "Review the PR for quality.",
  "context": "Repository: org/repo, PR #42"
}

The Controller assembles the brief from five sources:

Component Source Example
Skills Skills Registry GitHub tool, CRM connector, code reviewer
Config Config Registry Response style, model settings, standards
Instructions Per-task (inline) "Review this PR against our style guide"
Secrets Secrets store GitHub PAT, API keys (injected as env vars)
Context Per-task (inline) Codebase overview, domain rules

The assembled brief is uploaded to object storage. The agent receives only a key at boot -- downloads, verifies the content hash, and loads.

Dispatch Modes

Controller POSTs to the Dispatcher's /tasks endpoint directly.

Controller --> POST /tasks --> Dispatcher

Controller publishes to Redis Stream or SQS. Dispatcher consumes via XREADGROUP.

Controller --> Redis Stream --> Dispatcher (consumer group)

Set dispatch_mode=bus on the DispatcherInstance record in the Controller.

Dependency Resolution

Before dispatch, the Controller resolves infrastructure dependencies:

  1. Tier deps -- derive base dependency set from the agent tier
  2. Definition deps -- merge any additional deps from the AgentDefinition
  3. Service deps -- look up each InfraService record. If missing or unhealthy, reject dispatch
  4. Port deps -- add required port mappings to the runtime spec
Dep type Env vars injected
scuttlebot-irc SCUTTLEBOT_URL, SCUTTLEBOT_TOKEN, SCUTTLEBOT_CHANNEL, SCUTTLEBOT_IRC_ADDR
navegador-redis NAVEGADOR_REDIS_URL

Early failure

If a required service is missing or unhealthy, dispatch fails loud at dispatch time -- not at agent boot.

Task Request Schema

What the Controller sends to POST /tasks:

{
  "task_id": "uuid",
  "agent_image": "ghcr.io/conflicthq/kohakku-agents:terminal-claude-latest",
  "runtime_target": {"type": "k8s", "namespace": "agents"},
  "resources": {"cpu": "1", "memory": "2Gi"},
  "env": {"TASK_ID": "...", "BRIEF_KEY": "s3://..."},
  "ports": [{"container_port": 6080, "protocol": "tcp"}],
  "brief_key": "briefs/guid/hash.json",
  "callback_url": "https://controller/api/v1/tasks/guid/callback/",
  "callback_token": "signed-bearer-token",
  "timeout_seconds": 3600
}

Task State Machine

QUEUED
  | (container booting)
PROVISIONING
  | (agent checks in)
RUNNING
  | (exit 0)        | (exit != 0)      | (deadline exceeded)
COMPLETED         FAILED             TIMED_OUT

The Dispatcher owns this state in Redis. The agent moves it from QUEUED to RUNNING (at check-in) and RUNNING to terminal (at check-back).

Retry Policy

dispatch_with_retry() wraps dispatch with exponential backoff:

Retryable:

  • Connection errors, timeouts, 5xx responses
  • "No active dispatcher" (temporary -- dispatchers may be restarting)

Non-retryable:

  • BriefAssemblyError -- skill or config resolution failed
  • ImageResolutionError -- agent image not found
  • ValueError -- invalid task parameters
  • 4xx responses

Default: 3 attempts, exponential backoff. Configurable at the workflow level via Temporal retry policy.

Task Deduplication

Tasks are keyed by a hash of their config. The Dispatcher will not re-run a task that is active or completed unless forced. Check-in is idempotent.

Monitoring

Two ways to get task state:

Method How
Callback (push) Dispatcher POSTs to the Controller's callback URL on completion/failure
Poll (pull) GET /tasks/{task_id} returns current state at any time

Telemetry tracked per task: status, started_at, completed_at, duration_seconds, exit_code, tokens_used, log_stream, error, result_key.