AgenticRail Gate

by Unknown

Not rated
Website

Description

Remote MCP server (Streamable HTTP) at https://mcp.agenticrail.nz/ — deterministic step-order enforcement for AI agents. evaluate_step returns ALLOW or DENY before a step runs; verify_receipt proves a sequence's Ed25519-signed, hash-chained receipt chain is intact. No auth…

About

Remote MCP server (Streamable HTTP) at https://mcp.agenticrail.nz/ — deterministic step-order enforcement for AI agents. evaluate_step returns ALLOW or DENY before a step runs; verify_receipt proves a sequence's Ed25519-signed, hash-chained receipt chain is intact. No auth required: omit the bearer token and calls run…

Details

Author
Unknown
Categories
Developer Tools, AI, Security, Automation

How Do You Integrate AgenticRail's Sequence Enforcement API?

Markdown mirror for AI agents, generated 2026-08-22 from the live page. Canonical:https://agenticrail.nz/docs/Site context:https://agenticrail.nz/llms.txt

One endpoint. One header. POST before each step — the gate returnsALLOWorDENY. Your agent only proceeds on ALLOW. Every ALLOW writes a cryptographic receipt — a signed, chained record of what ran, when, in what order, written before the action executed. The same gate answers the engineering question and the compliance question.

Wrapper live —https://api.agenticrail.nz/v1/evaluate

Every gate call follows the same path. Your agent sends a request. The gate enforces sequence. You get a receipt or a halt.

POST to/v1/evaluatewith your agent's current step, a unique nonce, and a timestamp. Auth via theAuthorization: Bearerheader.

The gate validates step order, checks the nonce for replay, verifiesfunctionandaction_typeagainst the policy for this step, and confirms the sequence is not sealed. All checks must pass.

On pass: a cryptographic receipt with decisionALLOW— Ed25519-signed, chained, written to R2 as a tamper-evident record. That receipt is your compliance record: structural proof of what ran and in what order, timestamped by AgenticRail. On failure: aDENYwith a reason code. Your agent only proceeds on ALLOW.

All requests to the wrapper require theAuthorization: Bearerheader. The demo key is public and rate-limited — use it to test without signing up.

Add to every request:Authorization: Bearer DEMO-AGENTICRAIL-PUBLIC-2026

The wrapper expects theAuthorizationheader; the gate usesx-slp8-key.

For production use, contacthello@agenticrail.nzfor a private key with no rate limits.

AgenticRail deploys three public services:

Endpoint:https://api.agenticrail.nz/v1/evaluate

Adds API key management, rate limiting, D1 logging, and demo key bypass. All client requests should use this endpoint.

Pure sequence enforcement layer — validates step order, nonce, function/action_type policy, and sequence seal. Called internally by the wrapper via service binding. Not publicly accessible — all client traffic enters through the wrapper.

Endpoint:https://report.agenticrail.nz/report

Generates HTML/JSON compliance reports for any sequence. Read-only; no state mutation.

Demo keyDEMO-AGENTICRAIL-PUBLIC-2026works with all three services. Wrapper prefixes demo sequence IDs withdemo-and isolates receipts.

All requests areContent-Type: application/jsonvia POST. Fields are validated in order — a missing required field halts at gate step 1.

