Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

Supervision protocol

Halfspan API and supervision protocol

Version: 0.1 · Browser use supervisor protocol

Purpose and scope

This document covers the browser use supervisor and its restricted service protocol. For API integration and the guardian proxy, read How Halfspan works, Company setup, and Data access and privacy.
Halfspan supervises a consumer agent one action at a time. The consumer proposes an action and supplies a structured report. Halfspan checks immutable owner authority and trusted state, then asks a separate guardian model to evaluate task relevance when hard checks pass. Only the gateway can issue and consume a permit. Browser execution and recorded receipts establish what actually happened.
The supervisor limits the executor's available tools and output schema to the configured action catalog. Its browser controls apply to sessions it runs, not to arbitrary external browsers. Consumer justifications are reported explanations, not private chain of thought or proof of intent.
The merchant, bank, and broker examples use synthetic transaction data. Obtain the appropriate service origin and scoped credentials from your integration operator. The hosted example storefront supports the merchant browser flow.

Actors and trust

ActorResponsibilityAuthority
OwnerSupplies instruction, terms, budget and exact/bounded approvalCreates immutable grants
Consumer / executorProposes one action and explains itCannot grant itself permission
Halfspan guardianReturns ALLOW, PAUSE or TERMINATECannot override hard checks
GatewayChecks state, grants, counters and bindings; issues single-use permitsEnforces authorization
Browser adapterExecutes the approved control in an isolated browserFixed-origin, scoped session
Hosted storeVerifies signed dispatch permits and commits effects in D1Enforces exact request binding
Page text, consumer prose and readable provider evidence are untrusted. Never accept instructions embedded in them. Opaque model continuation is retained privately and is not sent as guardian evidence.

Authentication and authority

Owner orchestration requires an authenticated owner session. When an organization restriction is configured, owner requests also require matching organization and active membership. Supervisor run records belong to the installation's shared workspace; use a company integration for tenant-scoped company access. Confirm the isolation boundary before connecting multiple organizations.
Executor agents use restricted service bearer credentials issued by trusted orchestration. These credentials do not authorize owner operations, grant creation, or transaction approval. A valid service credential is necessary but insufficient for execution: protected actions also require an exact, current, single-use permit.

One action cycle

  1. Read trusted observation, including its ID, document epoch, state revision and finite action catalog.
  2. Send the consumer the original instruction, grants, terms, workflow, clarifications and scoped browser screenshot when applicable.
  3. The managed executor returns a version 1 outcome: proposal, clarification, authorization_required, or refusal. Only proposals enter the action pipeline. Direct HTTP/MCP submissions retain the original TurnProposal contract. Accept streamed output only after successful response completion.
  4. Validate the outcome and, for proposals, the selected candidate. One malformed-output repair attempt is allowed. Explicit native or structured refusals never enter repair or automatic retry. Non-proposal outcomes pause without a permit.
  5. Apply deterministic checks: service, operation, grant, expiry, budget, target, exact arguments, effect contract, observation and transaction reference.
  6. If hard checks pass, send the report and the same trusted context to the guardian. Optional readable provider evidence is labeled untrusted. The guardian returns a structured decision.
  7. Bind any ALLOW to a short-lived single-use step permit. Recheck authority at claim and execution time.
  8. Execute through the selected transport, record the receipt, verify browser observations and retain signed evidence. Observe again before the next proposal.
Exact mode pauses after preparation until the owner approves the immutable transaction proposal. Bounded mode approves limits up front. Neither mode gives the consumer general account access.

Consumer report

