COG-16: Human-in-the-Loop Requests
Status: Draft
Version: 0.1
Created: 2026-07-19
Authors: Mike Anderson
This specification is under active development. Structure and details may change significantly based on implementation experience and community feedback.
This document specifies how agents and operations request decisions, approvals, and information from humans on the Covia Grid. It builds on the Job lifecycle of COG-8: Jobs, the per-user lattice namespaces of COG-4: Grid Lattice, the capability model of COG-13: Agent Capabilities, and the federation mechanisms of COG-15: Cross-Venue Federation. It introduces no new trust primitive — HITL composes the existing ones.
This standard specifies Human-in-the-Loop (HITL) requests — the mechanism by which an agent or operation asks a human for input, approval, or authority, and receives a structured, auditable answer.
Purpose
Autonomous agents routinely reach points where a human decision is required: approving a payment, choosing between alternatives, supplying missing information, or consenting to an expansion of the agent's authority. HITL requests make these moments first-class grid citizens:
- Durable — requests land in the target user's inbox and survive venue restarts; humans respond in minutes or in weeks
- Structured — asks are typed (text, approval, choice, checkboxes) so clients can render them and answers can be validated
- Auditable — the request, the response, and any authority granted are recorded with verified identities on both sides
- Job-shaped — every request is carried by a standard Job (COG-8), so requesters wait, poll, stream, and cancel with the machinery they already have
- Consent-preserving — a request MAY offer capability grants, but authority moves only through an explicit choice the human makes
- Federated — a request can target a user on a remote venue, with caller identity and authority forwarded per COG-15
Terminology
See COG-1: Architecture for Grid terminology, COG-8 for the Job lifecycle, and COG-13 for capabilities and UCANs.
| Term | Definition |
|---|---|
| HITL request | A structured request for human input, delivered as a record in the target user's h/ namespace |
| Ask | A single typed question within a request (text, approval, choice, checkboxes) |
| Requester | The verified identity (user or agent acting for a user) that created the request |
| Responder | The human user the request is addressed to — the owner of the h/ inbox it lands in |
| Inbox | The responder's h/ namespace, holding open and resolved HITL request records |
| Offered grant | A capability {with, can} attached to a request, ask, or option, which the responder may confer on the requester by approving it |
| Response | The responder's resolution of a request: an answer set, or a rejection |
Model
A HITL request separates three concerns, each carried by an existing grid primitive:
- The request record — a durable document in the responder's
h/namespace. This is the source of truth for HITL semantics: what is being asked, by whom, what is offered, and how it was resolved. - The Job — the requester-side lifecycle carrier. It is created when the request is submitted and reaches a terminal state exactly when the request is resolved:
COMPLETEwith the response as output, orFAILEDon rejection or expiry. - The response operation — the responder's action. It validates the answers against the asks, resolves the record, completes (or fails) the Job, and issues any approved capability grants.
HITL is not a Job status
A Job waiting on a HITL request SHOULD be in the INPUT_REQUIRED state, because that is the accurate lifecycle state: the job is blocked awaiting external input. However, the implication runs in one direction only:
INPUT_REQUIREDdoes not imply HITL. The status means input is required from some external party — another agent, a multi-turn caller, or a human. Many non-HITL flows (agent-to-agent conversations, multi-turn operations) use the same status.- HITL semantics live entirely in the
h/record and thehitl:*operations that manage it. No HITL behaviour is keyed off Job status, and clients MUST NOT discover pending human asks by scanning forINPUT_REQUIREDjobs. The inbox ish/.
Lifecycle overview
Requester (agent/user) Responder (human)
| |
|-- hitl:request ----------------------->|
| Job: PENDING -> INPUT_REQUIRED | record written to h/<id>, status "open"
| |
| (minutes ... weeks) | responder lists h/, reviews asks
| | and any offered grants
| |
|<------------------- hitl:respond ------|
| |
| outcome "answer": | record status "answered"
| Job: COMPLETE, output = response | approved grants issued as UCAN
| outcome "reject": | record status "rejected"
| Job: FAILED |
| |
| (no response before expiry) | record status "expired"
| Job: FAILED |
| (requester cancels the Job) | record status "cancelled"
| Job: CANCELLED |
The h/ Inbox
Each user's lattice record (COG-4) includes the h/ namespace, reserved for HITL requests. It behaves like the other user namespaces (w/, o/): slash-separated paths, navigable JSON values, and durable last-write-wins merge semantics.
Addressing
A request record lives at:
h/<request-id>
where <request-id> is the hex encoding of the carrying Job's ID. Using the Job ID as the request ID gives every request a unique, time-ordered identifier and a direct link between record and Job.
Write discipline
The h/ namespace is framework-managed:
- Records are created and resolved only by the venue, via the
hitl:*operations. Directcovia:writeintoh/MUST be rejected. - The inbox owner MAY read and list
h/freely (covia:read,covia:list,covia:slice,covia:inspect). - The inbox owner MAY delete resolved records (
covia:delete h/<id>) for inbox hygiene. Deleting an open record is equivalent to rejecting it: the venue MUST fail the carrying Job. - Cross-user reads of
h/records follow the standard delegation rules (COG-13): a requester holding acrud/readdelegation on the record path can observe the record state directly; otherwise the Job is the requester's view.
Request record schema
| Field | Type | Set by | Description |
|---|---|---|---|
id | string | venue | Request ID (Job ID hex) |
from | string | venue | Requester's verified DID. Never caller-supplied |
agent | string | venue | Originating agent (e.g. g/assistant), when the requester is an agent |
origin | string | venue | Origin venue DID, for requests delivered across venues |
title | string | requester | Short human-readable summary |
description | string | requester | Markdown body giving full context for the decision |
asks | array | requester | The list of asks (see Asks) |
status | string | venue | open → answered | rejected | expired | cancelled |
created | integer | venue | Creation timestamp (Unix ms) |
expires | integer | venue | Absolute expiry timestamp (Unix ms), when a timeout was requested |
response | object | venue | The response (see Responses), set on resolution |
Asks
A request contains an ordered list of one or more asks. Each ask is a typed question:
type | Meaning | Answer form |
|---|---|---|
text | Free-text input | string |
approval | Approve or reject a single stated action | boolean |
choice | Select exactly one option | option id (string) |
checkboxes | Select zero or more options | array of option ids |
Ask schema
| Field | Type | Applies to | Description |
|---|---|---|---|
id | string | all | Unique (within the request) identifier for the ask |
type | string | all | One of text, approval, choice, checkboxes |
prompt | string | all | The question, as shown to the human |
required | boolean | all | If true, an answer outcome MUST include an answer for this ask. Default false |
comment | boolean | all | If true, clients SHOULD offer an optional free-text comment alongside the answer. Default false |
options | array | choice, checkboxes | The selectable options. REQUIRED for these types, and MUST be non-empty |
grants | array | approval | Grants conferred if this ask is approved (see Capability Grants) |
Option schema
| Field | Type | Description |
|---|---|---|
id | string | Unique (within the ask) identifier for the option |
label | string | Human-readable label |
description | string | Optional longer explanation |
grants | array | Grants conferred if this option is selected |
Validation
Venues MUST validate requests at submission: ask ids unique, types recognised, options present and non-empty where required, option ids unique within their ask, and grants attached only where permitted — on approval asks and on options. Invalid requests are rejected synchronously — no record is written and no Job parks.
Responses
A response resolves a request. Its schema:
| Field | Type | Description |
|---|---|---|
outcome | string | answer or reject |
answers | object | Map of ask id → answer, in the form required by the ask type. REQUIRED for answer; ignored for reject |
comments | object | Optional map of ask id → free-text comment, for asks with comment: true |
comment | string | Optional overall comment. For reject, this is the rejection reason |
grants | array | The offered grants the responder explicitly approves (see Consent) |
Venues MUST validate responses against the record's asks: every required ask answered (for answer outcomes), answer forms matching ask types, choice and checkboxes answers naming existing option ids, and no answers for unknown ask ids. An invalid response fails the hitl:respond call and leaves the record open.
Job resolution
| Event | Record status | Job terminal state | Job payload |
|---|---|---|---|
answer response | answered | COMPLETE | output = {id, outcome, answers, comments?, comment?, grants?, token?} |
reject response | rejected | FAILED | error = "HITL request rejected" plus the responder's comment, when given |
| Expiry reached | expired | FAILED | error = "HITL request expired" |
| Requester cancels the Job | cancelled | CANCELLED | standard cancellation |
Job terminal states are sticky (COG-8); when a response races an expiry or a cancellation, exactly one resolution wins and the record MUST reflect the winner.
Rejection detail intended for the requester (the rejection comment) MUST travel in the Job error, since the requester generally cannot read the responder's h/ record.
Waiting, timeouts, and restarts
- Jobs have no framework-level timeout (COG-8); an unbounded HITL request waits indefinitely by design. Requesters SHOULD set a
timeoutfor time-sensitive decisions. - Expiry is a HITL-level property, enforced by the venue hosting the record. The venue MUST fail the Job when
expirespasses without a response, and MUST re-arm expiry enforcement for open requests after a restart. - Open requests and their parked Jobs survive venue restarts: paused-family Jobs are restored, and the
h/record is durable lattice state. - Requesters observe resolution through the standard Job surfaces: polling, blocking waits, and Job SSE streams. Responder clients discover work by listing
h/— venues MAY additionally surface notification channels, which are out of scope for this COG.
Operations
HITL is exposed through the hitl adapter. Operations follow the standard operation model (COG-7) and are catalogued under v/ops/hitl/.
hitl:request — submit a request
Creates the request: validates the asks, writes the record to the target user's h/, and parks the carrying Job in INPUT_REQUIRED. Asynchronous by nature — the Job is the handle.
Input:
| Field | Type | Description |
|---|---|---|
user | string | Target responder DID. OPTIONAL — defaults to the requester's own user identity (an agent asking its owner) |
title | string | REQUIRED. Short summary |
description | string | Markdown context for the decision |
asks | array | REQUIRED. One or more asks |
timeout | integer | Seconds until expiry. OPTIONAL — omitted means no expiry |
Output (Job output on completion): the response resolution payload described above.
hitl:respond — resolve a request
Invoked by the responder. Validates the response, updates the record, resolves the Job, and issues approved grants.
Input:
| Field | Type | Description |
|---|---|---|
id | string | REQUIRED. The request ID |
outcome | string | REQUIRED. answer or reject |
answers | object | Ask answers (for answer) |
comments | object | Per-ask comments |
comment | string | Overall comment / rejection reason |
grants | array | Explicitly approved grants |
Output: {id, status} — the resolved record status. Responding to a request that is not open MUST fail without side effects.
hitl:list — list the caller's inbox
Convenience listing of the caller's own h/ records, filterable by status. Venues MAY implement this as a thin wrapper over the workspace listing operations; clients MUST NOT depend on it existing and can always fall back to covia:list h/.
Cancellation
There is no hitl:cancel operation. The requester cancels through the standard Job cancellation surface; the venue then marks the record cancelled. Responder clients MUST treat a cancelled record as closed.
Authorisation
Delivering a request into a user's inbox is a cross-user act and is authorised at the point of delivery, following the capability model of COG-13:
- Ability:
hitl/requeston the resource<responderDID>/h/. - Self-ask: when the target user is the authenticated requester's own identity (the common case — an agent asking its owner), delivery is always permitted.
- Cross-user and federated asks: the requester MUST present authority covering
hitl/requeston the responder's inbox — a UCAN delegation issued by the responder, or authority admitted by the venue's trust policy (COG-15). Venues MAY additionally apply local policy (allow-lists, per-user opt-in) at this boundary. - Responding is restricted to the inbox owner in this version. Delegable response authority (e.g. an assistant answering on a user's behalf via a
hitl/responddelegation) is a candidate extension. - Anonymous callers cannot submit or answer requests: both operations require an authenticated identity, and the default public capability ceiling (COG-10) withholds
invokein any case.
Because responding can issue capability grants, venues MUST authenticate responders with the same strength they require for capability issuance generally.
Capability Grants
A request MAY offer the responder the opportunity to confer authority on the requester. Every offered grant is bound to a specific affirmative choice — if you choose this, you give this:
- Approval-ask
grants— conferred when that ask is approved (answeredtrue) - Option
grants— conferred when that option is selected
Grants attach nowhere else. There are no request-level grants: authority transfer is never a side effect of merely answering a request, and a grant that is not the direct consequence of a choice the responder made MUST NOT be issued. A plain "grant me access to X" is therefore expressed as an approval ask whose approval carries the grant.
Each offered grant is a capability as defined by COG-13:
{ "with": "w/reports/", "can": "crud/read", "exp": 1795000000 }
This COG deliberately specifies no capability semantics of its own. What a responder is able to grant, how delegations are issued and signed, how attenuation constrains onward use, and how issued tokens are trusted across venues are defined by COG-17: Capability Granting (with the capability model of COG-13 and the cross-venue trust rules of COG-15). HITL specifies only the consent surface: which choices confer which offered grants, and how the resulting token travels.
Grant rules
- An offered grant MUST lie within the responder's grantable authority as defined by COG-17: the responder's own resources, or resources belonging to others over which the responder holds granting rights (
grant/…). HITL is a consent surface, not a source of authority — a responder can confer through HITL exactly what they could delegate directly, and nothing more. - Grantability is enforced at issuance time, when the responder and their authority are known. A response echoing a grant outside the responder's grantable authority MUST fail without side effects.
- Every grant issued through HITL MUST be time-bounded. A grant's
expis capped by venue policy; an offer withoutexpreceives the venue's default grant lifetime.
Consent is explicit
Silent authority transfer is the central risk of HITL, and the protocol guards against it structurally:
- Responder clients MUST display every offered grant (resource, ability, expiry) attached to the choice that confers it, so the cost of approving or selecting is visible at the point of choice.
- The response MUST echo the grants being approved in its
grantsfield. The venue issues exactly the intersection of (a) the echoed grants and (b) the offers actually triggered by the choices made (approved approval asks and selected options). An echoed grant that was not offered-and-triggered MUST fail the response. - Answering a request while echoing no grants is always valid: the responder answers the questions but confers nothing.
Issuance
On a valid answer outcome with approved grants, a delegation token is issued whose audience is the requester (from) and whose attenuations are exactly the approved grants. Token format, the signing model (venue-attested, or signed by a self-sovereign responder), attenuation validation, and how verifiers trust the token's root are all governed by COG-17 — not by this COG.
HITL adds only the transport: the issued token is returned in the Job output as token, alongside the approved grants list, and the requester thereafter presents it as a standard proof.
Cross-Venue Requests
A HITL request targets a user where their inbox lives. To ask a user on a remote venue, the requester invokes hitl:request on that venue — directly, or via the grid federation operations — and COG-15 supplies the machinery:
- Caller identity crosses the hop as an audience-bound identity token; the responder's venue verifies the requester's own signature and attributes the request accordingly. The record's
fromis the verified caller DID andoriginthe originating venue. - Authority crosses in the proof channel: the requester forwards the UCAN delegation that covers
hitl/requeston the target user's inbox, and the remote venue enforces it at delivery exactly as in the local case. - The Job lives on the responder's venue (it carries the request); the requester's local grid job proxies its status and result through the standard federation job surfaces.
- Granted tokens flow back in the Job output. The audience is the requester's DID, so the token is presentable on any venue, subject to the root-authority trust rules of COG-15.
A venue MUST apply the same delivery authorisation to federated requests as to local cross-user requests. Federation changes where the request comes from, not what it is allowed to do.
Agent Skill
Venues SHOULD ship a hitl skill (COG-11) in the venue skill library so any agent can discover and load the HITL capability. The skill bundles:
- Tools:
v/ops/hitl/request, plus the standard job-status operation for observing resolution - Instructions, covering at minimum:
- Ask sparingly; batch related questions into one request rather than interrupting repeatedly
- Put the full decision context in
description— the human sees only the record, not the agent's conversation - Use the narrowest ask type that fits (
approvalfor yes/no,choice/checkboxesfor enumerable options,textonly when free text is genuinely needed) - Set a
timeoutfor time-sensitive decisions and handle theFAILEDexpiry outcome - Offer only the minimum grants needed, scoped as narrowly as possible; never treat a rejection as an error to retry
Security Considerations
- Requester identity is venue-attested.
from,agent, andoriginare set by the venue from the verified request context and are never caller-supplied. A record's provenance is as strong as the venue's ingress authentication. - Social engineering. A HITL request is a phishing surface: it asks a human to approve actions and confer authority. The cross-user
hitl/requestgate exists so users receive asks only from parties they (or their venue's policy) have accepted. Clients MUST render the verifiedfrom/originidentities prominently, and MUST NOT render requester-controlled text (title, description, prompts) in a way that spoofs client chrome or verified fields. - Grant review. All authority transfer is bound to a specific affirmative choice, opt-in per grant, echoed explicitly in the response, restricted to the responder's grantable authority (COG-17), and time-bounded. Clients that cannot render grants MUST NOT submit responses that echo them.
- Mutation and TOCTOU. The record the responder reviews is the record the venue resolves: requests are immutable once delivered (only the venue-set
status/responsefields change), and the echo-consent rule means a response approves specific capabilities, not "whatever the record now says". - Sensitive content. Ask prompts and answers may carry sensitive data. The standard
secretFieldsredaction applies to the carrying Job's persisted record; theh/record itself lives in the responder's own namespace under their access control. Requesters SHOULD NOT place secrets in requests destined for third parties. - Resource exhaustion. Every request parks a Job and writes a record. Venues SHOULD bound open requests per requester and per inbox, and SHOULD rate-limit
hitl:request, particularly at the cross-user and federated boundaries. - Expiry integrity. Expiry enforcement MUST survive restarts; a venue that loses its timers must reconstruct them from the durable
expiresfields, not silently leave requests open forever when a timeout was promised.
Examples
Simple approval (agent asks its owner)
// invoke v/ops/hitl/request
{
"title": "Pay invoice INV-4711",
"description": "Acme Ltd invoice INV-4711 for £12,400, matched to PO-2231. Payment due Friday.",
"asks": [
{ "id": "pay", "type": "approval", "prompt": "Approve payment of £12,400 to Acme Ltd?",
"required": true, "comment": true }
],
"timeout": 172800
}
The Job parks in INPUT_REQUIRED; the record appears at h/<id> in the owner's inbox. The owner responds:
// invoke v/ops/hitl/respond
{
"id": "0195f3a2b4c6...",
"outcome": "answer",
"answers": { "pay": true },
"comments": { "pay": "Approved — this invoice only." }
}
The Job completes with:
{ "id": "0195f3a2b4c6...", "outcome": "answer",
"answers": { "pay": true },
"comments": { "pay": "Approved — this invoice only." } }
Mixed asks with an offered grant
{
"title": "Quarterly report run",
"description": "Ready to generate the Q3 report pack. I need output preferences and read access to the source reports.",
"asks": [
{ "id": "detail", "type": "choice", "prompt": "Report depth?",
"options": [
{ "id": "summary", "label": "Executive summary" },
{ "id": "full", "label": "Full detail" }
], "required": true },
{ "id": "sections", "type": "checkboxes", "prompt": "Include:",
"options": [
{ "id": "fin", "label": "Financials" },
{ "id": "ops", "label": "Operations" }
] },
{ "id": "access", "type": "approval", "prompt": "Grant read access to w/reports/ for 7 days?",
"grants": [ { "with": "w/reports/", "can": "crud/read", "exp": 1795000000 } ] },
{ "id": "notes", "type": "text", "prompt": "Anything to emphasise?" }
]
}
Response, explicitly echoing the approved grant:
{
"id": "0195f3c1d2e8...",
"outcome": "answer",
"answers": { "detail": "full", "sections": ["fin", "ops"], "access": true,
"notes": "Flag the Q3 logistics overspend." },
"grants": [ { "with": "w/reports/", "can": "crud/read", "exp": 1795000000 } ]
}
The Job output includes the answers, the approved grants, and a token — a UCAN audienced to the requesting agent, presentable as a proof on its subsequent w/reports/ reads.
Rejection
{ "id": "0195f3a2b4c6...", "outcome": "reject", "comment": "Wrong PO — resubmit against PO-2240." }
The Job fails with error: HITL request rejected: Wrong PO — resubmit against PO-2240. The requester sees the reason through the Job; the resolved record remains in the responder's inbox until deleted.
Related Specifications
- COG-4: Grid Lattice — user namespaces, including
h/, and merge semantics - COG-7: Operations — the operation model implemented by the
hitladapter - COG-8: Jobs — the Job lifecycle carrying every HITL request
- COG-9: Agent Messaging — the agent-to-agent counterpart of human-directed requests
- COG-10: Venue Authentication & Access Control — caller authentication and the public capability ceiling
- COG-11: Agent Lifecycle — agents and skills
- COG-13: Agent Capabilities — capabilities, UCAN delegation, and attenuation
- COG-15: Cross-Venue Federation — identity forwarding and authority relay for remote requests
- COG-17: Capability Granting — the granting model beneath HITL's consent surface