heso
Learn more

The gate

How your rules decide what an action is allowed to do.

Before your agent does anything, the gate checks the action against the rules you wrote and picks one of four paths: let it through, refuse it, hold it for a person, or let it through with some fields stripped out. Whatever it decides, your code gets back a clear outcome you can branch on.

You write the rules in heso.toml and read the result off outcome.allowed:

# Rules are checked top to bottom. The first one that matches wins.

# A large payment is held for a person.
[[rule]]
id = "payment.large"
order = 10
enabled = true
subject = { kind = "any" }
verb = "payment"
scope = "*.stripe.com"
decision = "require_approval"
conditions = [{ field = "amount", op = "gt", value = 10000 }]

# Everything else a tool call does is fine.
[[rule]]
id = "tool.allow"
order = 100
enabled = true
subject = { kind = "any" }
verb = "tool_call"
scope = "*"
decision = "allow"

What the gate returns

Every gated call resolves to one of three outcomes. You read it off outcome.allowed and the outcome value, and act on it:

allowed
The action passed your policy. It runs, and a signed receipt is minted.
blocked
The action failed your policy. It is refused before it runs.
suspended
The action needs a person. It is held until an approver clears or denies it.

The four rule paths (allow, block, redact, require_approval) collapse into those three outcomes: a redact rule still lets the action run, so you see allowed with the named fields already gone, and a require_approval rule shows up as suspended until a person clears it.

How a decision is made

Your rules are an ordered list. The gate walks them top to bottom and the first rule that matches the action wins. It checks who is acting, what kind of action it is, where it is going, and any conditions you set (like amount > 10000). Once a rule matches, the gate stops looking and uses that rule’s decision.

No match means a person looks at it

If no rule matches, the gate does not guess and it does not quietly allow. It holds the action for a human (require_approval), so an action you never wrote a rule for becomes suspended rather than slipping through.

The floor you cannot weaken

Some actions are risky enough that heso always holds them for a person, no matter what your rules say. A payment with no proof a user authorized it, or a destructive action heso cannot identify, is held by default. A rule you write can make things stricter, but it can never make these looser. heso even refuses to load a policy whose rule would blanket-allow one of them, so you find out when you save the file, not in production.

  • An allowed action runs and gets a signed receipt.
  • A blocked action never runs, and nothing is signed.
  • A suspended action waits for an approver before it can run.

Where to go next

Policy authoring

Write the rules: subjects, conditions, decisions, and the order they fire in.

The gate SDK

Wire the gate into your code and branch on what it returns.

Limits

The gate can only decide on actions it sees. An action that leaves through a path you did not put the gate on is never checked, so coverage is only as complete as where the gate is installed.