| Field | Type | Description | | schema_version | string | Always"1.0"| | sequence_id | string | Unique per sequence — e.g. a UUID or session ID. Groups steps together. | | step | string | Your step name — must matchfunction. Must be a valid step in your configured sequence, called in the defined order. e.g."verify_identity","assess_risk","execute_transfer". | | function | string | Canonical function name — must equalstep. e.g."verify_identity","assess_risk". Used for policy lookup. | | action_type | string | Canonical action type for this step. Must be in the allowed set for the function. e.g."CHECK_STATE","RECORD_RESULT","WAIT_FOR_SIGNAL". | | model_id | string | Your agent identifier — e.g."my-agent-v2". When using the demo key, the wrapper transforms this to"client:demo"before passing to the gate. | | nonce | string | Unique string per request (any format). Used for replay protection — never reuse. | | action | string | Descriptive action label for this step. e.g."verify identity","assess risk". | | ts_ms | number | Unix timestamp in milliseconds. Required — useDate.now()or equivalent. Must be within ±300 seconds of current time when received by the gate. | | inputs | object | Optional. Any context you want to log alongside the step. | | attestation | object | Optional. Evidence object signed into the receipt at this step — e.g.{"aml_check": "passed", "approved_by": "risk-committee-id"}. The full object is signed into the receipt and stored in R2 alongside it, so any later alteration is detectable. Use it to embed proof of deliverables, external check results, or human approvals directly in the audit trail. Can contain hashes, IDs, and long strings — excluded from poison hardening. | | step_order | string[] | Required on every call. Array of all step names in execution order — e.g.["verify_identity", "assess_risk", "execute_transfer"]. The gate reads it from each payload to resolve the step's position. The gate does not store it between calls. |

Timestamp freshness:The gate enforces a ±300 second window around the current time. If your request arrives more than 5 minutes early or late, it will be rejected with reasonSTALE_TIMESTAMP. Always generatets_msfresh usingDate.now()or equivalent.

This example works against the live wrapper right now. Each snippet generates a fresh timestamp, a unique nonce, and a unique sequence ID on every run, so it returnsALLOWthe moment you paste it.

# Paste the whole block. Fresh timestamp, unique nonce + sequence id - runs every time. TS=$(( $(date +%s)  1000 )) NONCE=$(openssl rand -hex 8) SEQ="my-seq-$(date +%s)" curl -X POST https://api.agenticrail.nz/v1/evaluate \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer DEMO-AGENTICRAIL-PUBLIC-2026' \ -d "{ \"schema_version\": \"1.0\", \"model_id\": \"my-agent\", \"sequence_id\": \"$SEQ\", \"step\": \"verify_identity\", \"function\": \"verify_identity\", \"action_type\": \"CHECK_STATE\", \"action\": \"verify identity\", \"nonce\": \"$NONCE\", \"ts_ms\": $TS, \"inputs\": {}, \"step_order\": [\"verify_identity\", \"assess_risk\", \"execute_transfer\", \"audit_ledger\"] }"
# Paste the whole block into PowerShell $ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() $nonce = -join ((1..16) | ForEach-Object { '0123456789abcdef'[(Get-Random -Maximum 16)] }) $seq = "my-seq-$ts" $body = '{"schema_version":"1.0","model_id":"my-agent","sequence_id":"' + $seq + '","step":"verify_identity","function":"verify_identity","action_type":"CHECK_STATE","action":"verify identity","nonce":"' + $nonce + '","ts_ms":' + $ts + ',"inputs":{},"step_order":["verify_identity","assess_risk","execute_transfer","audit_ledger"]}' $headers = @{ "Content-Type" = "application/json"; "Authorization" = "Bearer DEMO-AGENTICRAIL-PUBLIC-2026" } (Invoke-WebRequest -UseBasicParsing -Uri https://api.agenticrail.nz/v1/evaluate -Method POST -Headers $headers -Body $body).Content

ts_msis a required field — the current Unix time in milliseconds, within 300 seconds of server time. The snippets generate it for you. Note:date +%s%3Nis GNU-only; the cross-platform form$(( $(date +%s) 1000 ))works on macOS and Linux.

// One gate call — adapt into your agent loop const res = await fetch('https://api.agenticrail.nz/v1/evaluate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer DEMO-AGENTICRAIL-PUBLIC-2026', }, body: JSON.stringify({ schema_version: '1.0', model_id: 'my-agent', sequence_id: 'my-seq-' + Date.now(), step: 'verify_identity', function: 'verify_identity', action_type: 'CHECK_STATE', action: 'verify identity', nonce: crypto.randomUUID().replace(/-/g, '').slice(0, 16), ts_ms: Date.now(), inputs: {}, step_order: ['verify_identity', 'assess_risk', 'execute_transfer', 'audit_ledger'], }), }); const gate = await res.json(); if (gate.decision === 'ALLOW') { // Proceed with your step } else { // Halt — do not proceed console.error('DENY:', gate.reasons); }

