Skip to content

An agent proposes. Something else decides.

Every action passes through the same four stages, in the same order, with no way around them. This is each one, including what happens when it fails.

The four stages

The order is the design. An agent that could execute would be an agent whose judgement is the last word.

  1. Propose

    An agent reads the situation and names an abstract action and its parameters. Nothing more.

    Cannot call a connector, hold a credential, or reach anything outside OnDuty.

  2. Evaluate

    The decision engine checks the proposal against your workspace's guardrails and answers permit, hold or deny, with a reason and a trace id.

    Never executes. Holds no connector credentials.

  3. Execute

    Only a clean permit reaches the executor, which calls the connector once, keyed so a retry cannot send the same message twice.

    A hold goes to a person. A deny stops. Nothing else executes.

  4. Record

    The verdict, its reason, its trace and its outcome are written to a hash-chained trail, whether permitted, held or refused.

    Refusals are recorded as carefully as executions.

Nothing acts on your customers because a model was confident. It acts because a rule you wrote said it could, and the record of that rule saying so is kept.

The two contracts

Fixed shapes. There is no free-text channel through which an agent can talk the executor into something.

What an agent proposes

action
The abstract operation, for example messaging.send. Never a vendor name.
parameters
What the operation needs. Structured, validated, readable by a person reviewing a hold.
agent_id
Which agent proposed it, so a pattern of bad proposals is traceable.
tenant_id
Whose workspace this belongs to. Every rule and every key resolves per tenant.
context
What the agent was looking at. This is what a reviewer reads.
idempotency_key
The identity of the intent. Two deliveries execute once.

What comes back

decision
permit, hold, or deny. No fourth answer, no partial one.
reason
Why, in terms of the rule that applied.
trace_id
Ties this verdict to its audit entry and to what followed.
latency_ms
How long the decision took.
active_campaigns
Which standing rules were in force, including a kill switch if one was on.
shadow
Whether the workspace is still proving its rules rather than enforcing them.

When something goes wrong

Fail-closed is not a setting. It lives in the executor, the one place that can actually stop an action.

SituationWhat happensWhy
The engine times outNothing executes.A slow answer is not a permit.
The engine returns an errorNothing executes.An error means the rules were not applied.
The engine is unreachableNothing executes.Availability of governance is never traded for getting the action out.
The verdict is holdIt waits in the review queue for a person.Auto-resolving a hold would delete the only thing it was for.
The verdict is denyIt stops, and is recorded as denied.The useful question is often what the system was stopped from doing.
The connector fails after a permitRetries, then a dead-letter queue.The decision was clean; only delivery failed, and the key stops duplicates.

Around the seam

Three mechanisms that make a hold a person rather than a timer, and a verdict a record rather than a log line.

  1. The review queue

    hold

    A held action carries the proposal, the context, the rule that stopped it and what approval does. Approving releases this one action, not the agent.

  2. Holds resolve asynchronously

    webhook and poll

    OnDuty subscribes to the engine's webhooks and also polls, so a webhook that fails every retry cannot leave an action waiting with nobody aware.

    An unanswered hold becomes a signal, and then a row on Today.

  3. Shadow mode

    prove it

    Every rule runs and every verdict is recorded without anything executing. Real proposals, real verdicts, a week to read before one is real.

    Shadow is a setting on the engine's side. OnDuty honours it and never claims production governance while it is on.

  4. The decision trail

    hash chain

    Append-only, hash-chained, with a verify endpoint that answers about the whole record rather than one row.

Built and tested

Where this stands today

  1. The seam

    tests

    Agents cannot construct an executor, no route names a gate implementation, and the executor refuses to act without a clean permit. Enforced by the test suite, not by convention.

  2. Two gates behind one interface

    production and local

    The production path calls the decision engine. The local path permits everything and says so loudly: a workspace on it is shown as ungoverned.

  3. Your action vocabulary and guardrails

    with you

    The concrete actions an agent may propose in your operation, and the rules over them, are written with you. Until then the shipped rules propose only work a person does.

Built and tested Not built

Read the rules before you trust them.

Connect one system, run it in shadow, and read a week of decisions that did not happen.

On duty ·