Skip to content

0025: Goal supervision is an explicit bounded host

Status: accepted (2026-07-22) · Scope: product tier (core/governor, governor CLI, dashboard, workflow specialist profiles)

Harnery can run a bounded multi-agent workflow and can preserve a durable work objective across attempts. It does not yet connect several dependent work items into a foreground loop that repeatedly discovers ready work, dispatches it, reviews proof, and stops for governance or safety limits.

Putting that behavior inside the work reconciler would break its observational contract. A read or repair command could unexpectedly spend usage, mutate a repository, repeat an external side effect, or accept work. Keeping one model session alive indefinitely would also make correctness depend on context compaction and process lifetime rather than durable records.

The missing layer is an explicitly invoked host above durable work. It needs a frozen team contract, objective-level bounds, restartable projection, and clear stop reasons. It does not need a mandatory daemon, mutable task board, or unbounded recursive agents.

Add the product-tier harnery/core/governor module and harn governor command. A governor intent is created once under .harnery/governors/<goal-id>/intent.json with private permissions. It freezes:

  • one root durable-work ID whose immutable dependency closure is the goal graph;
  • named specialist profiles with bounded instructions and optional adapter, model, effort, turn, timeout, and schema-retry defaults;
  • run limits for governor cycles, wall time, graph-wide attempts, parallel work items, agents per work item, and child-agent concurrency;
  • explicit automation policy for accepting passing proof, resuming resolved approvals, and retrying blocked work.

Workflow agent() calls may name a specialist. The engine resolves the frozen profile before dispatch, prepends its instructions to the assignment, records the specialist in the transcript and proof-facing agent record, and includes the resolved profile in call identity. A workflow run manifest freezes the complete specialist map so approval resume cannot pick up changed team behavior.

harn governor tick <goal-id> performs at most one bounded cycle. harn governor run <goal-id> repeats cycles in the foreground. Each cycle:

  1. reconstructs the root dependency closure from work intent and reconciles it;
  2. stops for pending approvals, reviews not authorized for automatic acceptance, blocked work not authorized for retry, cancellation, malformed evidence, exhausted budgets, or lack of progress;
  3. records authorized acceptance or selects ready/resumable/retryable work;
  4. dispatches at most the frozen parallel-work limit and lets each work lease serialize its own attempt;
  5. reconstructs all state again from work transcripts and proof before deciding whether another cycle is legal.

The governor has an exclusive crash-recoverable lease, but no mutable status file. Its projection and reports are derived from immutable governor intent plus the work ledger. Restarting run after a process loss continues from those records. It never keeps a model process alive merely to preserve role identity; specialist roles are durable configuration and child sessions remain bounded leaf processes.

Expose the same read-only projection at /governors and /governors/<goal-id>. The dashboard imports a state-only package subpath so rendering goal state does not bundle the workflow execution engine.

Automation defaults fail closed. Passing proof still enters in_review unless the immutable governor policy explicitly authorizes acceptance. Blocked work is not retried unless the intent explicitly authorizes it, and the work item’s own attempt ceiling plus the goal-wide attempt ceiling still apply. Resolved approval resume is separately configurable and never bypasses the recorded approval decision.

  • Make reconciliation execute its next_action. Rejected because callers rely on reconciliation being safe to run for inspection and recovery.
  • Run an always-on background daemon. Rejected as a required runtime. A host may schedule the foreground command, but ledger correctness cannot depend on daemon liveness.
  • Use one long-lived model session as the governor. Rejected because process death and context compaction would become state-loss mechanisms.
  • Let a planner dynamically rewrite the graph in the first schema. Deferred. The initial static dependency closure is auditable and enough to prove safe scheduling; append-only graph expansion needs its own provenance and cycle semantics.
  • Retry every failed attempt automatically. Rejected as the default because repeated execution may duplicate side effects or repeat a deterministic defect. Explicit immutable policy can authorize bounded retry.
  • Allow specialist profiles to remain runtime-only. Rejected because a parked workflow could resume under changed instructions or model settings.
  • Goal continuity lives in private records rather than model context.
  • The initial graph is static: create prerequisite work first, then the root, then the governor intent. Dynamic planning is a later additive layer.
  • Parallel work items each enforce their own child concurrency, so the maximum simultaneous child count is parallel_work × agent_concurrency.
  • isolation remains a host declaration; the governor does not create a worktree or sandbox. Shared-checkout children still use Harnery’s normal coordination and claim guards.
  • Automatic acceptance means the governor writes an explicit governance event as its named actor after fully passing proof; it is not a reconciler side effect or an inference from process exit.
  • Specialist adapter is optional and inherits the run default when omitted. Harnery does not auto-spread across adapters; see the addendum below.

Addendum: pin or inherit, no auto-spread (2026-08-03)

Section titled “Addendum: pin or inherit, no auto-spread (2026-08-03)”

The optional adapter field on a specialist profile means “pin this role to that seat.” It does not mean “pick a seat for me.” Resolution is:

opts.adapter ?? profile.adapter ?? default_adapter

A team that omits every pin therefore lands every child on one adapter. That is the contract, and it has always been the contract. What was missing is that omitting the pin is silent: a six-specialist team reads as multi-adapter work and behaves as single-adapter work.

Under metered billing that concentration is a cost curve. Under subscriptionOnly it is a cliff: one seat’s session meter carries the whole team, so when that seat hits its limit every specialist stops at once. A run that burned one subscription seat for about ninety minutes while two other attested adapters sat idle is what made the silence expensive.

Two responses were considered.

Auto-spread (round-robin / least-recently-used / per-role defaults when adapter is omitted) was rejected. Silently overriding an author who meant the default would hide the same miss under a different failure mode, and it would also hand children to a registered-but-dead seat. Reachability is not registration.

Refuse at governor create was chosen. The check is narrow on purpose (false refusal is worse than the miss) and fires only when all four hold:

  1. more than one specialist,
  2. every specialist resolves to the same adapter,
  3. subscriptionOnly is on,
  4. another adapter is attested reachable (via harn adapter attest, not the registry).

Condition 4 is load-bearing. Counting declared adapters would recommend a seat that cannot start; every child handed to it would fail closed. Attestation is the only record that an adapter completed a real turn on this machine.

The refusal happens at create because the intent freezes with no amend path. Discovering it at run time means recreating the goal. --allow-single-adapter is the opt-out when one seat is what you want.

Operator-facing write-up: governor CLI → Every specialist on one adapter. Implementation: src/core/governor/adapter-spread.ts.