Prepared-run authority
harn_vm::prepared_run reconciles everything a workflow needs with everything
its host can safely provide before execution starts. It is intended for product
hosts, headless runners, and hosted schedulers that embed harn-vm.
The host constructs a value-free RunIntent from the workflow's compiled
CapabilityPolicy and its additional network, secret-consumer, environment,
socket, MCP, budget, provenance, and startup requirements. HostFacts contains
observed ceilings and the canonical permission and network evaluators. Its
permission evaluator is a RunApprovalPolicy, constructed from one typed
RunAuthorityPosture: run interactivity, approval availability, and workspace
trust. Hosts use WorkspaceTrust::HostMaterialized for isolated workspaces they
created for CI, eval, scheduled, or hosted execution; this is a run fact, not a
durable per-path trust-store entry. permits_project_policy returns false for
WorkspaceTrust::Untrusted and true for Trusted and HostMaterialized.
Calling prepare yields one of three outcomes:
Readycontains an opaque fingerprinted lease and a persisted readiness receipt.NeedsApprovalcontains one fingerprinted batch, grouped into reviewable authority families.Blockedcontains actionable diagnostics, such as stale runtime provenance, unavailable approval, a secret-consumer mismatch, or a policy denial.
The first receipt event is persisted before host validation. A host must call
prepare before credential resolution, model calls, subprocesses, network I/O,
or process-sandbox installation. An executor passed to PreparedRun receives
only AuthorityUse; it calls authorize with the exact typed requirement
immediately before each material operation. Dispatch repeats the canonical
evaluation and rejects any requirement not fingerprinted into the lease.
Requested filesystem and process roots are authority to acquire, not concrete file effects in an existing workspace. Their policy evaluation retains authored path constraints and sensitive-path refusals, without treating the requested root as an existing workspace grant. Host ceilings, the exact approval batch, and the approved lease still control admission. Concrete tool dispatch uses its explicit workspace boundary and cannot use this internal acquisition interface.
PreparedRunExecutor has separate Output and Error associated types.
ExecutionOutcome::ExecutorFailed returns the concrete executor error beside
the terminal authority receipt, so hosts can retain structured partial-run
evidence without parsing a rendered string or rereading a shared event store.
ExecutionOutcome::AuthorityFailed is distinct: it reports lease validation
or receipt persistence failures owned by Harn. Existing string-only executors
use type Error = String; no adapter or side channel is required.
Agent executors call AuthorityUse::record_agent_terminal with the actual
producer's AgentTerminalOutcome before returning. Attached sessions expose
the same operation as ActivePreparedSession::record_agent_terminal. The
authority owner retains the decision in the optional receipt agent_terminal
field and projects its shared lifecycle before the terminal receipt is
persisted. Hosts do not rewrite authority receipts after execution.
Provider diagnostic message and detail are omitted from authority evidence.
Custom reasons use the producer's current journal redaction policy when recorded;
ordinary stop reasons and typed owner identity are retained.
| Producer lifecycle | Authority stage / status |
|---|---|
| Completed, executor succeeded | terminal / completed |
| Cancelled or stopped | stopped / stopped |
| Failed | terminal / failed |
| Suspended or otherwise unfinished | terminal / failed |
| Completed, executor failed | terminal / failed |
Suspension retains its producer identity but cannot claim completed work in a
finished generic invocation. An executor error outranks an earlier natural
terminal. With no recorded agent terminal, ordinary generic executor result
semantics remain in effect; absence does not imply a stop.
ExecutionOutcome::Completed means the executor delivered its output. Read
the authority receipt to determine whether that agent work completed, stopped,
or remained unfinished.
The normative JSON Schema for the normalized plan is
run-authority-plan.v1.json. The
serialized contract contains secret references and exact consumer bindings,
never secret values. AuthorityLease is deliberately not serializable;
receipts are evidence, not reusable authority.
Non-interactive hosts must advertise only secret brokers that both support non-interactive access and cannot invoke GUI-capable keyring APIs. Environment and dotenv credentials should be moved into a zeroizing process-local provider and scrubbed from the process environment before workload execution. Durable secrets remain behind a host broker outside the workload sandbox.
When a run is both non-interactive and unable to obtain approval,
RunApprovalPolicy resolves a winning ask from any rule, legacy pattern, or
repeat guard to a deterministic denial, unless an installed resolver can
answer it. Rule selection happens first, preserving explicit grants and
denials. The host's
construction callback receives the same posture and selects its workspace
policy layers from workspace_trust; it must not infer this fact from a path
layout.
Prepared execution installs this evaluator for live tool dispatch and inherited
worker scopes. Nested approval declarations intersect with the prepared
policy. Outside prepared execution, Harn constructs the same evaluator from
the active host bridge and approval reviewer. An unavailable approval is
reported with the approval_unavailable denial gate and its original rule in
the decision receipt.
Rust callers use current_run_approval_policy for decisions. The compatibility
reader current_approval_policy projects declarations for nested scopes and
worker transport. RunApprovalPolicy::effective retains the typed evaluator;
use declared when a ToolApprovalPolicy configuration value is needed.
discover_toolchain is the only command-derived root path. Preparation reviews
the exact command and a read-root ceiling, then persists readiness. Only after
that receipt exists may a host ToolchainProbeRunner spawn the command. Harn
turns every observed root or attempted operation into a typed lease delta. A
narrower process-read root is applied atomically and remains unused until
dispatch authorizes it. A wider path, network access, secret access, process
write, or budget change is refused and receipted without invalidating the
already reviewed parent lease. Interactive hosts receive one new grouped
decision and non-interactive hosts receive an actionable block; in either case,
the caller decides whether the unavailable discovery was optional or a startup
precondition. Missing toolchains, malformed probe output, and probe policy
denials likewise leave the parent lease executable. Integrity failures still
invalidate it: an expired lease, a probe outside the fingerprinted lease, or a
discovery receipt that cannot be persisted.
PreparedSession is the versioned, replay-safe host protocol around this
engine. prepare emits needs_approval, ready, or blocked; one persisted
approval decision converts the grouped request into a fingerprinted session
lease. attach binds that lease to the exact session, workspace, runtime
provenance, and consumer before engine startup. A durable
PreparedSessionLeaseStore atomically rejects replay across server processes.
Routine turns reuse the attached authority envelope without prompting again,
and stop, pivot, and terminal all persist terminal accounting. Accepted
Stop and pivot controls persist stage: stopped and status: stopped, retaining
the used and unused authority without classifying the control as executor failure.
The JSON Schema is schemas/prepared-session-v1.schema.json; generated Rust,
TypeScript, Swift, Python, and Go protocol artifacts expose the same states and
commands.
Embedded runtimes whose turn futures are not Send use
PreparedSession::run_turn_with(&active, turn). The future runs in the same
attached authority and identity scope as run_turn; the embedder calls
active.authorize before each material operation. Returning from a turn keeps
the session attached. Its accepted lifecycle event calls finish or stop to
persist terminal accounting and retire the lease.
ACP embedders implement AcpRuntimeConfigurator::run_prompt to scope that
future on the server's engine executor. The context identifies the session and
workspace, exposes Harn's resolved capability policy and the existing host
bridge, and reports accepted cancellation. Refusing before polling the future
prevents VM, host-capability, and provider execution. Provider endpoint overrides
preserve this configurator. The adapter still owns prompt responses, event
flushing, and cancellation classification.
request_session_approval(&bridge, session_id, &batch) projects a grouped batch
through the attached ACP permission bridge. It uses Harn's canonical permission
options and response parser; missing, malformed, and rejected answers cannot
grant authority. Pass its decision to PreparedSession::decide, which verifies
both the request ID and semantic batch fingerprint, then persists the decision
before attachment or execution. Each batch has a fresh request ID even when its
semantic content is identical. Preserve that ID in the decision; an older Allow
or Deny cannot consume a replacement request.
The helper rejects a bridge attached to another session before requesting any
host decision.
PreparedRun::request_delta remains the typed attenuation interface for a
single prepared run. PreparedSession::request_delta adds the interactive
session behavior: an identical requirement is already covered, attenuation is
immediate, and widening produces one fingerprinted semantic approval batch.
Delta decisions likewise require the exact request ID and active parent lease.
Only the exact approved widening joins the active envelope; a denial leaves
the existing session usable.
SDK profiles, workload identity, instance metadata, and hosted credentials use
ConsumerBoundIdentityBroker. RunAuthorityPlan.v1 records only a
harn-identity:// reference plus exact broker, source, renewal, provider,
audience, tenant, and consumer facts. A host advertises whether the broker is
non-interactive, GUI-capable, host-isolated, renewing, and able to return
opaque process-local handles for that exact binding. Changing any binding fact
blocks readiness before broker acquisition or provider spend.
OpaqueIdentityHandle is non-cloneable and non-serializable. Its zeroizing
material can be consumed once through the complete fingerprinted requirement;
the handle rejects a different provider, audience, tenant, consumer, or broker.
Local and hosted adapters implement the same broker interface while retaining
custody of their own durable stores. At provider dispatch Harn re-reads broker
facts, acquires the handle, and marks identity used only after the exact
consumer successfully opens it. Broker-managed identities get one
reacquisition when a handle expires. Bedrock and Vertex cannot fall back to
ambient SDK, profile, metadata, environment, or credential-file chains inside
a prepared session; calls outside one retain their compatibility resolvers.
Every terminal receipt records requested, granted, used, denied, and unused authority, along with its decider and canonical policy-decision evidence. A receipt never grants authority and must not contain secret material.