Abe · free · open source · FJP Gate reference implementation
Act. Block. Escalate.
Abe is one control point before an AI agent acts. It checks a proposed action against your policy and returns ACT, BLOCK or ESCALATE, with an immutable record of why. It runs entirely on your machine. No account, no API key, no network, no model.
< 1 ms
Median evaluation, no external calls.
0
Network calls, accounts or keys required. No call-home.
L3
Every record passes FJP-CONF v0.1. 160 conformance checks, offline.
Three answers. Nothing else.
ACTThe policy found no reason to stop or escalate. Execute exactly as evaluated. It does not claim the action is optimal.
BLOCKA rule clearly forbids it: over a hard limit, blocked vendor, unauthorized agent. Do not execute.
ESCALATERules conflict, evidence is missing, stakes or irreversibility are high, or judgment is required. Hold. Not an error.
BLOCK beats ESCALATE beats ACT. Bad input or a broken rule returns ESCALATE / EVALUATION_FAILURE. Abe never silently acts.
01Install and run your first check
$ pip install abe-ai # or: npm install abe-ai
$ abe init # writes abe-policy.yaml + request.json
$ abe check request.json
Decision: ESCALATE
Reason: FINANCIAL_THRESHOLD_EXCEEDED
Rules: purchase_review_limit
Record: jgr_01M3Q4…
02Put it in front of the action
Python
from abe import Abe
abe = Abe("abe-policy.yaml")
r = abe.check(
action={"type": "wire_transfer",
"amount": 50000},
context={"agent_id": "finance-agent"})
if r.decision == "ACT":
execute()
TypeScript
import { Abe } from "abe-ai";
const abe = new Abe({
policy: "./abe-policy.yaml" });
const r = await abe.check({
action: { type: "purchase",
amount: 12500 },
context: { agent_id: "procurement-agent" }
});
if (r.decision === "ACT") execute();
Any other language: abe serve runs a local HTTP sidecar on 127.0.0.1 (POST /v1/check), also available as a Docker image. MCP agents: abe mcp exposes fjp_check_action.
03Write the policy you already have in your head
version: "0.1"
defaults: { unmatched: ESCALATE } # fail closed
rules:
- id: purchase_hard_limit
when: { all: [ { field: action.type, op: eq, value: purchase },
{ field: action.amount, op: gt, value: 100000 } ] }
decision: BLOCK
- id: purchase_review_limit
when: { all: [ { field: action.type, op: eq, value: purchase },
{ field: action.amount, op: gt, value: 10000 } ] }
decision: ESCALATE
reason_code: FINANCIAL_THRESHOLD_EXCEEDED
evidence_requirements:
- { id: refund_evidence, when: { field: action.type, op: eq, value: refund },
require: [evidence.customer_verified, evidence.original_transaction] }
judgment_required:
- action.type: terminate_employee
| Section | Does |
|---|
| rules | 11 operators (eq gt in contains exists…) with all / any / not |
| authorization | Which agent may take which action types → AUTHORIZATION_FAILED |
| evidence_requirements | Required facts before acting → EVIDENCE_MISSING with the missing fields |
| risk · irreversibility | Levels with thresholds. Callers can raise risk, never lower it. |
| confidence | Agent-supplied confidence minimums, recorded as uncalibrated |
| judgment_required | Action classes that always need judgment |
04Keep a record an auditor can verify
Every call returns a Judgment-Grounded Record: the decision, every matched rule, the exact policy hash, the request hash and a SHA-256 record hash, optionally Ed25519-signed with a local key. Records never change. Outcomes and resolutions are appended as linked records.
decisionESCALATE · FINANCIAL_THRESHOLD_EXCEEDED
policy.hashsha256:7152f8e4… (which rules existed when the agent acted)
falsifierAn OUTCOME record reports status executed before a RESOLUTION with decision ACT is linked
record_hashsha256:684f5e90… · signature ed25519 (optional)
$ abe validate-record jgr.json --public-key abe-signing-key.pub.pem
VALID jgr.json (hash verified, signature verified; FJP-CONF v0.1 L0-L2)
05When rules aren't enough, add Flow
Rules handle the obvious. When Abe says ESCALATE, hand that one action to Flow's judgment service. ACT and BLOCK never leave your machine; only escalations are sent, redacted, and only they cost anything.
$ pip install abe-flow
from abe_flow import FlowResolver
abe = Abe("abe-policy.yaml",
resolver=FlowResolver(api_key=os.environ["FLOW_API_KEY"]))
| Abe says | Flow | Result |
|---|
| ACT / BLOCK | not called | unchanged. A resolver can never loosen a BLOCK. |
| ESCALATE: human approval | not called | stays with the human |
| ESCALATE: anything else | judge | REACH → ACT · SKIP → BLOCK · WAIT / RESEARCH_FIRST → ESCALATE, with Flow's reason and falsifier linked to Abe's record |
| Flow unreachable | | stays ESCALATE. Abe never fails because Flow is down. |
Abe acts, blocks or escalates. Flow resolves the escalations. Abe is useful without Flow. Flow is what you call when Abe says a call needs judgment.
06Prove it conforms
$ abe conformance --bench
160/160 checks passed
RESULT: conforms to FJP-CONF v0.1 Gate profile, Level 3
performance: p50 0.34 ms p95 0.44 ms
Third-party implementations can run the same published fixtures and claim "FJP Compatible". Apache-2.0.