Skip to content

Opt-in task workflow API (FLOW-02)

Status: local server implementation; not deployed. Bridge automation and native presentation remain FLOW-03/FLOW-04. Integration tests use actual MCP, HTTP and PostgreSQL with synthetic provider sessions and Git references. They do not prove that a real provider can produce or verify a candidate.

Dispatch and identity

Call workflow_dispatch(spec, write_context) with tasks:write and active owner/admin membership. The actor must also control the selected Bridge's anchor project. All writes use the same resource/instance/project binding as existing MCP writes. spec is a discoverable, closed typed schema in tools/list:

  • task_id, current expected_task_version, enrolled bridge_id, unique idempotency_key (1–128 alphanumeric, underscore, dot or hyphen characters).
  • Explicit absolute workspace, 40-character lowercase Git base_commit, branch, and bounded nonempty work prompt.
  • profile (worker) and verifier: versioned operator-authored profile snapshots. Each contains profile_id, version, runtime, instructions, optional soul, pinned skills (id, version, content), and provider account_id and explicit model. Runtime is synthetic, codex_cli or claude_code_cli. Synthetic fixtures omit the account. Provider accounts must be node-allowed. Worker and verifier profile IDs differ; verifier allow_workspace_writes must be false. These are snapshots, not automatic Agent Catalog resolution.
  • criteria: 1–32 entries with unique id, nonempty description and method.
  • document_refs: up to 32 repository-relative references pinned through the contract's repository/base commit.
  • max_work_attempts: 1 or 2, default 2. Every verification is a distinct attempt.

The server freezes the task goal, input version, repository, assignment and profiles into an immutable revision and SHA-256 contract digest. Dispatch and its first offer are atomic. A matching idempotency replay returns the same revision; a changed request with that key fails. A new revision is allowed only after cancellation or blocking and with the current task version. Old revisions, attempts, evidence references and phase history remain available in storage. A node allows at most one offered/running execution, including legacy work.

Claim, preparation and completion

Bridge uses the existing /bridge/v1/executions HTTP offer/claim/renew/event routes. The plan additionally contains workflow: revision ID, purpose (work/verify), contract digest, criteria, document references, candidate, worker attempt ID and any correction feedback. The execution ID is the attempt ID; plan.session_id is fresh for every attempt. Node-side workspace/runtime opt-in and actual profile/tool preparation must be implemented in FLOW-03.

The execution's legacy state=running denotes a held lease. The authoritative workflow phase distinguishes claimed, preparing, running and verifying. A claim alone never reports that the provider session is ready.

Send ordered events under lease_id, fencing_token, sequence:

  1. state=preparing after claim.
  2. state=running with a fresh, nonempty provider_session_id after preparation.
  3. state=completed, exit_code=0, the same provider session ID, result_commit, repository-relative evidence_path, clean_workspace=true. A failed/interrupted event can instead give a bounded reason.

Leases expire after 90 seconds, can be renewed, and have an absolute 15-minute attempt deadline. An exact event replay is safe; conflicting or out-of-order sequences fail. The server checks current node/project/account authority on claims, renewals and events. Expired/terminal executions cannot accept results. Missing candidate/clean-workspace/evidence attestation blocks the workflow. Bridge is responsible for checking the actual clean Git workspace and SHA; the server cannot inspect the Mac's filesystem from a reference.

Worker completion creates one verifier offer atomically with awaiting_verification. The verifier receives the exact candidate as its base. It must use a separate fresh session and treat worker material as evidence, never as instructions overriding frozen criteria. Its terminal event additionally contains verdict:

{
  "contract_digest": "<64 lowercase hex characters>",
  "candidate_commit": "<40 lowercase hex characters>",
  "worker_execution_id": "<worker attempt UUID>",
  "verifier_execution_id": "<this verifier attempt UUID>",
  "results": [
    {
      "criterion_id": "tests",
      "outcome": "pass",
      "evidence_path": "evidence/tests.json",
      "feedback": "The recorded tests pass for the candidate."
    }
  ]
}