No SDK is required.The gate is a plain HTTPS JSON call, exactly as above, so any language that can POST can use it. These packages wrap that call for convenience and ship the integrations below.

# Python — ships LangGraph and CrewAI integrations pip install agenticrail # JavaScript / TypeScript — dual ESM + CJS, works with LangGraph.js, Mastra, Genkit npm install @agenticrail/core

Both are MIT-licensed and open source. Evaluate against the live gate with the public demo key above — no account, no signup.step_orderis sent on every call; the gate reads it from each payload and does not store it.

The wrapper returns a flattened response with all decision details at the top level. There is nopackwrapper — thedecision,reasons, andexecutedfields are directly in the response object. The nestedreceiptobject carries the receipt metadata for that decision —key_id,signature_alg,payload_hash, andversion.

{ "decision": "ALLOW", "executed": true, "pack_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552", "reasons": [], "sequence_id": "demo-test-seq-001", "step": "verify_identity", "function": "verify_identity", "action_type": "CHECK_STATE", "model_id": "client:demo", "result": { "status": "submitted", "data": { "state": null } }, "receipt": { "pack_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552", "key_id": "k2_2026-06-07_ed25519", "signature": null, "signature_alg": "Ed25519", "payload_hash": "201031e1bce583b179f7b9b8b9c794de2cd8514da84adae974232ed3f2ff0774", "prev_receipt_id": null, "ts_ms": 1780732058107, "version": "slp8_receipt_v2", "attestation": null }, "log": { "ok": true, "error": null } }
{ "decision": "DENY", "executed": false, "pack_id": "1493ba42f5e0ffb81227e700eda1e03e762058fd9da4080f320c432b6fa23c2f", "reasons": ["SEQUENCE_VIOLATION"], "sequence_id": "demo-replay-test-seq", "step": "execute_transfer", "function": "execute_transfer", "action_type": "CHECK_STATE", "model_id": "client:demo", "result": { "status": "skipped", "message": "No execution triggered" }, "receipt": { "pack_id": "1493ba42f5e0ffb81227e700eda1e03e762058fd9da4080f320c432b6fa23c2f", "key_id": "k2_2026-06-07_ed25519", "signature": null, "signature_alg": "Ed25519", "payload_hash": "9f2c1a77b4e83d0516a8c4f9e2b7d3061c5a8e94f0b2d6713a9e4c8051f7b2d4", "prev_receipt_id": "80fe6e6887ca024d2325260f83224c86c3d2157b10ef60cc73ee8fded4661552", "ts_ms": 1780732061488, "version": "slp8_receipt_v2", "attestation": null }, "log": { "ok": true, "error": null } }

About the signature.The inlinereceiptcarries the decision metadata and thepayload_hash. The signature itself is finalized in the durable receipt written to storage — it is not echoed in the synchronous response, so the calling system cannot verify it at the moment of decision, only afterward. That's deliberate: the synchronous path stays lean, and every verification is forced through the one durable, tamper-evident record rather than trusting an ephemeral API response. To verify it, callreport.agenticrail.nz— the compliance report includes each receipt's rawsignature(base64) and its exactsigned_canonicalpreimage, so you can runed25519_verify(public_key, signed_canonical, signature)yourself, entirely offline, against the published key at/spec/receipt-public-keys.json— no callback to AgenticRail, no trust in our own verification claim required.

Step arrived out of order — e.g.execute_transferbeforeverify_identityhas completed.

Nonce has already been used. Generate a fresh nonce per request.

