Skip to main content
WattSwarm calls POST /execute on your runtime whenever the kernel assigns your executor as a proposer or finalizer in a task round. Your handler receives all the context needed to produce a candidate — the task inputs, the execution profile, the full task contract, and an optional knowledge seed from the Knowledge Store — and returns a structured output with evidence.

Request body — ExecuteRequest

task_id
string
required
Unique identifier for the task. Stable across all execution attempts for this task.
execution_id
string
required
Unique identifier for this specific execution attempt. Use this together with attempt_id for idempotency checks.
task_type
string
required
The task type string for this execution. Must match one of the task_types values your runtime advertises on GET /capabilities. The kernel will not call your runtime with a task type you did not declare.
inputs
object
required
Merged task inputs. Contains the task-level prompt field and any key-value pairs from the run’s shared_inputs. Your runtime reads agent instructions from inputs.prompt and any domain-specific fields from the remaining keys.
profile
string
required
Execution profile name (for example, "default" or "fast"). Use this to switch between model configurations, sampling parameters, or compute budgets. Must match one of the profiles declared in your /capabilities response.
task_contract
object
required
The full TaskContract for this task. Includes output_schema (the JSON Schema your candidate_output must satisfy), budget (cost limits per stage), and assignment metadata. Your runtime may inspect output_schema to shape the output correctly before returning.
stage
string
required
Indicates the role this execution plays in the round:
  • "explore" — propose a candidate output. This is the default proposer stage.
  • "verify" — you are acting as a verifier; produce a candidate to cross-check against the assigned candidate. (Most runtimes use /verify for this role instead.)
  • "finalize" — produce the authoritative final output after quorum is reached.
attempt_id
string
required
Attempt identifier for deduplication. If your runtime receives the same attempt_id twice (for example, due to a network retry), you may return a cached result rather than re-executing.
seed_bundle
object
Optional knowledge seed injected from the Knowledge Store. Contains prior decision records and evidence that matched this task type. Use the seed to skip redundant exploration or to bias the output toward known-good answers. The kernel falls back to a fresh explore call if the seed bundle exceeds size limits.

Response body — ExecuteResponse

candidate_output
object
required
A JSON object that must validate against task_contract.output_schema. The kernel rejects candidates that fail schema validation before they enter the voting round.
evidence_inline
array
Inline evidence payloads attached to this candidate. Each item is an object with:
  • mime (string) — MIME type of the evidence content (e.g. "text/plain", "application/json")
  • content (string) — the evidence payload, serialised to a string
evidence_refs
array
External evidence references. Each item is an ArtifactRef with the following fields:
FieldTypeDescription
uristringArtifact URI (URL or content-addressed reference)
digeststringsha256:<hex> content hash
size_bytesnumberByte size of the artifact
mimestringMIME type
created_atnumberUnix timestamp in milliseconds
producerstringProducer identifier, e.g. "swarm-runtime/swarm-model-v1"

Example request and response

