> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Rules, behaviours and triggers

> algovoi-keystone-agent is the behaviour layer for Keystone: declare rules and triggers as small specs, and gate any keystone-connect write before commit.

An agent should govern itself with the same evidence it produces. `algovoi-keystone-agent` is the
open (Apache-2.0) behaviour layer that sits on top of [keystone-connect](/keystone-connectors):
connectors bind each write to the decision that authorised it, and behaviours **decide, gate and
react** to those writes. Every firing reduces to one primitive,
`ref = "sha256:" + SHA-256(RFC 8785 JCS(payload))`, so a behaviour's verdict is itself a verifiable
Keystone record with no AlgoVoi software in your trust base.

<Note>
  Like the rest of the Keystone family, `algovoi-keystone-agent` installs from the Keystone control
  panel: the integrity path, from the AlgoVoi index that is baked into the installer, so you run the
  validated build rather than a mutable public artifact. New releases land on the AlgoVoi index first;
  PyPI mirrors follow for those not using the panel.
</Note>

## Install

```bash theme={null}
pip install algovoi-keystone-agent
```

CPython 3.10 to 3.13 on Linux (x86\_64 / aarch64) or Windows (AMD64). Prerequisites, the AlgoVoi-index
integrity path, control-panel setup, and `keystone doctor` verification are documented once on the
[Keystone install hub](/keystone#install-and-run).

## Three small pieces

A governing behaviour is a **rule** (a pure predicate to a verdict), a **trigger** (when it wakes),
and an optional **action** (what to do). That is the whole model:

```python theme={null}
from algovoi_keystone_agent import rule, trigger, behaviour, Engine

cap    = rule("spend_cap", lambda ev: "BLOCK" if ev.get("amount", 0) > 500 else "ALLOW")
charge = trigger(stage="spend_decision", where=lambda ev: ev.get("action_type") == "charge")
freeze = behaviour("freeze_on_cap", on=charge, rule=cap,
                   action=lambda ev, verdict: {"froze": ev.get("scope")} if verdict == "BLOCK" else None)

engine = Engine([freeze], decision_ref=decision_ref)
for record in engine.dispatch(spend_event):
    ...   # record["behaviour_ref"] recomputes byte for byte
```

A rule returns `"ALLOW"`, `"FLAG"` or `"BLOCK"` (or a bool). `Engine.dispatch(event)` fires every
behaviour whose trigger matches and appends a self-describing `behaviour_ref` record to `engine.log`;
`Engine.verdict(event)` returns the strongest verdict, ordered `BLOCK` over `FLAG` over `ALLOW`.

## Gate a real write

`Engine.guard(client)` wraps a keystone-connect client so each call is dispatched as an event first.
A `BLOCK` denies the call **before it reaches the data plane**; reads and non-matching calls pass
straight through, because their triggers simply do not match.

```python theme={null}
from algovoi_keystone_agent import Denied

guarded = engine.guard(keystone_s3_client)
guarded.put_object(Bucket="receipts", Key="r1", Body=b"{}")   # allowed
guarded.put_object(Bucket="locked",   Key="r2", Body=b"{}")   # raises Denied, no write, block recorded
```

The denial is not advisory. The write never runs, and the block is recorded like any other firing, so
the audit trail shows the decision that stopped it.

## Ready-made behaviours

The `library` module ships the common policies so a guardrail is one call, not a lambda. Each rule is
a pure function of a single event and reads both flat stage records and guarded-connector calls:

```python theme={null}
from algovoi_keystone_agent.library import cap_charges, deny_writes_to, restrict_scope
from algovoi_keystone_agent import Engine

engine = Engine([
    cap_charges(500),                                   # block a charge over 500
    deny_writes_to("Bucket", ["locked"], method="put_object"),
    restrict_scope(["acct/7/"], method="put_object"),   # only this agent's namespace
], decision_ref=decision_ref)
```

| Factory                                                      | Effect                                        |
| ------------------------------------------------------------ | --------------------------------------------- |
| `spend_cap(limit)` / `cap_charges(limit)`                    | block when an amount exceeds a limit          |
| `flag_over(limit)` / `flag_large_charges(limit)`             | flag but allow when an amount exceeds a limit |
| `deny_list(field, values)` / `deny_writes_to(field, values)` | block a named chain, bucket, table, entity    |
| `allow_list(field, values)`                                  | block anything not on the list                |
| `scope_fence(prefixes)` / `restrict_scope(prefixes)`         | allow only within a namespace                 |
| `require_fields(*fields)`                                    | block records missing required fields         |

## Test a behaviour at any stage

You do not need a live gateway or real payments. `synth_event(stage)` stands in for whatever precedes
your behaviour, and the check battery verifies the keystone properties offline.

<Tabs>
  <Tab title="A behaviour">
    ```python theme={null}
    from algovoi_keystone_agent import check_behaviour, synth_event

    report = check_behaviour(
        freeze,
        [synth_event("spend_decision", amount=900, action_type="charge", scope="acct/7")],
        expect="BLOCK",
    )
    assert report.ok
    print(report)
    ```
  </Tab>

  <Tab title="A rule or trigger">
    ```python theme={null}
    from algovoi_keystone_agent import check_rule, check_trigger, synth_event
    from algovoi_keystone_agent.library import spend_cap

    report = check_rule(spend_cap(500), [
        (synth_event("spend_decision", amount=900), "BLOCK"),
        (synth_event("spend_decision", amount=100), "ALLOW"),
    ])
    assert report.ok
    ```
  </Tab>
</Tabs>

## The conformance battery

Both checks return a `Report` with an `ok` roll-up. Between them they assert:

| Property        | Meaning                                                                 |
| --------------- | ----------------------------------------------------------------------- |
| Fires           | the behaviour wakes on the events its trigger describes                 |
| Recompute       | the recorded fields reproduce the claimed `behaviour_ref` byte for byte |
| Self-describing | each record carries the fields a verifier needs, with no mapping        |
| Decision-bound  | swap the `decision_ref` and every `behaviour_ref` changes               |
| Tamper-evident  | mutate the verdict or scope and the reference no longer recomputes      |

A behaviour that ignores its `decision_ref`, or a rule that is not deterministic, fails `report.ok`.
The harness never crashes on a broken behaviour; it reports the failure.

## One primitive

Everything above is one function:

```python theme={null}
from algovoi_keystone_agent import keystone_ref

keystone_ref(payload)   # "sha256:" + SHA-256(RFC 8785 JCS(payload))
```

Any party recomputes any `behaviour_ref` with a stock RFC 8785 implementation and standard SHA-256,
with no AlgoVoi software involved. That is what lets an agent be governed by rules whose every
decision is independently verifiable. See [Build a bolt-on](/keystone-connect), the
[connector catalogue](/keystone-connectors) and the [Keystone chain](/keystone).