Timestamp (ts_ms) is outside the allowed ±300 second window from current time. Always generate ts_ms fresh using Date.now() or equivalent.

This sequence has already been completed. Start a newsequence_id.

action_typeis not in the allowed set for this function/step.

step/functionis not present in this sequence's own declaredstep_order. An unrecognised name alone does not deny — it falls through to a permissive generic policy so customstep_ordersequences work. Only a name absent from your declaredstep_orderis rejected.(Corrected 2026-07-05 — supersedes the previously-documented but unreachableNO_POLICY_MATCH.)

A witness step'sattestation.witnessed_pack_iddid not match the real prior receipt — missing, wrong, or unverifiable against the durable record.

Thestep_ordersent differs from the one this sequence was opened with. The declared order is locked on the first call, so a later call cannot shorten it to skip a required step. If the process genuinely changed, start a newsequence_id.

Required field absent — e.g.missing_function,missing_action_type,missing_nonce.

Every code above arrives as an entry in thereasonsarray of aDENY, and every DENY is written to a signed receipt. A request can also be refusedbeforeit reaches enforcement, in which case you get a HALT instead. Those are a different class, and they are listed next.

HALT is not an enforcement decision.ALLOW and DENY are decisions: the gate evaluated your step against the sequence and reached a verdict, and either way a signed receipt is written before your action runs. HALT means the request was rejected at the boundary — malformed, oversized, unauthenticated, or matching a prompt-injection pattern — and never reached the enforcement engine at all.

A HALT produces no receipt.Nothing was decided, so there is nothing to sign or store. If you are reconciling receipts against calls, HALTed calls will have no corresponding receipt, and that is correct behaviour, not a gap.

A HALT is returned with a non-2xx HTTP status and carriesstatusrather thandecision:

{ "status": "HALT", "halt_gate_step": 1, "reason_code": "SCHEMA_VIOLATION", "reason_detail": "REJECT_ROLE_DIRECTIVES" }

reason_codeis the bucket;reason_detail, when present, is the specific trigger.
- Missing or invalid credentials.reason_detailisMISSING_KEYorBAD_KEY. On the public API this means theAuthorization: Bearerheader.

The body failed hardening before parsing.reason_detailcarries the trigger:BAD_CONTENT_TYPE(415),BODY_TOO_LARGE(413),BAD_JSON(400),BODY_READ_ERROR(400), or one of the injection patterns below (403).

The body contains role-directive text of the kind used in prompt-injection attempts.

A base64-shaped string over 40 characters. Payloads are metadata, not carriers. Not applied toattestation, which legitimately holds hashes and IDs.

YAML front-matter markers, matched both as real newlines and as the escaped\nthat appears in JSON-stringified bodies.

Theattestationobject exceeds its size cap.

Theattestationobject nests deeper than the allowed depth.
- The demo key has a tighter body-size cap than a production key.

Three rejections happen earlier still, at the public wrapper, and return a plainerrorfield rather than a HALT envelope:invalid_api_key(401) when a real key prefix is presented with the wrong secret,invalid_json(400) when the body will not parse, andrate_limited(429) when you exceed your rate limit. Treat all of these the same way you treat a HALT: the call did not reach enforcement, and there is no receipt.

Sending no key is not one of them.An unrecognised credential — no header at all, a placeholder, or a key that was never issued — does not fail. The call runs on the public demo lane and the response says so, carryinglane,lane_reasonandlane_notice. Only arecognisedkey presented wrongly is refused: a wrong secret returns 401, a revoked key returns 403. The trade is that a demo-lane sequence is prefixeddemo-and its report can be read by anyone holding the sequence id, so nothing private belongs inattestation.

These aren't soft guidelines. A violation on any one of them returns DENY immediately.

Steps must run in the configured order.No skipping. Each step must follow the one before it — for example,verify_identityassess_riskrequest_approvalexecute_transfer. An out-of-order step returnsSEQUENCE_VIOLATION.