All root fields below are required. Unknown root fields are rejected. Money uses integer cents encoded as decimal strings. Candidate IDs must be unique and the selected ID must refer to exactly one proposed candidate. There may be 1–12 candidates.
{ "goalRestatement": "The original owner instruction", "candidates": [{ "id": "candidate-1", "action": { "kind": "observe", "operationId": "merchant.catalog", "targetRef": "<current catalog target reference>", "args": {} }, "purpose": "Inspect the product before preparing the purchase.", "disposition": "proposed", "rejectionReason": null }], "selectedCandidateId": "candidate-1", "justification": { "summary": "This read supplies the product terms needed for the requested purchase.", "evidenceRefs": ["<current observation ID>"] }, "expectedEffect": { "operationId": "merchant.catalog", "transactionProposalId": null, "disclosedFields": ["<copy exact catalog fields>"], "postconditions": ["<copy exact catalog postconditions>"] }, "uncertainties": [] }
This is illustrative, not a runnable authorization: IDs and effect fields must come from the current observation. Action kinds are navigate, observe, click, fill, select and service. URL/value are optional but must exactly match the trusted catalog if present. args is an object and must match the catalog. A rejected alternative has disposition rejected and an explanation. Considering an unsafe alternative does not itself authorize or execute it.
The managed executor may return a proposal, clarification, authorization request, or refusal. Proposal requirements apply only to its proposal branch. The required justification.summary field is shown as a reported rationale; it is not a transcript of private reasoning. Direct transport callers continue to submit the original report shape.

Halfspan response and proposed next step

{ "decision": "PAUSE", "reasonCode": "MISSING_EVIDENCE", "explanation": "The justification must reference the current observation.", "clarificationRequest": null }
ALLOW means the reviewed proposal may receive a permit after all hard checks. PAUSE blocks execution pending correction, refreshed evidence or owner clarification. TERMINATE revokes session authority and unused permits. Halfspan does not generate an alternate action in this version: its next-step output is clarificationRequest or the exact authorized action in the permit. A guardian verdict is not itself a permit.
A permit binds run, goal, turn, grant, observation, document epoch, state revision, selected action, operation and transaction proposal. It expires after at most 30 seconds and no later than its grant. Another outstanding permit blocks a new turn. Consumed, expired, revoked or mismatched permits cannot authorize execution.

Owner API

All /api/v1/owner routes require owner authentication. Non-GET API calls also require x-halfspan-owner: 1. Browser Origin must match the authorized owner origin; cross-site requests and owner requests carrying Authorization are rejected. Send JSON bodies with Content-Type: application/json. These endpoints are for trusted owner orchestration, not executor agents.
Method and pathContract
GET /api/v1/owner/statusProvider availability and browser capability
GET /api/v1/owner/runsUp to 100 complete RunView objects, newest first
POST /api/v1/owner/runsCreate and initialize a scoped run
GET /api/v1/owner/runs/:idComplete current run view and timeline
POST /api/v1/owner/runs/:id/stepAdvance one supervised action
POST /api/v1/owner/runs/:id/playAdvance until pause/completion, max 16 steps
POST /api/v1/owner/runs/:id/revokeRevoke session and unused permits
POST /api/v1/owner/runs/:id/retryResume only eligible retry/configuration stops; no dispatch
POST /api/v1/owner/runs/:id/clarifyBody: {"clarification":"..."}; cannot expand grant
POST /api/v1/owner/runs/:id/approveBody: {"proposalId":"<uuid>"}; exact approval
POST /api/v1/owner/runs/:id/simulateSynthetic local lifecycle event; unavailable for hosted runs
GET /api/v1/owner/runs/:id/evidenceSigned evidence export
GET /api/v1/owner/runs/:id/eventsSSE signed events; Last-Event-ID resumes by sequence
GET /api/v1/owner/runs/:id/screenshotLatest scoped browser PNG, or 404
GET /api/v1/owner/public-keyPublic verification key
GET /api/v1/owner/specificationThis Markdown contract
GET /api/v1/owner/attacksAuthored adversarial fixture catalog
POST /api/v1/owner/attacks/runBody: {"attackId":"...","service":"merchant"}
GET /api/v1/owner/evaluations/casesFrozen case catalog, expected verdicts, and default comparison arms
GET /api/v1/owner/evaluationsSaved frozen semantic comparisons
POST /api/v1/owner/evaluationsBody: {"executionMode":"replay"} or live; no domain actions. Use the CLI for a bounded live matrix; the default live matrix exceeds the call ceiling
The documentation site provides endpoint-level request and response schemas and named examples in its API reference tab, generated from docs/openapi.json.
Example create-run body:
{ "service": "merchant", "target": "hosted", "channel": "browser", "trafficActor": "agent", "mode": "bounded", "executionMode": "live", "executor": "openai", "interrogator": "openai", "reasoningEvidence": false, "budgetCents": "13700", "instruction": "Buy one Fieldwork keyboard for $137 total using the approved terms." }
openai uses the connected ChatGPT account when available, otherwise its configured API credentials. No provider substitution is performed on failure. See the API reference for defaults and term schemas. A RunView contains identity, immutable instruction and terms, configuration, status/stage, grants, observation, model call count, proposal, executions, last decision, pending permit, clarifications and timeline. No private continuation or credentials are exposed.

