Proposal 073: Agent — Bounded Stateful Orchestration Organ¶
Promoted to:
doc/project/60-solutions/047-agent/047-agent.md
Status¶
promoted
Date¶
2026-06-26
Executive Summary¶
Orbiplex should introduce Agent as the node organ for stateful, bounded,
multi-step orchestration that sits above Inquirium. An Agent is a durable,
addressable entity that binds a model-selection policy, a remembered session
context, parameters, a budget, and a bounded controller loop, with an explicit
lifecycle: spawn, fork, suspend, resume, stop.
An Agent composes other organs and owns none of them. It calls Inquirium for inference, declares bounded observation needs and effect proposals through horizontal contracts, and uses Memarium-backed durable memory (not the agent's hot working/KV memory). The host resolves those ports through the owning domains and owns authority, budget, and lifecycle. This realizes the agentic mode — an entity with an attached model, remembered context, and parameters, plus actions that multiply or stop agents — that Inquirium deliberately excludes:
"In Orbiplex, Inquirium is not the agent loop. … Flow, Arca, Sensorium, and the host own broader orchestration." — Proposal 063
Agent is that missing home, defined so that no model ever gains ambient authority.
The governing rule is:
Agent is the bounded controller with identity, memory, and a lifecycle.
Inquirium answers; Memarium remembers; the host resolves observations and effects.
The agent declares needs, proposes effects, and orchestrates; it never selects an
authority path or self-authorizes an effect.
Context and Problem Statement¶
Inquirium is bounded inquiry and is explicitly not the agent loop (Proposal
063; Proposal 064 invariant "conversation orchestration is not an Inquirium
adapter concern"). Proposal 064's Flow IR permits only an inline bounded
controller (max_steps, max_cost, max_time, allowed_tools,
termination_condition, review policy). Proposal 066 assigns agentic effects to
this capability-gated Agent layer rather than to Inquirium or its adapters.
Yet real workflows need a stateful agent: an entity that remembers a session, holds parameters, runs several inference steps toward a goal, may spawn helpers, and can be stopped. Today that entity has no home. Putting it inside Inquirium would make a model adapter an ambient agent — the named threat "Inquirium becomes a general AI agent with ambient authority" (Proposal 063). Leaving it ad hoc invites the classic agent failure modes: unbounded loops, fork bombs, orphaned state, runaway cost, and effects without accountability.
Agent gives that entity one durable, host-owned, auditable home with an explicit lifecycle and authority that is bounded by construction.
Goals¶
- A first-class, durable, addressable
Agentabstraction binding model-selection policy, remembered session context, parameters, budget, and a bounded controller. - Explicit lifecycle operations
spawn,fork(multiply),suspend,resume,stopas host capabilities — budget-metered, ledgered, fail-closed. - Strict stratification: Agent uses horizontal inference, observation, effect, memory, and causal contracts; the host composes them with Inquirium, Sensorium, Workbench, Memarium, and other vertical domains. Neither side acquires the other's authority or implementation vocabulary.
- Bounded by construction: monotone narrowing on fork, bounded fan-out, enforced budget, mandatory termination, no self-authorizing agents.
- Full causal trace: every step, spawn, effect proposal, and lifecycle transition is an auditable, prompt-free fact.
Non-Goals¶
- Not an inference engine (Inquirium), effect engine (Sensorium), memory store (Memarium), or authority root (host).
- Not ambient autonomy and not a general AI agent with standing authority.
- Not a replacement for Flow IR's declarative DAG; the two are complementary (an Agent may run a Flow; a Flow may spawn an Agent).
- Not a cross-node/federated agent runtime in this slice (deferred).
Decision¶
1. Agent is a stateful organ above Inquirium¶
An Agent is a durable record plus a host-run controller. It binds, by
reference, everything an agentic session needs, and nothing it must not own:
Agent {
agent/id
agent/parent? # lineage for forked/spawned agents
model-selection # profile/ref or runtime-candidate constraints;
# host-owned binding, never a raw provider key
session/ref # Memarium-backed remembered context (durable facts)
params # AssistantMode (ModeKeyed), plurality, classification
# ceiling, instruction profile (PromptAssemblyPolicy)
budget # token / cost / wall-time / step ceilings (enforced)
controller # bounded loop policy (see 3)
grants[] # capability ids this agent may request (gated)
trust/locality # default local-only / strict_local
lifecycle/state # pending | running | suspended | completed
# | stopped | failed
}
The boundary is hard: Inquirium has zero knowledge of agents. The Agent calls
inquirium.generate (and future operations) as a normal host-capability caller,
subject to the same classification, inference grants, and trace discipline as any
other caller. Inquirium output remains evidence, never authority.
The same boundary applies to collaborative rooms. A model-backed participant in a Room or Corpus deliberation is represented by an Agent controlled by an accountable subject or node role; a raw Inquirium adapter or model runtime is not a room member. If a deployment wants a one-shot model respondent, it should use a degenerate Agent profile with one step and an explicit budget rather than admit the adapter as a speaking actor.
2. Lifecycle: spawn, fork, suspend, resume, stop¶
Lifecycle operations are host capabilities, not Inquirium operations. The
node-local slice registers agent.spawn, agent.status, agent.stop,
agent.fork, agent.suspend, and agent.resume in the Capability Registry
(Solution 037). Every mutation carries an idempotency key and is admitted by the
host before an append-only lifecycle command/state fact is written. The command
fact is the commit marker and authoritative replay record; the state fact is its
rebuildable audit projection, so a partial multi-fact write cannot lose the
idempotency decision. Local control retains administrative authority. A module
caller is admitted only when its JSON-e Flow configuration contains a separate,
bounded agent_grants entry for the exact agent.* capability; allowed_calls
alone is syntax, not authority. Request-size, Agent-id-prefix, profile, and
delegated-capability bounds are checked before lifecycle or binding admission.
agent.spawn { spec | template/ref, budget, grants } -> Agent (pending)
agent.fork { agent/id, narrowing } -> child Agent
agent.suspend { agent/id } -> suspended
agent.resume { agent/id } -> running
agent.stop { agent/id, reason } -> terminal
agent.status { agent/id } -> read-only projection
State machine:
pending -> running -> { suspended <-> running } -> completed | stopped | failed
In the current node-local slice, lifecycle mutations are authoritative and
exactly replayable from durable command facts: an exact retry returns the prior
result while reuse of an idempotency key with a different request fails closed.
suspend freezes the controller while preserving its fact projection; resume
continues from the latest durable state rather than replaying a prompt. Terminal
state and TTL reaping are durable. The current controller has no detached
background step to cancel: suspend or stop prevents the next passage. Agent-owned
leases are persisted in the existing model-runtime lease registry and released
on synchronous effect completion, terminal controller state, explicit stop, TTL
reaping, or startup reconciliation. A deferred effect retains its lease until a
bounded scheduler observes terminal status in the shared Deferred Operation
Registry, or until Agent termination or lease TTL. Exact dispatch replay returns
the durable deferred or terminal projection without reinvoking the target. The
reconciler advances a bounded fairness cursor through the recovered candidate
projection so an early page of live operations cannot starve later terminal
ones; durable facts, not that disposable cursor, remain the restart source of
truth.
Unused child budget is returned by rebuilding the reservation projection from
durable child state and metered spend: a live child retains its bounded
allocation, while a terminal child retains only spent budget and still-live
descendant commitments.
3. Multiplication is monotone narrowing with bounded fan-out¶
agent.fork is the "multiply" action, and it can only narrow. On every axis a
child is a subset of its parent: grants ⊆ parent.grants, classification ceiling
no higher, autonomy no looser, allowed_tools ⊆ parent. The parent's budget is
split, not duplicated — a child draws from a reserved slice of the parent's
remaining budget. This mirrors the monotone discipline of ClassKeyed/ModeKeyed
and PromptAssemblyPolicy: a lower scope may specialize, never widen.
Fan-out is bounded by construction to prevent fork bombs and resource exhaustion:
controller {
max_steps
max_depth # spawn-tree depth cap
max_children # direct children per agent
max_concurrent # live descendants across the tree
aggregate_budget # whole-tree token/cost/time ceiling
termination_condition # mandatory; an agent with no terminator is rejected
review_policy # when a human gate is required
}
There are no self-authorizing agents: an agent cannot grant itself a capability, raise its own budget, or spawn a child with authority it does not hold.
4. Agent state is durable facts, not mutated objects¶
Session seeds and lifecycle transitions are append-only facts in Memarium
(Proposal 036), not mutated in place. This gives as of queries, audit, and
replay: the trajectory of an agent — what it knew, decided, spawned, and stopped
— is reconstructable. The live controller holds only a cache derived from those
facts; the facts are the source of truth. resume and crash recovery both rebuild
from the same fact stream.
Memory follows the MemoryPolicy from Proposal 064: pinned facts (never
auto-summarized), a bounded rolling summary, and a host-pinned recall allowlist —
so context does not grow without bound.
Memory model: durable plane vs working set¶
Memarium is the agent's durable, governed memory — the source of truth — not its hot working memory. The two are distinct strata and must not be conflated:
durable fact plane (Memarium) source of truth: governed, classified, "as of",
| MemoryPolicy projects v auditable, replayable, optionally federated
working set / assembled context ephemeral, per-step, token-bounded
| rendered into v
provider KV / prompt cache optimization, runtime/provider-side, discardable
Two consequences:
- Memarium is off the hot path. The agent reads through a projection (the
working set built by
MemoryPolicy) and writes only meaningful facts — turns, results, decisions, observations — never the KV cache token by token. This keeps the per-step path fast and the governed log free of bulk or ephemeral content (Proposal 066:memarium.writestays a fact-plane). - Degraded mode mirrors the assistant. When Memarium is disabled at startup, the agent runs on a local ephemeral, non-federating fact store and reports that durability explicitly in status. When a configured Memarium write fails, the mutation fails closed rather than silently changing durability. A later transition between these modes requires an explicit reconciliation protocol; the current process does not switch sources of truth dynamically.
By memory type: the working set is working memory (KV-like, ephemeral); Memarium holds episodic (this session) and semantic/long-term (across sessions) memory; procedural memory lives in grants and templates, not Memarium.
5. Observations are needs; effects are proposals; inference is evidence¶
A controller step may declare an AgentObservationNeed containing an opaque
source/ref, expected payload/schema-ref, and age/byte bounds. A durable
AgentObservationBinding fixes which need and source a consumer-authorized Agent
may use. agent-core does not know whether that source is a Sensorium Interface,
Room projection, Workbench view, or a future domain. The daemon composition root
selects the resolver, rechecks its domain authority, validates the payload at the
schema gate, and returns bounded inert context plus prompt-free
AgentObservationEvidence carrying the source P081 causal/context plus distinct
source-version and resolution references.
Observation evidence may additionally carry a bounded list of opaque contextual
qualifiers as (schema/ref, value/ref, digest) tuples. This keeps agent-core
substrate-neutral: it does not learn the Sensorium operational-impact vocabulary or
interpret a Workbench environment. The daemon resolver validates each qualifier in
the owning domain and supplies only admitted refs and digests to Agent state and
prompt-free traces.
For sensorium-operational-context.v1, the composition root must resolve the
qualifier before exposing the associated observation payload to an Agent passage.
It computes a local caution class as the maximum of the source-published class and
any stricter local policy floor, then asks the host-owned Inquirium prompt assembly
boundary to render a fixed, versioned caution layer. The layer is present before the
first inference step that can consume the feed and before every later passage whose
working set includes it. A remote context/summary remains retrieved data below the
instruction hierarchy; it is never promoted into a system or developer instruction.
The composition root also records a deterministic host-owned provenance object with
the local policy ref, local floor, selected class, and each admitted source class
paired with its exact qualifier digest. It passes the same bounded projection directly
to the durable Inquirium trace rather than reconstructing it from caller metadata or
provider output. This evidence distinguishes a source-published high-impact class from
a stricter class selected by local policy without teaching agent-core the Sensorium
vocabulary.
Missing, malformed, stale, or descriptor-inconsistent operational context fails the
collaborative-live observation resolution closed. When a future passage admits more
than one live source, the host uses the maximum caution class while retaining every
per-source qualifier ref and digest for audit; it does not persist a second
authoritative effective-* wire field. This context changes reasoning posture, not
effect authority: all effect proposals still pass their normal grant, lease, policy,
and human-review boundaries.
Stale is not an Agent-owned timeout. It means exactly that P082 reports a source
generation mismatch or a superseded interface publication. Agent Core neither reads
source clocks nor derives freshness from passage age. The optional summary is
already bounded by P082 to 512 UTF-8 bytes and remains untrusted observation data.
A controller may also propose an effect. The agent never executes one directly
and never chooses the provider or authorization path. The daemon maps the generic
proposal to a closed host adapter such as Sensorium or Artifact Delivery and
enforces grants, leases, classification, quarantine, and human-in-the-loop policy.
Sensitive classes (relationship, governance, external publication, egress)
require operator approval, inheriting Proposal 066's Phase 3 contract. An
Inquirium Plan return remains a CandidatePlan the host compiles or rejects
(Proposal 064); the agent is the durable, addressable form of that same host-first
orchestration, not an escape hatch around it.
JSON-e Flow may define only static declarative wiring: an operator-authored,
schema-validated, digest-pinned mapping from need/ref to opaque source/ref,
schema, and bounds, plus separately admitted grant requests. Rendered flow data
may select or narrow a predeclared mapping but cannot create or widen one. Agent,
model, or observation output must never interpolate an authority-significant
wiring field. After caller-capability and ownership checks, the daemon must prove
that every exact source/ref plus payload/schema-ref pair has one registered
resolver before persisting a binding; absent, incompatible, and ambiguous pairs
fail closed. Authorization, classification, source interpretation, and effect
semantics remain compiled host code. Every successful resolution emits a stable
resolution/ref and preserves the validated source causal/context in the Agent
trace. Step facts and traces bind that evidence to the enclosing agent/id,
binding/ref, and canonical passage ref. The resolution ref makes the selected
binding auditable; the causal context preserves the source chain without retaining
payload bytes.
6. Stratification and crates¶
agent-core (thin contract crate)
- Agent / controller / budget / grant DTOs
- substrate-neutral observation need/binding/evidence and effect-proposal DTOs
- lifecycle state machine + monotone-narrowing validator
- depends on horizontal P081, classification, serde/error, plus one explicit
vertical exception: pure inquirium-core request/result DTOs for the Agent's
constitutive bounded-inference operation
- the Inquirium exception carries no host, provider, runtime, or authority code
- MUST NOT import Room, Corpus, Memarium, Sensorium, Workbench, or other
provider-specific source/effect types
- MUST NOT depend on substrate (daemon, model-runtime, HTTP, async, SQLite),
enforced by a positive direct-dependency allowlist plus vertical dependency
and vocabulary checks
daemon (substrate)
- agent.* host capabilities and the bounded controller runtime
- composition-root resolvers from opaque observation/effect refs to owning domains
- durable agent/session store (Memarium-backed) + spawn-tree budget metering
- schema-gate validation, capability/HIL gating, lease lifecycle, decision ledger, trace
Implementation Recommendations¶
Implement Agent as a stratified host organ, not as an Inquirium operation, model adapter, Flow shortcut, or ambient daemon side loop. The first runtime slice should use a daemon-owned controller that may call Flow IR for bounded sub-steps, but the controller lifecycle, authority checks, budget metering, and stop/suspend/resume semantics remain host-owned. This keeps one orchestration substrate responsible for live agent state while still allowing declarative Flow plans to be one of the things an agent executes.
Build the implementation in layers:
- Keep
agent-coreas the substrate-free contract crate: DTOs, validation, lifecycle state machine, monotone fork validator, generic observation/effect port values, and schema constants only. It must not gain Sensorium, Workbench, provider, daemon, model-runtime, HTTP, async runtime, SQLite, or store dependencies. - Add the daemon host facade and local-control surfaces for the smallest useful
lifecycle:
agent.spawn,agent.status, andagent.stop.fork,suspend,resume, effects, and assistant escalation come after this slice can create, inspect, stop, and audit a bounded local agent. - Persist lifecycle transitions as append-only facts. The live controller may keep an in-memory working projection, but that projection is cache-like and disposable. It is not Memarium, not authority, and not required for crash recovery semantics.
- Add budget/fan-out enforcement before enabling
forkor effect proposal routing. A fork without budget split and monotone narrowing is not an agent feature; it is a fork bomb waiting for policy. - Route effects only as generic proposals through closed daemon adapters and existing host capabilities. Agent output may ask for an effect; the host and operator remain the authority that admits, denies, delays, or scopes it.
- Keep JSON-e Flow at the wiring layer. Static, digest-pinned configuration may map a need to an opaque source and declare grant requests; it must not evaluate authorization, classification, source semantics, or agent-generated wiring.
The first implementation slice is node-local only. Cross-node or federated agents are explicitly deferred to a later proposal and must not leak into the first controller through remote spawn, remote resume, or federated state replication. A local agent may call existing federated organs through explicit capabilities, but the agent lifecycle itself is local.
Memarium is the durable fact plane, not the live cache. The first working set should be an in-memory / ephemeral projection derived from the agent request and any admitted local facts. A dedicated projection cache may be introduced later if profiling shows the need, but it should be a rebuildable optimization with clear lifecycle, not a second source of truth.
Explicit non-goal: do not dump the in-memory runtime cache to disk and reload
it verbatim on restart. That would make the ephemeral projection a second
source of truth by the back door. The only sanctioned path to surviving a
restart is agent-durable-state (append-only agent.state.v1/agent.session.v1
facts) plus agent-memory-projection (rebuilding the working set from those
facts) — never a serialized snapshot of the cache itself.
The current implemented slice has a Memarium-backed append-only fact store and a disposable in-memory projection. Lifecycle commands, session seeds, state, initial steps, budget traces, effect proposals, and effect outcomes survive a restart when Memarium is enabled. Exact lifecycle retries rebuild their idempotency result from those facts. If Memarium is disabled, status reports an ephemeral, non-federating mode rather than pretending crash recovery exists.
Active lifecycle capabilities require explicit authority. Local control is the
administrative path; module calls require one exact agent_grants entry in the
calling JSON-e Flow configuration, and lifecycle operations are additionally
restricted to Agents created by that module. Binding and effect-dispatch grants
carry an explicit target-capability allowlist. Mutations preserve either
local-control or the concrete caller module id in lifecycle facts. The rebuilt
idempotency projection has a fail-closed bound: once its configured capacity is
reached, new mutations are denied rather than evicting replay evidence and
making duplicate execution possible.
Use conservative, overridable developer defaults for the first profile:
max_steps = 8
max_depth = 1
max_children = 0 or 1
max_concurrent = 1
wall_time_ttl = short, deployment-configured
These defaults are a safety floor, not a constitutional constant. Distributors and operators may override them in agent configuration, but widening must remain explicit, validated, and visible in status/trace. The default profile should reject agents without a termination condition, agents with unbounded budget, unknown capability grants, or effects that try to execute without a host grant.
Minimum test matrix for the first slices:
- lifecycle state-machine transitions, including invalid transition denial;
spawn/fork/suspend/resume/status/stoplocal-control E2E with exact mutation replay and conflicting idempotency reuse denied;- unknown fields and missing termination condition fail closed;
- classification ceiling defaults fail closed;
- no ambient capability: an agent without a grant cannot invoke Inquirium or propose effects;
- no vertical-domain dependency or vocabulary in the Agent observation/effect port, and no dynamically interpolated observation binding;
- binding admission refuses absent, schema-incompatible, or ambiguous resolvers, and observation evidence cannot be moved across Agent, binding, or passage;
- monotone fork denial for widened grants, classification, autonomy, tool set,
or budget once
forkis enabled; - bounded fan-out defaults prevent more than the configured children/concurrency;
- prompt-free step/status traces contain refs, digests, budget deltas, and decisions, but not prompt text, model output, or raw context.
Controller as a functional core (agent-host)¶
The "daemon-owned controller" above should follow the same functional-core /
imperative-shell split already used by inquirium-host: the per-step controller
decision is a pure value computed in an agent-host service stratum, and the
daemon performs the effects. Each tick produces an agent.step-decision.v1:
agent.step-decision.v1 {
step/no
action # call-inquirium {request-ref, observation-need?}
# | propose-effect {proposal-ref}
# | spawn-child {child-spec-ref} | await-human | complete | fail
budget-charge
termination-satisfied
}
The daemon executes the chosen action and feeds the result back; the decision
itself is replayable and unit-testable without sinks. This keeps the agent loop
from accreting daemon coupling, mirroring the Inquirium decoupling. Stratify as
agent-core (contracts + state machine) → agent-host (pure step decisions plus
read-ports) → daemon (effects, persistence, budget metering), guarded by a
dependency-direction lint.
expected-step prevents replay after a committed passage, while proposal and
fork actions retain their own exact idempotency identities. A remote model
provider call cannot honestly promise exactly-once execution unless that
provider accepts and enforces the stable request identity. The host therefore
uses a stable request/ref, idempotent budget accounting, and content-addressed
product storage; an adapter SHOULD forward provider-native idempotency when it
exists. Implementations MUST NOT describe this boundary as exactly-once merely
because the local step commit is replay-safe.
Step 0 is a durable bootstrap projection and does not consume runtime step
budget. Explicit controller ticks start at 1; each consumes exactly one step,
checks the absolute wall-time deadline and remaining host-owned budget, and
stops the bounded run on await-human or a terminal decision. A waiting Agent
is never polled merely because scheduler time passed.
Lifecycle requests carry an idempotency/key: a retried spawn/fork must
replay the prior result, not create a second agent or a second child.
Consumer binding (collaborative chair/participant, assistant, Flow node)¶
Agent is driven by domain consumers, not invoked bare. The recurring shape is one
binding contract, agent.binding.v1, that attaches an agent to a consumer's
session and output sink under narrowed authority:
agent.binding.v1 {
binding/id, agent/ref
consumer/kind # collaborative-chair | collaborative-participant | assistant-channel | flow-node
consumer/ref # query/id (Corpus) | session/ref (assistant) | flow/node-ref
session-source/ref # room/ref | transcript/ref | dataset/ref (ref vocabulary)
output-sink/kind # collaborative-answer-draft | collaborative-turn-draft | assistant-response-draft | flow-result
grants[] # MUST be a subset of the consumer's own grants
budget # from the consumer policy (deliberation budget / assistant rigor)
participant/ref? # host-minted accountable principal; never model identity or model-supplied
membership-attestation/ref? # room-membership-attestation.v1 for Corpus bindings
membership-attestation? # inline create-time evidence; verified, never persisted in the binding
human-in-loop # approval policy for effect proposals
}
Invariants:
- Grants are monotone-narrowing from the consumer. A consumer cannot grant the
agent more authority than it holds — the same discipline as
fork(validate_fork_from). Corpus and the assistant narrow; they never widen. - The agent is a Room participant, never a raw model adapter. For
collaborative-chairorcollaborative-participant, the Corpus adapter joins the agent to the deliberation room throughroom-membership-attestation.v1(Solution 036). Binding creation carries the complete signed credential as boundary evidence; the host verifies its schema, signature, freshness, room, participant, required grants, deadline, and issuer authority, then persists only the content-addressed attestation ref. The node-local first slice requires the signer to equal the local Corpus round authority; later remote authorities must be admitted by explicit Room policy. Its contributions are room facts signed by its principal, satisfying Proposal 069's "no raw model adapters as room participants". - Output is a draft, not an effect. The agent produces a content-addressed
product (
agent.outcome.v1); the consumer admits it (Corpus stores an inert answer draft before any separately chair-signed final answer; the assistant surfaces a response draft). The agent never publishes or settles on its own. - Assistant escalation approval is not draft-render approval. The operator's
explicit approval authorizes creation or binding of the bounded Agent. Once that
approved binding produces a valid
assistant-response-draftfor the samesession/ref, the Assistant Channel may render the draft without asking a second operator question. Rendering is not publication or effect authority: schema, digest, classification, binding, session, and output-sink validation remain fail-closed, while every proposed effect and any external publication continue through their own capability and human-in-loop gates.
Reuse, do not reinvent: agent context comes through the existing
inquirium.context-assembly.request.v1 plus context-source grants and
MemoryPolicy (Proposals 064/066), so the agent reads context through the same
classification/grant gates rather than raw; human-in-the-loop for an effect
proposal reuses inquirium.operator-question.request.v1 (Proposal 066) rather than
a new approval surface; durable facts use the memarium.write fact plane.
Data Contracts¶
agent.spec.v1— declarative agent specification (model-selection, params, budget, controller, requested grants).agent.state.v1— lifecycle transition fact (state, reason, at, by).agent.session.v1— durable session seed binding the validated spec, selected runtime profile, creation command digest, actor, and expiry. Pinned facts, summary refs, and recall refs belong to the separate memory projection tracked below; they are not silently embedded in this lifecycle seed.agent.memory-policy.v1— one immutable, digest-bound revision of the host-ownedMemoryPolicy. It carries bounded pinned facts, an optional summary produced by a non-Agent component, and the recall-ref allowlist. Summary production remains the responsibility of that external component or Flow; neither Agent nor Inquirium silently summarizes its own history.agent.lifecycle-command.v1— durable idempotency fact for lifecycle mutations, binding operation, request digest, actor, result state, and related child where applicable.agent.step.v1— the durable step fact after execution or denial: the decision taken, the effect outcome, budget spent, evidence/effect refs, and the causal predecessor step. Distinct fromagent.step-decision.v1, which is the pure decision computed before the effect.agent.spawn.request.v1/agent.spawn.response.v1/agent.fork.request.v1/agent.suspend.request.v1/agent.resume.request.v1/agent.stop.request.v1/agent.stop.response.v1— lifecycle mutation request/response bodies.agent.status.request.v1/agent.status.response.v1— read-only lifecycle and budget projection.agent.step-trace.v1— prompt-free operational trace (step count, budget spent, model snapshot, instruction hash, spawn/effect refs; no prompt, output, or context content).agent.binding.v1— how a domain consumer (Corpus chair, assistant, Flow node) attaches an agent to a session source and output sink under narrowed grants (see Consumer binding).agent.assistant-escalation.request.v1/agent.assistant-escalation.v1/agent.assistant-escalation-decision.v1/agent.assistant-escalation.response.v1— the explicit, idempotent Assistant Channel escalation ceremony. The request binds an inert assistant proposal to one node-local Agent spawn and one same-session Assistant Channel binding; the durable host facts retain delegated authority and the operator's approved, denied, or timed-out decision. No assistant turn or model control creates a binding ambiently.agent.effect-proposal.v1— an agent's immutable request to invoke a host capability:proposal/ref,capability/id,args/digest, a validatedclassificationvalue (or store-side equivalent reference where the envelope owns the value), prompt-freereason/code, optionalevidence/refs, andrequires-human-in-loop. The proposal is a fact and is never mutated.agent.effect-proposal-outcome.v1— a separate host-authored fact, joined to the proposal byproposal/ref, recording the decision:outcome(admitted|denied|deferred|superseded|completed|failed),decided-by,at, and the fields appropriate to that transition. An execution-deferred outcome bindseffect/ref,operation/ref,result/digest, and boundedlease/refs; a terminal execution outcome retains the same causal binding. The outcome is a fact about the proposal, not a field inside it (facts over overwriting).agent.outcome.v1— the terminal product a consumer picks up: terminal state,product/kind, content-addressedproduct/ref(a draft, never inline),budget-spent, andtrace/ref.agent.assistant-draft.accept.request.v1/agent.assistant-draft.acceptance.v1/agent.assistant-response-draft.v1— a same-session, local-control acceptance boundary overagent.outcome.v1. Acceptance verifies the binding, sink, content-addressed product and classification before projecting a render-only draft. The acceptance fact fixespublication-authorized = false; publication remains a separate capability-owned effect.agent.step-decision.v1— the pure, replayable controller decision computed byagent-hostfrom read-ports before any effect; the daemon executes the chosen action and records the result as anagent.step.v1fact.
Effect dispatch follows the same stratification. agent-host owns a closed,
table-driven registry that validates each supported target capability and emits a
transport-independent execution plan. Its fields are private, the plan has no
deserialization path, and daemon admission consumes the plan as one value, so
callers cannot construct an equivalent-looking value while bypassing the policy
registry. Sensorium directives bind issuer.module_id to the authenticated
module or the explicit local-control actor. The daemon interprets only the
plan's closed target enum, invokes the owning host surface, and persists the
execution outcome. Unknown capabilities have no fallback and fail closed. A bounded
scheduler reconciles execution-deferred outcomes against the shared Deferred
Operation Registry, releases their leases only after terminal target status, and
appends completed or failed outcome facts; restart rebuilds the candidates
from those facts. result/digest identifies the bounded completion evidence
available at the host boundary: the validated target response for synchronous
completion, or the terminal Deferred Operation snapshot for deferred completion.
The exact terminal status remains available in reason/ref when several source
statuses collapse into the Agent-level failed class.
All requests reject unknown fields at the boundary; classification defaults fail-closed; identifiers are explicit and canonical.
Relationship to Existing Mechanisms¶
- Swarm Broadcast Assistance (077, advisory companion). Assistance decomposition/routing and unattended multi-agent deliberation ride bounded Agent sessions: human-in-the-loop gates effects, budgets, and acceptance — never individual conversational turns. What agents may do unattended is reason; what they may not do unattended is commit.
- Weak Signal Harvester (078). A bounded Agent may orchestrate a harvesting pass: scan configured sources, request Inquirium grouping/redaction, emit finding files, and stop. It must not widen source grants, bypass the findings directory, or publish Whisper/network artifacts directly.
- Inquirium (Solution 044 / Proposal 064). Agent is the consumer that 063 names ("Flow … and the
host own broader orchestration"). The Flow IR
bounded controller(064) is the seed; Agent generalizes it into a durable, addressable, forkable entity. The Inquirium boundary is unchanged — see the new P064 note Agent Loop Lives Above Inquirium. - Flow IR (064) / workflow orchestration (033). Complementary: Flow is a declarative DAG of steps; an Agent is a stateful controller with memory and a lifecycle that may compile and run Flows, and a Flow node may spawn an Agent.
- Horizontal Protocol Primitives (081 / Solution 043). Agent reuses
causal-context.v1as a horizontal evidence contract. Observation resolution preserves the validated source context and adds a separateresolution/ref; this dependency carries causality, not Sensorium or provider semantics. - Sensorium (045) / Sensorium Interfaces (082/083). Agent carries only opaque
observation needs and generic effect proposals. A daemon-owned adapter may
resolve them through Sensorium after checking the exact resource, grant,
collaboration, lease, classification, and HIL contracts. Sensorium vocabulary
and authority never enter
agent-core. - Memarium (036). Session context and lifecycle are durable facts; Agent adds no second memory store.
- Capability Registry (072).
agent.spawn/fork/suspend/resume/stop/statusare registered capability ids with fail-closed admission. - Assistant Channel (Solution 045). The assistant Phase 3 agentic effects land here: the assistant stays advise-only/local-only baseline, and an operator may, with explicit capability and human-in-the-loop, drive an Agent from the assistant surface. The assistant is one operator-facing surface over Agent, not the Agent itself.
- Corpus (069). Corpus live deliberation drives an Agent as the host-owned
reasoning chair bound to a Room (
agent.binding.v1,consumer/kind = collaborative-chair); the chair Agent participates via Room membership attestation, and its answer-draft product feeds Corpus answer acceptance. Draft acceptance revalidates the original signed evidence and yields an inert, content-addressed Corpus projection withpublication/authorized = false; publication remains a separate Corpus-owned transition. Corpus owns reasoning, chairing, and settlement semantics; the Agent owns the bounded session. - Enforced budget (064
inq-cost-budget-enforcement). Agent budgets reuse the same metering andBudgetExceededcontract at agent and spawn-tree scope.
Failure Modes and Guardrails¶
These are the agent-orchestration mistakes that recur in practice, with the guardrail Agent adopts against each:
- Fork bomb / resource exhaustion. Budget is split (not duplicated) on fork;
max_depth,max_children,max_concurrent, andaggregate_budgetbound the whole tree. - Non-terminating loops.
termination_conditionis mandatory; an agent without one is rejected.max_steps/max_timeare hard watchdogs. - Privilege escalation via spawn. Monotone narrowing on every axis; no self-authorization; the host is the only authority root.
- Orphaned agents / leaked leases. Lifecycle is durable facts;
stopis authoritative and idempotent; a bounded scheduler reaper records terminal state for agents past TTL. Agent-owned leases are operation-bound, persisted, TTL-bounded, and released on completed effects, terminal state, reaping, or startup reconciliation. Deferred effects retain leases while work is live. - Cost blowup. Enforced per-agent and per-tree budgets with typed
BudgetExceeded; spend attributable in trace. - Unbounded context growth.
MemoryPolicy(pinned + bounded summary + recall) with token estimation gating each step. - Effects without accountability. Effects are capability-gated proposals; sensitive classes are human-in-the-loop; every effect is an auditable fact.
- Non-reproducible runs. Each step records the resolved model snapshot, instruction hash, and controller decision, so a trajectory can be explained and replayed.
Resolved Decisions¶
- Agent is a separate organ above Inquirium, not an Inquirium operation; Inquirium stays "not the agent loop".
- Authority is host-owned; agents never self-authorize and fork only narrows.
- Agent state is durable facts (Memarium), not mutated objects.
- The contract lives in a thin
agent-corecrate guarded by a dependency lint. inquirium-coreis the sole explicit vertical dependency exception inagent-core: only its pure bounded-inference DTOs are reused. A positive direct-dependency allowlist prevents this exception from becoming precedent for another organ or runtime dependency.- Agent observation and effect ports are horizontal contracts. Vertical-domain resolution, including Sensorium and Workbench, belongs to the daemon composition root; configuration may only select and narrow statically admitted wiring.
- The first controller runtime is daemon-owned and may use Flow IR for bounded sub-steps; Flow IR is not the lifecycle owner.
- The first runtime slice is node-local only; cross-node/federated agents are deferred to a separate proposal after the node-local lifecycle, budget, trace, and effect-proposal model is proven.
- The first live working set is an in-memory / ephemeral projection. Memarium remains the durable fact plane, not a cache; a dedicated projection cache can be evaluated later after real profiling data and clear lifecycle requirements.
- Production fan-out and budget profiles are operator-defined, not limited to
a fixed preset catalog. The implementation still provides conservative,
configurable developer defaults:
max_steps = 8,max_depth = 1,max_children = 0 or 1,max_concurrent = 1, and a short deployment-configured wall-time TTL.
Additional Decisions For Durable Runtime Slice¶
The first node-local slice is decision-complete. These choices govern the next durable/runtime slice:
agent.spawn,agent.status, andagent.stopremain host-local lifecycle capabilities. Their Capability Registry shape staysdispatchable=true,surfaces=["host-local"], andpassport/eligible=false. Any future federated agent request surface requires a separate proposal and a distinct authorization model.budget_remaininginagent.status.response.v1is derived only from daemon-owned metering records. Controllers, adapters, or models may report usage as evidence, but the daemon validates and records the spend before it affects status.agent/idremains an opaque ref. Locality is enforced by storage, routing, and host registry boundaries rather than by embedding a node namespace into the identifier format.- Production Agent profiles are loaded from daemon/operator configuration.
agent-hostprovides reusable DTOs, validation, and the conservative developer default; it must not gain compile-time production profile presets that move deployment policy into the functional core. - Durable recovery preserves an immutable admission snapshot: the admitted profile identity and canonical constraint snapshot travel with the session. Historical facts may be reconstructed under that snapshot, but resume, new inference, forks, and effects must also pass current operator policy. A session that no longer passes becomes quarantined and must not prevent unrelated daemon services from starting.
- Quarantine follows authority lineage. If a recovered parent is quarantined, every descendant is quarantined even when its narrower spec would pass the current profile independently; a child cannot retain authority whose root no longer has current admission.
- Rolling memory summaries are admitted only from explicit non-Agent component
refs in the operator/distributor Agent host configuration and from modules
whose registered execution profile carries explicit
inquirium.summarizeauthority. The Capability Registry must positively admit that host-local capability. The effective set is the intersection of both sources; removing either authority quarantines affected recovered sessions rather than blocking unrelated daemon services. - Memarium lifecycle facts and the SQLite lease registry remain separate stores. Their cleanup contract is compensating and idempotent, not falsely atomic: terminal/expired state denies new lease admission, and startup reconciliation releases stragglers after interrupted stop or reaper passages.
- Eligible rolling-summary producers are derived from registered JSON-e Flow
module identities that explicitly request the positively admitted
inquirium.summarizecapability, then narrowed byagent.host.summary_producer_refs. Capability admission and module grant are necessary but not sufficient: the effective authority set is their intersection with operator/distributor configuration. Missing or removed authority fails closed during admission and current-policy reconciliation. - Inactive Agent-owned lease audit rows use a configurable retention horizon followed by audit-preserving compaction. The default horizon is 30 days after expiry or release. After that horizon, detailed rows are replaced by minimal tombstones retaining the lease and owner refs, scope digest, relevant operation/runtime refs, lifecycle timestamps, and terminal reason. Distributor and operator configuration may lengthen the horizon or disable compaction; no implicit hard deletion is allowed.
Deferred work that does not require a new decision is already tracked below: cross-node/federated agents require a separate proposal; a dedicated projection cache waits for profiling data and a clear lifecycle; and production fan-out/ budget profiles are operator-defined with the conservative developer defaults above as the initial built-in profile.
Open Questions¶
No open questions remain for the current node-local durable runtime scope. New questions should be opened only when a later federated or cross-node slice requires policy that cannot be derived from the frozen decisions above.
Implementation Tracker¶
Status values: todo, in-progress, done, deferred.
| ID | Work item | Status | Done criteria / evidence |
|---|---|---|---|
agent-operational-context-framing |
Propagate source-owned operational impact into pre-inference Agent context without adding vertical vocabulary to agent-core. |
done |
agent-core carries only bounded generic qualifier refs and strict SHA-256 digests. The daemon resolver validates the complete current P082 read result, source generation, effective publication, schema, and digest before deriving those neutral qualifiers; stale, malformed, inconsistent, or superseded evidence fails closed without an Agent-owned TTL. The composition root computes a monotone local maximum across feeds, records host-owned provenance pairing each source class with its digest plus the local policy ref, floor, and selected class in both request metadata and the durable Inquirium trace, and supplies the versioned non-droppable P064 caution layer before feed-dependent inference. The trace receives that host projection directly rather than trusting caller metadata or provider output. Tests retain per-source evidence, prove order-independent maximum and provenance selection, and keep the at-most-512-byte source summary out of instructions and durable Agent payloads. |
agent-core-crate |
Create thin agent-core contract crate with Agent/controller/budget/grant DTOs and the lifecycle state machine. |
done |
node/agent-core compiles as a substrate-free contract crate: AgentSpec/AgentParams/AgentBudget/ControllerPolicy/TerminationCondition/CapabilityGrant DTOs with deny_unknown_fields and validate(), fail-closed classification ceiling, conservative developer defaults, idempotency/key on spawn, agent.step-decision.v1, agent.spawn.response.v1, agent.status.request.v1, agent.status.response.v1, agent.stop.response.v1, the AgentLifecycleState::apply state machine, and the validate_fork_from monotone-narrowing validator. Evidence: cargo test -p orbiplex-node-agent-core, cargo clippy -p orbiplex-node-agent-core -- -D warnings, and python3 tools/check-agent-core-deps.py pass. Runtime budget metering, fork budget split, and durable wiring are tracked separately below. |
agent-dep-direction-lint |
Add a dependency-direction lint so agent-core cannot import substrate or another vertical domain. |
done |
node/tools/check-agent-core-deps.py uses a positive direct-dependency allowlist, names pure inquirium-core DTOs as the sole vertical exception, rejects daemon/model-runtime/HTTP/async/SQLite and vertical-domain packages through cargo tree, and rejects Room, Corpus, Memarium, Sensorium, Workbench, and other source/effect vocabulary in the core source. It is wired into .github/workflows/docs.yml, and the current check passes. An xtask-level lint may later replace the standalone script. |
agent-inquirium-boundary-docs |
Document that the durable agent loop lives above Inquirium and that assistant agentic effects are realized through Agent. | done |
Proposal 064 now has the Agent Loop Lives Above Inquirium boundary note, Proposal 066 Phase 3 points agentic effects at Proposal 073, and this proposal owns the lifecycle/controller/budget tracker. |
agent-lifecycle-capabilities |
Add agent.spawn/fork/suspend/resume/stop/status host capabilities. |
done |
All six node-local ids are active, host-local, non-passport-eligible capabilities with table-driven dispatch. Mutations write agent.lifecycle-command.v1 plus state/session facts, preserve local-control or the authenticated module actor, replay exact idempotency keys after restart, and reject conflicting reuse. Module calls require bounded per-capability agent_grants and ownership of the Agent. A process-level smoke drives spawn/status, binding, passive and active controller passages, suspend/resume/controller-mediated fork/stop, kills the daemon without orderly shutdown, and confirms durable terminal-state recovery through real authenticated HTTP against Memarium. The current synchronous controller has no detached passage requiring a separate cancellation protocol. |
agent-monotone-fork |
Enforce monotone narrowing and budget split on fork. |
done |
AgentSpec::validate_fork_from prevents widened grants, classification, trust, model selection, controller bounds, and budget; daemon fork admission requires a running parent, reserves the child's budget from parent remaining budget, prevents the child deadline from exceeding the parent's remaining absolute TTL, records lineage durably, and rejects a second child under the default fan-out profile. Core and daemon negative/recovery tests pass. |
agent-bounded-fanout |
Enforce max_steps/max_depth/max_children/max_concurrent/aggregate_budget and mandatory termination_condition. |
done |
Core/profile admission enforces bounded steps, depth, children, live descendants, per-agent and aggregate budget ceilings, and a mandatory terminator; daemon fork admission enforces depth/direct-child/root-concurrency limits; operator profiles are loaded from daemon config; the TTL reaper is scheduler-owned; and the real controller shell meters explicit runtime ticks against step and wall-time bounds without polling await-human. Child spawn now runs through the active controller executor. Reservation reconciliation walks the recovered tree bottom-up: live children retain their bounded allocation (or actual spend on unbounded axes), terminal children retain only spend plus descendant commitments, and unused budget returns to the parent deterministically before status is projected. Tests cover fan-out/concurrency denial, active process-level child spawn, release on terminal state, and restart reconstruction. |
agent-durable-state |
Persist session context and lifecycle as Memarium-backed durable facts with replay/recovery. | done |
The daemon persists validated agent.session.v1, agent.state.v1, agent.lifecycle-command.v1, initial step/trace, budget trace, effect, and outcome facts through a narrow AgentFactStore backed by Memarium Personal facts. The lifecycle command and completed controller step are commit markers; recovery repairs missing state/initial-step projections, initial effect outcomes, and content-addressed terminal outcomes after a partial bundle. Startup rebuilds the disposable projection and lifecycle idempotency ledger through bounded pages over the ordered stream, with a fail-closed startup budget of 100,000 facts or 256 MiB of canonicalized fact JSON; exceeding it requires administrative compaction or snapshot recovery rather than unbounded allocation. Recovery caches parsed deadlines and repairs only the latest missing state projection so a late historical repair cannot regress current state. Memarium generic fact queries provide the append-only as of source. With Memarium disabled, status explicitly reports ephemeral durability. |
agent-profile-recovery-policy |
Implement recovery when an admission profile is removed or tightened. | done |
agent.session.v1 carries a canonical-digest-bound immutable admission profile snapshot. Recovery is split into pure historical replay against that snapshot, an explicit repair phase, and current-policy reconciliation. Removed or tightened profiles produce a typed current/quarantined status projection without appending policy facts; quarantine cascades through descendants and denies resume, new inference charges, forks, effect proposals, admitted-effect lookup, and directive binding while status, stop, and unrelated daemon services remain available. Tests cover removed/tightened profiles, descendant cascade, digest mutation, no reconciliation writes, and isolation of a healthy session. |
agent-memory-projection |
Build the working set as a projection of durable Memarium facts via MemoryPolicy, with fail-closed degradation. |
done |
Every session receives an explicit default agent.memory-policy.v1; later revisions are immutable, contiguous, canonical-digest-bound facts and recovery rejects revision overflow. Each controller tick rebuilds a bounded in-memory projection through the shared Inquirium MemoryPolicy projector from pinned facts, an externally produced summary, and the recall allowlist. Agent-authored and unregistered-producer summaries fail closed at admission; removing a configured producer quarantines only affected recovered sessions. Projection text never enters prompt-free step traces, and only its evidence digest is attached to the step. Memarium-backed recovery restores the latest policy; disabled Memarium retains the existing explicit ephemeral, non-federating mode. Summary production remains another component's responsibility. |
agent-controller-step-records |
Persist each controller step as an auditable agent.step.v1 fact. |
done |
Spawn and fork write a durable bootstrap agent.step.v1. The daemon consumes pure agent-host decisions through a bounded explicit-input controller loop, executes admitted CallInquirium, ProposeEffect, and SpawnChild actions through their owning host strata without holding the Agent lock, then records each result as agent.step.v1 plus a prompt-free trace. Inquirium execution is constrained by the Agent classification ceiling, pinned profile, runtime allowlist, explicit capability grant, and Agent budget preflight; provider-reported final usage is charged idempotently to the same Agent before a successful controller response is accepted. Returned classifications are checked again before commit, and the execution evidence digest covers outcome, inference, effect, model, product, and classification refs. Every runtime tick consumes one step, conflicting concurrent passages fail closed, failed execution releases the ephemeral controller claim, passive/terminal actions stop the passage, and recovery repairs partial step/trace/terminal-state/outcome bundles. Unit tests cover grant admission, classification denial, and begin/commit exclusivity; the real process HTTP smoke exercises active child spawn and restart recovery after agent.binding.create. |
agent-effects-as-proposals |
Route effects through Sensorium/AD capability gates with human-in-loop for sensitive classes. | done |
Immutable proposals and separate outcomes are durable. Admission checks running state, Agent grants, step freshness, classification, and review policy. A proposal may name the last committed step for replay or exactly the next uncommitted controller step; arbitrary future steps fail closed. Active controller decisions can create proposals but cannot execute them implicitly. Proposal refs have one global Agent owner, question refs use a direct projection index, and each outcome history follows a bounded host-validated transition sequence. The live projection fails closed at 64 proposals per Agent and 16,384 active proposal refs node-wide; exact proposal replay remains idempotent. HIL proposals project to the existing operator-question lifecycle; Confirm answers normalize boolean and registered yes/no values, timeout transitions are audited, and a process test proves that a module authtok cannot reach an agent-effect-question:* operator action. The generic agent.effect.dispatch bridge accepts only an exact admitted proposal, matching canonical payload digest and effect/ref, explicit module and binding target grants, active operation-bound leases, and a dispatchable target. agent-host compiles Sensorium Core and Artifact Delivery requests through a closed table-driven policy-adapter registry into transport-independent execution plans; unknown capabilities and Workbench requests fail closed. The daemon invokes only the plan's closed target, records durable execution-deferred/completed/failed outcomes with operation, result digest, and bounded lease refs, and returns exact terminal/deferred replays without reinvoking the target. A bounded scheduler reconciles Deferred Operation Registry status and releases leases on terminal completion. Golden, negative, transition, and restart-recovery tests cover the boundary. Workbench retains its stricter dedicated bridge. |
agent-budget-enforcement |
Reuse the enforced token/cost budget at agent and spawn-tree scope. | done |
Inquirium charges carrying agent/ref are preflighted against host-owned spend plus reservations, replayed exactly, persisted as prompt-free traces, and rebuilt after restart. An admitted binding's monotone-narrowed budget is the effective limit for active and passive controller decisions, Inquirium and lease charges, child allocation, reservation reconciliation, status, and the absolute wall-time deadline; it never falls back to the wider session budget. Fork reserves rather than duplicates parent budget; terminal-child reconciliation returns unused slices while retaining actual subtree spend; root live-descendant caps are enforced; and runtime controller ticks charge one daemon-owned step. Every admitted Agent-owned lease is preflighted and charged once to the same durable cost ledger using the operator-configurable positive agent.lease_cost_micros; charge failure compensates by releasing the newly created lease. Tests cover narrowed Assistant binding enforcement, exact lease-charge replay, and reservation recovery. |
agent-step-trace |
Add prompt-free agent.step-trace.v1 with model snapshot, instruction hash, and decision. |
done |
agent.step-trace.v1 is a durable validated fact with decision, cumulative/delta budget, model/instruction slots, refs, predecessor, and timestamp; bootstrap, passive and active controller passages, and Inquirium budget-charge traces survive recovery without prompt/output content. Active executors attach inference/effect refs, canonical evidence digests, and the selected runtime/model-binding snapshot while keeping generated content outside the trace. |
agent-reaper |
Add a TTL reaper for orphaned/stale agents that releases leases. | done |
A bounded Replay Scheduler job reaps expired non-terminal sessions in deterministic batches, writes idempotent Reap lifecycle/state facts, releases Agent-owned leases, and recovers terminal state after restart. Lease admission also checks the Agent wall-time deadline, and startup reconciliation releases stragglers owned by terminal or already-expired non-terminal Agents. Terminalization releases active proposal-owner and operator-question routing indexes, including after recovery, while durable Agent records still prevent historical proposal/ref reuse; a late answer to a reaped Agent's question is inert. Stop, controller-terminal, reaper, and startup-reconciliation paths share the durable lease registry; tests cover owner binding, exact replay after successful release, TTL expiry, stop, reaping, expired-running recovery, effect-index cleanup, and terminal recovery cleanup. |
agent-summary-producer-registry-authority |
Derive eligible summary producers from the Capability Registry and intersect them with the host configuration allowlist. | done |
Daemon startup first requires positive host-local dispatch admission for inquirium.summarize, then derives eligible producer identities only from registered JSON-e Flow modules carrying that explicit inference grant. agent.host.summary_producer_refs can only narrow the set. agent-host admits the intersection; both source sets are capped at 256 stable refs of at most 256 bytes, config-only and module-only identities fail closed, Agent refs are invalid, and removal of either authority quarantines only affected recovered sessions. Unit and recovery tests cover intersection, malformed and oversized authority sets, absent registration, valid projection, and producer removal. |
agent-lease-audit-compaction |
Compact inactive Agent-owned lease rows after a configurable audit horizon. | done |
The Replay Scheduler runs an independently configurable bounded compaction job. Expired/released Agent-owned details remain for at least the 30-day default horizon, then one SQLite transaction writes inquirium.model-runtime.lease-audit-tombstone.v1 and removes the detailed row. Tombstones retain lease/owner/operation/runtime/model-binding identity, lifecycle timestamps, terminal reason, and a canonical digest of scope plus access; local lease GET resolves both details and tombstones. Distributor/operator configuration may lengthen retention or disable compaction. A durable scan cursor prevents old live operations from starving later rows, active rows are only normalized to expired in their first passage, non-terminal deferred-operation bindings fail closed as retained details, and stored lease JSON is rejected above 64 KiB before parsing. Tests cover bounds, live-deferred exclusion, active-row preservation, oversized stored rows, idempotent cursor cycling, and reopen durability. |
agent-assistant-surface |
Let the assistant (P066) drive an Agent under explicit capability and human-in-loop. | done |
inquirium.assistant.agent-escalation.proposal.v1 is an inert model control. agent.assistant.escalate requires explicit caller authority, records a durable host-authored escalation, and projects an expiring operator Confirm question. The terminal Approved fact is persisted before Agent or binding authority is materialized; its actor and timestamp come from the durable operator-question record through a typed internal authority. Recovery rejects a binding without matching approval and idempotently repairs an approved escalation interrupted after any partial spawn write. Denial and timeout remain terminal facts, and direct ambient binding is rejected. agent.assistant.draft.accept is local-control-only, bounded by the durable idempotency projection limit, emits prompt-free operational telemetry, and accepts only the latest content-addressed agent.outcome.v1 for the same session and assistant-response-draft sink. It returns a validated render-only draft with publication-authorized = false. A real process smoke covers dirty restart with a pending question, exact replay, approval, denial, timeout, controller execution, outcome creation, explicit acceptance, and absence of generated content from status and notifications before acceptance; fault-injected unit coverage proves approval-first ordering and partial-materialization repair. |
agent-host-stratum |
Add an agent-host service stratum so the controller step decision is a pure value and the daemon performs effects. |
done |
node/agent-host computes agent.step-decision.v1 as a pure value over agent-core contracts, exposes the conservative developer profile, contains no storage/HTTP/async/runtime substrate, and is guarded by node/tools/check-agent-host-deps.py in CI. Evidence: cargo test -p orbiplex-node-agent-core -p orbiplex-node-agent-host, cargo clippy -p orbiplex-node-agent-host -- -D warnings, and agent core/host dependency checks pass. The daemon executes actions in later tracker items. |
agent-binding-contract |
Add agent.binding.v1 so consumers (Corpus chair, assistant, Flow node) drive an agent under narrowed grants. |
done |
agent.binding.v1 and agent.binding.create.{request,response}.v1 carry consumer identity, session source, output sink, monotone-narrowed grants and budget, bounded MemoryPolicy, optional Room participant/attestation refs, HIL policy, request digest, actor, and idempotency identity. FlowNode bindings remain module-owned or local-control. Assistant Channel bindings are node-local, same-session, strict-local, require a matching durable Approved escalation before admission and after replay, reject publication grants and incompatible sinks, and persist with their escalation and decision facts for restart recovery. Corpus-chair creation requires complete inline room-membership-attestation.v1 evidence; the host verifies schema, signature, freshness, trusted local round authority, exact query/room/participant binding, answer/moderate/speak grants, and deadline, while the recovered binding stores only the content-addressed attestation ref. Every caller-delegated capability must cover both spawned-Agent and binding grants. The controller uses optimistic expected-step; a checked-in JSON-e Flow fixture demonstrates separate spawn/binding/controller grants and delegated target capability allowlists. |
agent-outcome-projection |
Publish a content-addressed terminal draft and bounded operator status projection without granting effect authority. | done |
A completed bound Agent with a successful Inquirium product writes agent.outcome.v1 to the durable fact stream. The generated response is canonicalized into the existing object store; the outcome carries only its content-addressed product/ref, classification, sink kind, binding, terminal state, budget, and prompt-free trace ref. The canonical outcome identity is revalidated during recovery, conflicting outcomes fail closed, and an interrupted append is repaired from the durable completed step. FlowNode consumes the draft through its own result path. Assistant Channel uses a separate durable same-session acceptance and receives a validated assistant-response-draft only after explicit local-control acceptance; Agent never renders or publishes it. Status exposes at most 64 metadata-only effect proposal projections plus a total count, while payloads and generated content remain outside the projection. |
agent-effect-proposal |
Add an immutable agent.effect-proposal.v1 plus a separate agent.effect-proposal-outcome.v1 fact joined by proposal/ref, with operator-question human-in-loop. |
done |
Core owns validated proposal/outcome and generic effect-dispatch DTOs; daemon persists them in Memarium, replays exact proposals, rejects conflicting bodies and cross-Agent proposal-ref reuse, caps and validates outcome transitions, projects deferred proposals to Confirm questions with fail-closed timeout defaults, joins validated boolean or registered yes/no answers as admitted/denied outcomes, audits timeout transitions, and binds each admitted proposal to exactly one effect/ref. The outcome vocabulary distinguishes policy deferral from execution deferral and records bounded operation/result/lease evidence through terminal completion or failure. Generic Sensorium and Artifact Delivery policy adapters and dispatch are implemented, active controller decisions can create proposals, agent.status exposes a bounded metadata-only operator projection, and recovery reconstructs deferred reconciliation candidates without target reinvocation. |
agent-corpus-chair |
Let Corpus (069) drive an Agent as the deliberation chair bound to a Room. | done |
The Corpus adapter maps its chair into the horizontal collaborative-chair role with a collaborative-answer-draft sink, then consumes a signed and fresh room-membership-attestation.v1, verifies its canonical Ed25519 did:key, exact query/room/participant/grant/deadline binding, and rejects foreign, malformed, or expired evidence. The Corpus query must already exist, and the node-local first slice requires the signer to be its local round authority so an arbitrary self-signed credential is not admission authority. Recovery restores the durable binding without turning the discarded inline credential into ambient authority. A terminal agent.outcome.v1 is accepted only by local control through a Corpus-owned idempotent contract into an inert answer draft; embedded evidence passes schema-gate again, exact replay remains bound to the original actor, conflicting replay fails closed, dirty restart restores both binding and draft, and no final Corpus answer is published without a separate authorized transition. A real process smoke covers unknown-query, untrusted-signer, foreign-room, expired-evidence, and unsigned-extension denial; exact and conflicting replay; two dirty restarts; bounded Inquirium controller execution; and absence of final publication. |
agent-corpus-participant |
Let a selected Corpus provider participate through an Agent without exposing a raw model runtime as a Room subject. | done |
agent.binding.v1 admits the horizontal collaborative-participant role only after the Corpus adapter validates the exact durable invite and signed, fresh Room evidence, with narrowed grants, budget, participant identity, and collaborative-turn-draft sink; participant mismatch is denied before binding. The corpus.room.turn host policy keeps corpus-reasoning-turn-proposal.v1 inert until ordinary effect/HIL admission; proposal classification cannot exceed the Agent ceiling and the dispatched payload cannot change class. A host-owned Interaction Broker room-event watch wakes the chair without connector-local polling; live content is ephemeral, durable replay uses an explicit metadata allowlist, and an entropy-bearing source epoch invalidates old cursors after restart. Story-011 proves selected B expert → A chair execution, C remaining only a competing bidder, restart recovery of the exact accepted draft, exact dispatch replay, and no ambient publication. |
agent-observation-port-and-sensorium-adapter |
Admit one statically bound observation need as bounded context for an exact Agent passage, with Story 012 supplied by a daemon-owned Room/Sensorium resolver. | done |
agent-core owns only generic AgentObservationNeed, AgentObservationBinding, and prompt-free evidence values; its only observation-evidence dependency is the horizontal P081 causal-context contract, while its positive dependency allowlist and vocabulary lint reject Room, Corpus, Memarium, Sensorium, Workbench, and other source/effect-domain coupling. Operator-authored JSON-e Flow configuration declares bounded static need-to-source mappings and imports the Agent-owned hard age, byte, reference, and item caps; rendered data may only select or narrow them, and dynamic interpolation of authority-significant refs fails closed. After caller-capability and ownership admission, the daemon proves that every exact source/schema pair has one resolver before persisting the durable binding; absent, incompatible, and ambiguous registrations fail closed with bounded pair-specific diagnostics. The resolver privately binds interface, Room, relay epoch, Room-membership source sequence, and recipient; admits one authenticated relay delivery, rechecks a fresh relay acknowledgement plus current Room invitation after the exact typed Agent-host Broker principal read, schema-gates and bounds the terminal-screen snapshot, and preserves the exact-schema/version-validated source causal/context alongside source-version and resolution refs in generic Agent trace. Step facts and traces require matching Agent, binding, and canonical passage identities for every attached observation evidence item. A conflicting digest at one relay epoch/sequence is a dedicated refusal with a payload-free structured diagnostic and cannot overwrite the admitted latest state. Broker durable replay is payload-free, restart drops observation content, and unbound or widened needs, Room membership alone, stale epochs or membership generations, ordered terminal replay, implicit summarization, and every actuation capability fail closed. The composed Story 012 runner reuses Story 011's three-node bootstrap, proves equal B/C operational-context qualifiers, revokes C and waits for relay-audience convergence before repair, dirty-restarts B, and proves immutable test -> production replacement, superseded-binding refusal, newer passing evidence for a new exact B binding while C remains refused, plus an unpublished chair output. Its closed 17-entry refusal matrix assigns every claim to direct composed-process evidence or a named P070/P082/P083 lower-stratum owner. |
agent-operator-status |
Expose a bounded, metadata-only operator projection over all node-local Agent sessions. | done |
Operator-authenticated GET /v1/operator/agents provides stable exclusive-cursor pagination capped at 100 items. Each item reports lifecycle, durability, profile and current-policy admission, deadline, spent/remaining budget, latest step/outcome refs, pending effect/HIL counts, active leases, and controller claim without prompt or generated-product content. Unknown query parameters and invalid limits fail closed; module-authenticated requests cannot enter the operator route set. Unit tests cover ordering, pagination, caps, and metadata-only defaults. |
agent-doctor-maintenance |
Add inspect-first Agent doctor output and explicit bounded remediation. | done |
POST /v1/operator/agents/maintenance accepts only agent.maintenance.request.v1, dry_run|execute, and a batch limit of 1..1000. Both modes consume one pure maintenance plan: dry-run returns projected counts and a projected after diagnostic snapshot without mutation, while execute applies that same plan. Current-policy reconciliation, canonical durable TTL reaping, and terminal lease release remain limited to the same lexicographically ordered page after the exclusive after/agent-id cursor; the response reports exact lease-registry release counts, never edits facts in place, and leaves deferred-effect reconciliation with its existing scheduler owner. Lease release remains durably owned by the model-runtime lease registry, while policy admission remains a restart-recomputed disposable projection over immutable Agent history. Missing lineage records produce ancestor-absent, distinct from an existing quarantined ancestor. Tests prove preview/apply parity, cursor-scoped durable reaping, invalid-bound denial, distinct lineage diagnostics, and stable terminal state. |
agent-runtime-diagnostics |
Publish bounded-cardinality Agent readiness and operational metrics. | done |
Operator-authenticated GET /v1/operator/agents/diagnostics emits agent.runtime-diagnostics.v1 with fixed lifecycle, quarantine, expired/reaper-backlog, pending effect/HIL, controller-claim, active-lease, recovery scan/repair, active-controller latency, and idempotency capacity counters. Degradation uses a closed stable reason-code set and no Agent id as a metric dimension. Recovery repair facts are counted only while replay repair is active; completed active controller passages record bounded aggregate latency. Targeted daemon tests and warning-clean clippy pass. |
agent-standalone-acceptance |
Provide an Agent-owned process acceptance pack independent of Assistant and Corpus drivers. | done |
node/tools/acceptance/agent-runtime/run.py drives the real daemon with durable Memarium-backed Agent facts and the deterministic local Inquirium runtime. The authenticated HTTP slice covers spawn, binding, passive and active controller passages, inference, an inert Sensorium proposal, operator-question HIL admission, child fork/stop, content-addressed terminal outcome, operator list/diagnostics, forced SIGKILL, and recovered parent/child terminal states. Assistant Channel and Corpus are not lifecycle drivers. The runner emits agent.acceptance-report.v1 and fails on the first unsuccessful check. |
agent-fault-soak |
Exercise partial writes, bounded capacity, restart recovery, and sustained short-session load. | done |
A deterministic failpoint matrix interrupts each write boundary of the six-fact spawn bundle; session-first partial bundles repair through the canonical replay path and a first-write failure remains cleanly absent. The explicit acceptance soak creates and stops 1000 durable sessions, rebuilds them after restart, and proves all sessions terminal with zero live controller, effect-owner, HIL-routing, and pending-effect projections. Existing bounded fair deferred-effect and lease-compaction scheduler tests remain the owners of those reconciliation cursors; no timing threshold is used as a correctness oracle. |
Next Actions¶
- Keep future capability-specific effect policy adapters additive: register a pure validator and closed execution target only when a concrete consumer and owning host surface exist; never add a generic fallback.
- Preserve the Assistant Channel boundary: escalation remains explicit and human-approved, draft acceptance remains render-only, and publication remains a separately admitted effect.
- Keep the node-local operator list, diagnostics, maintenance, failpoint matrix, and standalone process/soak pack on the Agent release gate. A later cross-node or federated runtime must begin in a separate proposal and must not widen these host-local surfaces into network authority.
- Preserve the horizontal observation/effect port: new vertical domains extend
the daemon resolver/adapter registries and static wiring, never
agent-core. Every binding remains operator-authored, schema-gated, digest-pinned, and represented by a prompt-free resolution reference while preserving the validated P081 causal context in trace. - Keep the shared Story 011/012 three-node bootstrap as the lower acceptance stratum. Story-specific runners may add domain fixtures and assertions, but must not fork federation-root, participant-binding, or restart semantics.
Related Capability Data¶
- implemented capabilities:
agent.spawn,agent.fork,agent.suspend,agent.resume,agent.stop,agent.status,agent.effect.propose,agent.binding.create,agent.controller.run,agent.effect.dispatch,agent.assistant.escalate,agent.assistant.draft.accept. - host-local operator projections:
GET /v1/operator/agents,GET /v1/operator/agents/diagnostics, andPOST /v1/operator/agents/maintenance; these are operator-session surfaces, not module capabilities or federated protocol endpoints. - schemas:
agent.spec.v1,agent.state.v1,agent.session.v1,agent.lifecycle-command.v1,agent.step.v1,agent.step-decision.v1,agent.spawn.request.v1,agent.spawn.response.v1,agent.fork.request.v1,agent.suspend.request.v1,agent.resume.request.v1,agent.stop.request.v1,agent.stop.response.v1,agent.status.request.v1,agent.status.response.v1,agent.step-trace.v1,agent.binding.v1,agent.binding.create.request.v1,agent.binding.create.response.v1,agent.controller.run.request.v1,agent.controller.run.response.v1,agent.memory-policy.v1,agent.effect-proposal.v1,agent.effect-proposal-outcome.v1,agent.effect.dispatch.request.v1,agent.effect.dispatch.response.v1,agent.outcome.v1,agent.assistant-escalation.request.v1,agent.assistant-escalation.v1,agent.assistant-escalation-decision.v1,agent.assistant-escalation.response.v1,agent.assistant-draft.accept.request.v1,agent.assistant-draft.acceptance.v1,agent.assistant-response-draft.v1,corpus-chair-admission.v1,corpus-agent-answer-draft.accept.request.v1, andcorpus-agent-answer-draft.v1.