pub enum HarnessReadRequestV1 {
ContextGet,
MonitorGet {
run_id: Option<HarnessRunId>,
},
TimelineRead {
run_id: Option<HarnessRunId>,
after_sequence: Option<u64>,
limit: u16,
},
TasksList {
after_task_id: Option<HarnessTaskId>,
state: Option<HarnessTaskStateV1>,
parent_task_id: Option<HarnessTaskId>,
limit: u16,
},
TaskGet {
task_id: HarnessTaskId,
},
RunsList {
task_id: Option<HarnessTaskId>,
after_run_id: Option<HarnessRunId>,
lifecycle: Option<HarnessRunLifecycleV1>,
parent_run_id: Option<HarnessRunId>,
limit: u16,
},
RunGet {
run_id: HarnessRunId,
},
OperationGet {
operation_id: HarnessOperationId,
},
TaskCreate {
title: String,
body: String,
parent_task_id: Option<HarnessTaskId>,
},
TaskMove {
task_id: HarnessTaskId,
expected_revision: HarnessRevision,
to: HarnessTaskStateV1,
},
RunFinish {
outcome: HarnessRunFinishOutcomeV1,
summary: Option<String>,
},
}Variants§
ContextGet
MonitorGet
Fields
run_id: Option<HarnessRunId>TimelineRead
TasksList
Fields
after_task_id: Option<HarnessTaskId>state: Option<HarnessTaskStateV1>parent_task_id: Option<HarnessTaskId>“What did this task spawn”: restricts the page to tasks whose
own parent_task_id equals this one – direct children only,
never deeper descendants. Additive over the original bare
{ after_task_id, state, limit } shape, so #[serde(default)]
keeps an older caller decoding. Composes with state (both
filters apply together) and pages the same way via
after_task_id.
TaskGet
Fields
task_id: HarnessTaskIdRunsList
Fields
task_id: Option<HarnessTaskId>after_run_id: Option<HarnessRunId>lifecycle: Option<HarnessRunLifecycleV1>parent_run_id: Option<HarnessRunId>“What did this run spawn”: restricts the page to runs whose own
parent_run_id equals this one – direct children only. Additive
over the original shape (#[serde(default)]), composes with
task_id/lifecycle, pages the same way via after_run_id.
RunGet
Fields
run_id: HarnessRunIdOperationGet
Fields
operation_id: HarnessOperationIdTaskCreate
D5, Slice D: an agent creates a task under its own subtree –
parent_task_id: None means “under my own task”; Some must name
the caller’s own task or a strict descendant of it (checked
service-side, HarnessEngine::task_is_strict_descendant), never a
task system-wide the way the operator’s own HarnessCreateTaskRequestV1
can. Gated by grant.task_permissions.create. Every refusal –
unreachable parent, a terminal parent, or an invalid title/body/
dependencies – travels back as HarnessTaskCreateResultV1’s own
named variant, never a host error. This bound is the coarse
wire-level ceiling only; the authoritative title/body rule is the
engine’s own HarnessTaskV1::validate(), reached when the mutation
applies.
TaskMove
D5, Slice D: restricted service-side to a STRICT descendant of the
caller’s own task – never the task that governs the caller’s own
run (HarnessTaskMoveResultV1::TaskIsOwn). Gated by
grant.task_permissions.mutate. to names the operator’s own task
graph (validate_operator_move in hatchery-harness-service); an
illegal transition or a stale expected_revision is a named refusal,
never a host error.
RunFinish
S10: a session reports its OWN run finished – resolved from the
caller’s own grant binding (actor_run_id), the same field every
other agent verb resolves its identity from; there is no run-id
argument, so a session can never finish another session’s run.
done applies HarnessLifecycleProjectionV1::CompletedReview
(hatchery-harness-service), landing the task in Review –
never Done, the review gate a session cannot skip. failed
applies HarnessLifecycleProjectionV1::Failed and records a
retryable HarnessFailureV1. Never gated by any grant permission
(unconditional in allowed_tool_ids, the same way g4a_context_get
is): every session needs the ability to report its own work
finished regardless of what else its grant allows, or nothing ever
closes – the exact structural gap this verb exists to close.
summary is accepted on the wire for backward compatibility but has
no effect: it used to be posted as mail to the task’s own forum,
removed 2026-09-17 when the mailbox moved to its own service (see
hatchery-harness-service::read::execute_exact_binding_read’s
RunFinish handler). Not idempotent: a second call against an
already-terminal run is refused by name as
HarnessRunFinishResultV1::AlreadyFinished, never silently accepted.