Nonces are single-use.Each request must supply a unique nonce. Reusing any nonce — even from a prior sequence — returnsREPLAY_NONCE.

function and action_type must be valid.functionmust matchstep.action_typemust be in the allowed set for that function. Invalid combinations returnACTION_NOT_ALLOWEDorFUNCTION_STEP_MISMATCH.

Sequences seal after completion.Oncesettleis accepted, the sequence locks. Any further request on thatsequence_idreturnsSEALED_SEQUENCE. Start a new sequence with a fresh ID.

Only POST is accepted.GET, PUT, PATCH and all other methods returnMETHOD_NOT_ALLOWEDimmediately.

Each step can carry anattestationobject — arbitrary evidence that travels with the request and getssigned into the R2 receipt. Use it to prove what happened at each step: an AML check passed, a human approved the action, an external system returned a specific result.

The attestation is stored alongside the receipt and appears in every compliance report generated for that sequence. It's not a separate log entry — it's part of the cryptographic chain.

from agenticrail import RailClient import time client = RailClient(api_key="DEMO-AGENTICRAIL-PUBLIC-2026") seq = client.sequence("payment-run-001", [ "verify_identity", "assess_risk", "request_approval", "execute_transfer", "audit_ledger" ]) # Attach evidence at each step — signed into the receipt seq.next("verify_identity", attestation={ "kyc_provider": "acme-kyc", "result": "pass", "checked_at": int(time.time() * 1000), }) seq.next("assess_risk", attestation={ "risk_score": 23, "threshold": 50, "decision": "below_threshold", }) seq.next("request_approval", attestation={ "approved_by": "risk-committee-id-7f3a", "approval_ref": "APR-2026-00412", }) seq.next("execute_transfer") # attestation optional — omit if nothing to prove seq.next("audit_ledger") # seals sequence — all attestations locked in chain
import { RailClient } from "@agenticrail/core"; const client = new RailClient({ apiKey: "DEMO-AGENTICRAIL-PUBLIC-2026" }); const seq = client.sequence("payment-run-001", [ "verify_identity", "assess_risk", "request_approval", "execute_transfer", "audit_ledger" ]); // Attach evidence at each step — signed into the receipt await seq.next("verify_identity", { attestation: { kyc_provider: "acme-kyc", result: "pass", checked_at: Date.now() } }); await seq.next("assess_risk", { attestation: { risk_score: 23, threshold: 50, decision: "below_threshold" } }); await seq.next("request_approval", { attestation: { approved_by: "risk-committee-id-7f3a", approval_ref: "APR-2026-00412" } }); await seq.next("execute_transfer"); // attestation optional await seq.next("audit_ledger"); // seals sequence — all attestations locked in chain

Theattestationfield accepts any plain JSON object. Values can include strings, numbers, and nested objects. Large binary blobs are not supported — store those in your own system and include a reference ID or hash here instead.

The report worker reads every receipt for a sequence, verifies the cryptographic chain, and produces a human-readable compliance report. This is the deliverable your lawyer, auditor, or regulator asks for — proof of what ran, verified independently of what the agent claims.

Not a log export. Chain-verified receipt evidence, generated on demand for any sequence.

Endpoint:POST https://report.agenticrail.nz/report

Headers:Content-Type: application/json,x-slp8-key: <key>

Body:{ "sequence_id": "your‑sequence", "format": "html"|"json" }

Demo key restricts to sequences prefixeddemo‑. Production key accesses any sequence.

Worker scans R2 for all receipts matching the sequence ID, verifies each pack ID hash (multi‑generation logic), validates the receipt chain, and composes a deterministicenforcement_summaryfrom the resulting counts.No language model is involved anywhere in report generation— the same inputs always produce byte-identical text, so the summary reproduces like the rest of the document.

HTML:Full‑page report with cover, sequence summary, enforcement log, chain proof, and the deterministic enforcement summary.

JSON:Structured data containing all verified receipts and verification results.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.