Skip to main content
Refund quickstart | Entity RuntimeValidate a policy, let an agent propose a refund, observe a typed refusal, and record an authorized decision.Entity Runtimehow-toentity-runtimehow-toadopterdeveloperinstall

Refund quickstart

This walkthrough uses a refund policy to show the whole boundary: an agent proposes approval, a deterministic rule refuses it, and the original state remains unchanged.

Install the command

Every release includes entity binaries for Linux, macOS, and Windows plus SHA256SUMS: download a release.

Or install from the tagged source with Rust 1.85 or newer:

cargo install --git https://github.com/beyond10x/entity-runtime \
--tag 0.18.1 --locked entity-cli
entity --version

The complete definition used here is examples/refund.yaml. The following Bash setup downloads that exact version into a fresh temporary directory. It needs curl; subsequent commands use that directory so another run cannot collide with its files or store. The sample actor names and timestamps are demonstration data, not authenticated identities or a trusted clock.

set -euo pipefail
refund_demo_dir="$(mktemp -d)"
cd "$refund_demo_dir"
curl --fail --show-error --location --max-time 30 \
https://raw.githubusercontent.com/beyond10x/entity-runtime/0.18.1/examples/refund.yaml \
--output refund.yaml

Understand the policy

The definition has four states:

$ entity graph refund.yaml
refund v1: initial draft
draft --submit--> submitted
submitted --approve--> approved
submitted --reject--> rejected

The same lifecycle can go straight into Markdown, an issue, or an agent report:

$ entity graph refund.yaml --format mermaid

Pan the full-size diagram: swipe or scroll, or focus the canvas and use the arrow keys.

DiagramA visual explanation of the surrounding documentation.

This block is the command's exact output, not a hand-maintained second diagram.

Approval has two preconditions:

preconditions:
- name: evidence_is_present
assert: { gt: [$fields.evidence_count, 0] }
message: a refund cannot be approved without evidence
- name: large_refunds_need_a_human
assert:
any:
- lte: [$fields.amount_cents, 5000]
- eq: [$args.actor_role, human]
message: refunds above 5000 cents require a human actor

Validate the complete document before using it:

$ entity validate refund.yaml
refund.yaml: valid (refund v1)
1 file(s), 0 invalid

Create and submit a request

The kernel generates no identity, so the caller supplies one:

entity create --definition refund.yaml --id refund-104 \
--fields '{"order_id":"order-88","amount_cents":12500,"evidence_count":2}' \
> draft.json

entity execute --definition refund.yaml --instance @draft.json \
--operation submit > submitted.json

submitted.json is a Decision: it contains the new instance, its complete replay record, and the events produced by submit.

Let the agent propose approval

The trusted shell supplies actor_role: agent from its execution context. It is not a label the model is allowed to choose.

if entity execute --definition refund.yaml --instance @submitted.json \
--operation approve \
--arguments '{"actor_role":"agent","reason":"customer supplied delivery evidence"}'; then
echo "Expected policy refusal, but approval succeeded" >&2
exit 1
else
refusal_status=$?
test "$refusal_status" -eq 1
fi

The command prints this structured refusal (plus a readable summary on stderr):

{
"kind": "precondition_failed",
"message": "precondition 'large_refunds_need_a_human' failed for operation 'approve': refunds above 5000 cents require a human actor",
"operation": "approve",
"reason": "refunds above 5000 cents require a human actor",
"rule": "large_refunds_need_a_human"
}

The operation was understood and refused. submitted.json is still submitted at revision 2, and no RefundApproved event exists.

Authorize and store the decision

For durable use, create and execute against a File Store. Stored commands require provenance the kernel cannot invent:

entity create --definition refund.yaml --id refund-104 \
--fields '{"order_id":"order-88","amount_cents":12500,"evidence_count":2}' \
--store ./refund-store --record-id request-104-created \
--recorded-at 2026-08-31T10:00:00Z --actor support-api

entity execute --definition refund.yaml --store ./refund-store \
--id refund-104 --operation submit \
--record-id request-104-submitted --recorded-at 2026-08-31T10:01:00Z \
--actor support-agent

entity execute --definition refund.yaml --store ./refund-store \
--id refund-104 --operation approve \
--arguments '{"actor_role":"human","reason":"supervisor verified the delivery evidence"}' \
--record-id request-104-approved --recorded-at 2026-08-31T10:04:00Z \
--actor supervisor-7 --format text

The final command prints:

refund refund-104 is approved (revision 3); record request-104-approved; events: RefundApproved

The generic CLI loads revision 2 and uses it as the commit expectation before writing revision 3. A concurrent writer is refused instead of overwritten. The resulting record includes the caller-supplied actor and time, normalized command, exact definition snapshot, new instance, changes, and events.

For a service that must preserve a previously observed revision and safely retry an accepted request, use the generated CLI, MCP tools, or StoredRuntime. Generic entity execute --store reloads current state on every call; it is not that retry boundary. Your demo files remain under $refund_demo_dir for inspection.

Next