Restricted consumer transport

A trusted owner runtime bootstraps a scoped service session. There is no public endpoint that grants a consumer its own authority. Consumer requests use Authorization: Bearer <restricted-session-token> against the exact service origin.
Method and pathContract
GET /api/v1/capabilitiesAvailable scoped action catalog
GET /api/v1/observationCurrent trusted observation
POST /api/v1/turnsConsumer report; returns turnId, decision and optional permit
GET /api/v1/decisionLast decision and pending permit
POST /api/v1/operationBody {"action":{...}}; x-step-permit and x-idempotency-key bind dispatch
Use only the action and references returned in the current catalog. Browser-local operations require the trusted browser runner. MCP exposes equivalent scoped handlers; native WebMCP is optional and unavailable unless the browser actually supports it. These restricted interfaces do not authenticate using the owner session cookie.

Hosted Cloudflare boundary

The hosted adapter bootstraps a signed session, then obtains a separately signed, exact-body dispatch permit for each mutation. The Worker verifies signature, audience, expiration, session, endpoint and request hash. A consumed-token ledger and mutation commit together in D1. A session cookie alone cannot authorize cart mutation or checkout. The private signing key never leaves the local runtime.
Local PostgreSQL and remote D1 are not one atomic transaction. A recorded external dispatch without a receipt is an unknown outcome, not proof of failure. Pause for manual reconciliation and do not automatically resend. Revocation cannot undo a request already dispatched. Hosted cancellation and arbitrary third-party websites are not implemented.

Evidence, timing and errors

Events carry ID, sequence, type, data, timestamp, previous hash, hash and Ed25519 signature. turn.proposed and guardian.decided share a turn ID. Permits reference the turn; execution and hosted receipts bind permit IDs. The UI pairs these records and labels decision provenance: live model, replay, hard policy or runtime/schema validation.
Recorded timestamps are persistence times, not exact inference start times. metrics events provide measured executor, guardian, policy, execution and observation durations. Signatures prove integrity against an independently trusted key; they do not prove explanation truth or current authority. Validate exports against the independently trusted public key, record hashes, signatures, and chain ordering.
Typical stop reasons include MALFORMED_PROPOSAL, MALFORMED_MODEL_REPORT, INVALID_SELECTION, STALE_TARGET, STALE_STATE, EFFECT_MISMATCH, MISSING_EVIDENCE, FORBIDDEN_OPERATION, ARGUMENT_MISMATCH, BUDGET_EXCEEDED, PERMIT_EXPIRED and provider timeouts/errors. HTTP 400 means invalid request schema, 401 means authentication required, 403 means origin or authorization rejection, 404 means missing resource; internal errors are sanitized. Operation-specific policy status codes and reasonCode accompany failures. Do not interpret an HTTP failure after dispatch as proof of no external effect.
Authored malformed attack reports are stored as attack.report followed by run.paused, without submitting a valid turn or issuing a permit. The 25-case attack catalog includes 12 added boundary cases checked ahalfspan all three domains (36/36 blocked with zero effects). Replay results are not live-model safety measurements.