Every frozen criterion must appear exactly once, with pass or fail, a valid relative reference and nonempty feedback. IDs, digest, candidate and session must match. Missing/stale/duplicate/unknown criteria cannot pass; the worker cannot submit a verifier verdict. A valid all-pass verdict atomically writes an acceptance receipt and sets task done. A failed criterion records changes_requested and queues a fresh correction attempt, including feedback, within the frozen work budget. Exhaustion blocks. Missing verdict/evidence is an infrastructure/evidence block, never a fabricated substantive failure.

This is an attributed verifier judgement with reference validation, not a claim that the server independently ran tests or fetched evidence contents. Real artifact checks and provider delivery are acceptance work for FLOW-03/FLOW-05.

Reads and recovery

  • workflow_get(task_id, after=0, limit=50) returns the current contract, phase, candidate, active attempt, reason and history. Limit is 1–100; next_after is the last returned sequence, scoped to that workflow revision. Reset the cursor when the workflow ID changes.
  • Node-authorized GET /bridge/v1/tasks/{task_id}/workflow?after=0&limit=50 returns the same detail contract. Foreign projects are denied.
  • MCP task_get/task_list and HTTP task detail/index include a compact workflow projection: phase, revision, attempt, candidate, reason, profile IDs/versions, last update, active purpose and lease expiry/deadline. List reads use one bounded batched query, never one request/query per row or full prompt/history serialization.
  • workflow_control(task_id, expected_version, action, write_context) is owner/admin-only. cancel atomically cancels the active attempt and workflow. reconcile marks an expired running attempt interrupted and its workflow blocked. An idle server does not silently retry an expired process; reconcile is explicit, and node renewal/event expiry also records the block. Reads do not mutate state; a disconnected node may retain its last reported phase until reconciliation. The projection exposes lease_expired and deadline timestamps so clients can distinguish a stale last phase from a live execution.
  • Retry dispatch requires a new key, current task version and explicit new frozen revision. No ambiguous process is resumed. Late events from old revisions can at most acknowledge already recorded events.

Managed task status changes and active goal edits through legacy task_update are rejected. Cosmetic metadata edits remain possible without invalidating the frozen contract or preventing claim. The ordinary execution create/cancel API cannot bypass managed task workflow control. Ordinary continuity tasks and legacy supervised executions keep their previous completion semantics.

Publication

Dispatch and task acceptance do not themselves push, merge or deploy repository changes. Publication remains a separately authorized release action. For the installed opt-in background path, see operating the complete workflow and the FLOW-08 release report.

Catalog-backed dispatch

workflow_dispatch_catalog(spec, write_context) replaces inline profile and verifier with {agent_id, version, account_id, allow_workspace_writes, sources}. Here account_id selects a local provider login (for example default), not the HeyAira account UUID. Model/provider/reasoning come from the pinned agent version; the caller still explicitly selects the worker and verifier identities.

Each source maps {ref, source_id, commit_sha} to an existing project-allowlisted Git document. ref must exactly match the document path and the catalog metadata reference. Map the role's heartbeat and optional instructions, optional agent soul and every skill source. Missing, extra, foreign, revoked, mismatched or truncated documents fail closed. Definitions must be active; a latest deprecated version disables that identity for new dispatch. Older active versions can be selected while the identity is available. Resolution has a 30-second bound, 35 sources per profile and the existing 60 KiB combined profile limit.

Dispatch requires tasks:write, agents:read, documents:read and current project owner/admin membership plus control of the assigned Bridge node. Source authorization is rechecked under locks when committing the workflow. The frozen contract includes identity versions, source IDs, repository/commit/path and content SHA256; correction/verifier sessions reuse that snapshot. Exact retries return the existing workflow without fetching new source content. Revoking a source prevents new dispatch; cancel an existing workflow explicitly if its already-frozen instructions must no longer run.

Supported reasoning values are low, medium, high, xhigh, max; Bridge passes the selected value to Codex or Claude. Actual model support is provider validated; an unsupported provider/model combination fails the session rather than silently changing the user's choice. Inline-profile dispatch remains compatible and reasoning is optional there. Source references are metadata; Git remains the source of document contents, frozen only in the execution contract needed to run the assigned task.