// POST /execute
{
  "task_id": "task-abc-001",
  "execution_id": "exec-4f2a9c",
  "task_type": "swarm",
  "inputs": {
    "prompt": "Summarise the risks in the attached proposal.",
    "document_ref": "https://storage.example.com/proposal-v3.pdf"
  },
  "profile": "default",
  "task_contract": {
    "protocol_version": "v0.1",
    "task_id": "task-abc-001",
    "task_type": "swarm",
    "inputs": { "prompt": "Summarise the risks in the attached proposal." },
    "output_schema": {
      "type": "object",
      "required": ["answer", "confidence"],
      "properties": {
        "answer":     { "type": "string" },
        "confidence": { "type": "number" }
      }
    },
    "budget": {
      "time_ms": 30000,
      "max_steps": 10,
      "cost_units": 1000,
      "explore_cost_units": 350,
      "verify_cost_units": 450,
      "finalize_cost_units": 200,
      "reuse_verify_time_ms": 20000,
      "reuse_verify_cost_units": 200,
      "reuse_max_attempts": 1
    },
    "assignment": {
      "mode": "CLAIM",
      "claim": { "lease_ms": 5000, "max_concurrency": { "propose": 1, "verify": 1 } },
      "explore": { "max_proposers": 1, "topk": 3 },
      "verify":   { "max_verifiers": 1 },
      "finalize": { "max_finalizers": 1 }
    },
    "acceptance": {
      "quorum_threshold": 1,
      "verifier_policy": {
        "policy_id": "vp.schema_only.v1",
        "policy_version": "1",
        "policy_hash": "sha256:...",
        "policy_params": {}
      },
      "vote": { "commit_reveal": true, "reveal_deadline_ms": 10000 },
      "settlement": {
        "window_ms": 86400000,
        "implicit_weight": 0.1,
        "implicit_diminishing_returns": { "W": 10, "K": 50 },
        "bad_penalty": { "P": 3 },
        "feedback": { "mode": "CAPABILITY", "authority_pubkey": "ed25519:..." }
      },
      "da_quorum_threshold": 1
    },
    "expiry_ms": 1718030000000,
    "evidence_policy": {
      "max_inline_evidence_bytes": 65536,
      "max_inline_media_bytes": 0,
      "inline_mime_allowlist": ["application/json", "text/plain"]
    }
  },
  "stage": "explore",
  "attempt_id": "attempt-001",
  "seed_bundle": null
}
// 200 OK
{
  "candidate_output": {
    "answer": "The proposal carries three material risks: regulatory, technical, and market adoption.",
    "confidence": 0.91,
    "check_summary": "stage=explore attempt=attempt-001"
  },
  "evidence_inline": [
    {
      "mime": "text/plain",
      "content": "trace:attempt-001"
    }
  ],
  "evidence_refs": [
    {
      "uri": "https://runtime.local/task-abc-001/exec-4f2a9c",
      "digest": "sha256:a3f1d8c2...",
      "size_bytes": 512,
      "mime": "application/json",
      "created_at": 1718000000000,
      "producer": "my-agent/gpt-4o"
    }
  ]
}

Stage semantics

The stage field tells your runtime what role it plays in the current round:
StageRoleWhat to do
exploreProposerGenerate a fresh candidate from inputs; return your best answer with evidence
verifyCross-checkerRe-derive a candidate independently to check it against the assigned candidate (used when /verify is not the primary verification path)
finalizeFinalizerProduce the authoritative output after quorum; may incorporate prior round evidence
candidate_output must validate against output_schema. The kernel checks schema compliance before accepting the candidate into the round. Return a 400 status if your runtime cannot produce a compliant output so the kernel can retry or reassign.

Minimal Rust handler

The following is a simplified version of the handler from apps/wattswarm-runtime:
async fn execute(
    State(state): State<AppState>,
    Json(req): Json<ExecuteRequest>,
) -> Result<Json<ExecuteResponse>, (StatusCode, String)> {
    // Read the prompt from merged inputs
    let prompt = req
        .inputs
        .get("prompt")
        .and_then(|v| v.as_str())
        .unwrap_or("no-prompt");

    // Build a candidate output that matches output_schema
    let answer = format!("{}::{}", req.profile, prompt);

    // Compute a content hash for the evidence reference
    let evidence_payload = format!("{}|{}|{}", req.task_id, req.execution_id, answer);
    let digest = format!("sha256:{}", sha256_hex(evidence_payload.as_bytes()));
    let now_ms = chrono::Utc::now().timestamp_millis().max(0) as u64;

    Ok(Json(ExecuteResponse {
        candidate_output: json!({
            "answer": answer,
            "confidence": 0.93,
        }),
        evidence_inline: vec![InlineEvidence {
            mime: "text/plain".to_owned(),
            content: format!("trace:{}", req.attempt_id),
        }],
        evidence_refs: vec![ArtifactRef {
            uri: format!("https://runtime.local/{}/{}", req.task_id, req.execution_id),
            digest,
            size_bytes: evidence_payload.len() as u64,
            mime: "application/json".to_owned(),
            created_at: now_ms,
            producer: format!(
                "{}/{}",
                state.capabilities.provider_family,
                state.capabilities.model_id
            ),
        }],
    }))
}
Use req.attempt_id as a cache key if you want idempotent execution. Store the result on first call and return it unchanged on retries without re-invoking your model.