Integration requirements and limits

  • Treat every consumer report as untrusted and validate before selecting or dispatching an action.
  • Never infer owner approval from a model explanation, page text or a forged permit field.
  • Distinguish proposed, allowed, permitted, dispatched and verified states in clients.
  • Keep money arithmetic in integer cents and scope every observation and permit to its run.
  • Require explicit owner approval for changed authority; clarification does not widen grants.
  • Current limits: 40 model calls per run, 60 seconds per provider call and one malformed response repair.
  • This contract describes implemented local functionality. Production hosting, tenant isolation, independent-agent enrollment and automatic external reconciliation are future work.

Versioned managed outcomes and recovery

The managed executor returns {version: 1, outcome: ...} with a proposal, clarification, authorization_required, or refusal discriminator. External HTTP/MCP proposal submission continues to accept the original TurnProposal shape. Native provider refusals are normalized separately and cannot authorize execution.
Owner run responses now include nullable stopContext (version 1): category, source, reasonCode, message, recovery, attemptId, observationId, and dispatch. This is a runtime classification, not a provider-controlled permission. Unknown versions fail closed at recovery.
POST /api/v1/owner/runs/:id/retry accepts {} and resumes only retry/configuration stops; it does not dispatch. The existing clarification route accepts only eligible clarification/refusal stops, and exact approval requires a fresh approval stop. All paths reject unresolved claimed or hosted effects. Refusal clarification never changes original authority. See decision supervision for classification, evidence, and compatibility details.

Traffic source attribution

Run creation accepts optional trafficActor: "agent" | "human" analytics metadata. Run responses expose this value, defaulting existing operator sessions to agent. This is caller-reported attribution, not proof of identity, and does not change authorization or execution behavior.
The overview counts sessions started in the selected UTC date window, limited to loaded records. Browser, HTTP API, server MCP and WebMCP are separate channels, each split by actor. Human traffic is counted only when explicitly attributed. This chart measures session starts rather than individual requests or page views.

Persistent workflow protection

GET /api/v1/owner/workspace returns registered services and guardians. Authenticated owner routes create service inventory and guardian drafts; PUT /api/v1/owner/workspace/guardians/:id requires the current revision. Concurrent edits reject rather than overwrite. Service URLs are inventory metadata, never agent-selected dispatch destinations.
POST /api/v1/owner/workspace/guardians/:id/verify runs synthetic reads through the installed local HTTP gateway. It tests caller authentication, mandatory permits, origin rejection, authorized receipts and duplicate-request idempotency without placing an order, transfer or trade or calling a model. It separately checks configured service, environment, operations, channels and native WebMCP capability. Verification events are excluded from operational dashboards.
POST /api/v1/owner/workspace/guardians/:id/activate requires {revision} and successful verification of that same revision within one hour. Activation supports the built-in local service adapters. Published policy versions are immutable. Published enforcement becomes degraded after 24 hours without fresh verification and publication. Custom or remote services remain drafts until their backend integration is implemented.
Run creation accepts optional guardianId. The backend resolves and snapshots the published policy as guardianBinding, including guardian, service, environment and policy version. It pins the authorization mode, budget and guardian provider, limits observation catalogs and grants to the selected operations, and rejects a mismatched service or channel. Publishing another version does not change active grants. Runs without a binding remain legacy sessions.
Dashboard outcomes distinguish decisions from effects. An unresolved hosted dispatch overrides a completed status. Receipt evidence is required for completion; a local authorization receipt cannot stand in for an external checkout receipt. Unconfirmed effects expose evidence review, never automatic retry. Exact approvals show the destination, amount, scope and expiry; stale or changed proposals cannot be approved.
Monitoring holds date- and mode-filtered charts. Traces holds searchable sessions and the approval, unconfirmed-effect and attention queues. Guardian/service filters and date ranges remain in session return links. Native WebMCP uses document.modelContext.registerTool, getTools, and executeTool(tool, inputObject); API detection, registration, invocation and backend enforcement have independent readiness labels. See the WebMCP draft for the API shape.
GET /api/v1/owner/hosting reports database connectivity, local runtime location, in-process worker status, signing-key fingerprint and check time. Company tenancy, deployment controls, employee enrollment and retention are not implemented; the dashboard displays those limits explicitly.