This walks the shortest path from nothing to a recorded policy decision. It uses only the pure Python primitive — no MCP server or Docker required — so you can see the gate return a verdict before wiring it into an agent. For the full install matrix (Python library, MCP server, Docker), see the install guide.
1. Install the policy primitive
The gate is a pure function with no I/O. That is the whole point — it is unit-testable and reproducible from a git commit.
pip install closegate-policy 2. Write a minimal policy.yaml
Declare your tiers, one materiality threshold, and a sensitive account. closegate adapts to your shape — this is deliberately small.
materiality:
default_usd: 10000 # above this, escalate to a human
sensitive_accounts:
- "1000-CASH" # any touch requires approval
tiers:
auto_confirm:
max_tier: 1 # T0/T1 below materiality auto-confirm
require_approval:
tier: 2 # T2 needs one human, distinct identity
require_dual_approval:
tier: 3 # T3 (irreversible) needs two 3. Evaluate an action through the gate
Feed the gate the proposed action, the match context, the actor identity, and your config. It returns exactly one of three decisions.
from decimal import Decimal
from closegate_policy.gate import (
Action, ActorContext, MatchContext, PolicyConfig, evaluate,
Allow, RequireHumanApproval, Deny,
)
config = PolicyConfig.from_file("policy.yaml")
decision = evaluate(
action=Action.CONFIRM,
match=MatchContext(
match_id="m-1042",
state="PROPOSED_MATCH",
proposed_by="llm:claude",
source="llm",
match_type="exact_match",
amount_usd=Decimal("42000"), # above materiality
),
actor=ActorContext(id="llm:claude", kind="llm"),
accounts={"5000-COGS"},
rationale="PO-88 / GRN-88 / INV-88 three-way match",
config=config,
) 4. Handle the three decisions
Because $42,000 is above the $10,000 materiality threshold, this action
routes to RequireHumanApproval. The clause carries the verbatim
policy text and a JSON-pointer into your policy.yaml.
match decision:
case Allow():
commit_match(match_id="m-1042") # + write audit row
case RequireHumanApproval(clause):
open_envelope(clause.text, clause.pointer) # LLM can't self-confirm
case Deny(clause):
raise PolicyViolation(clause.text) 5. Add the MCP server and audit log
Once the primitive behaves the way you expect, run the MCP server so any MCP-compliant client (Claude Desktop, Cursor, OpenAI Apps SDK) drives the same gate — with the append-only audit log recording every decision.
uvx closegate-engine --policy ./policy.yaml From here, wire the Slack or Teams approval bot so a human with a different actor identity confirms above-materiality actions. That is segregation of duties, enforced server-side.
Where to go next
- How it works — the three-step gate walkthrough with the architecture diagram.
- Features — all four primitives and what ships with them.
- The policy gate — the chokepoint pattern in depth.
- The audit log — how tamper-evidence is enforced at the database layer.
- Glossary — every term used above, defined.
closegate is open source (Apache-2.0), built by Neul Labs.