SCRIPTMASTERLABS · AGENT INFRASTRUCTURE · SEP 26, 2026
Jev decides. SPD permits. Receipt proves the source said it. Chat is out of scope.
A brake in front of irreversible actions. Before an agent sends a message, pays money, or deletes data, it must pass this gate. The gate returns allow | stop | human in under half a second — and logs everything: the question, the options, the scores, the state hash, the decision.
What v1 is: a local, zero-dependency Node module. decide() runs the gate, receiptCheck() runs the evidence check, ledger.mjs appends every decision to JSONL. 9/9 gate test scenarios pass; 7/7 MCP server checks pass. Latency is asserted under 500ms in tests. Public on GitLab.
What v1 is not: a model. SPD never calls a model directly — it calls a scorer interface, and the shipped scorer is a heuristic (receipt coverage × action-risk rules), not intelligence. Receipt is keyword overlap, not semantics: it is a tripwire, not a proof.
What nobody should claim: there are no users, no revenue, no production deployments. Nothing below has been battle-tested against a real agent stack yet. The weaknesses are documented in the open, in the code comments and the limits section.
| verb | risk | gate behavior |
|---|---|---|
| send | messages a human | unsupported claim → human |
| pay | spends money | unsupported claim → stop |
| delete | destroys data | always ≥ human, even when the claim is supported — irreversible |
Hard rules first, scorer only in the ambiguous middle — explicit and boring on purpose:
pay/delete: stop. send: human.pay/delete: stop. send: human.delete → human. Irreversible is never auto-allowed.allow with confidence ≥ 0.6 → allow, else human.receiptCheck(claim, sources) answers one question: is this claim evidenced by the provided sources? It returns { supported, coverage, missing } — the fraction of the claim's key terms found anywhere across the sources.
Catches: an agent asserting a claim that appears nowhere in the sources it was given — the classic "lying about evidence in context" failure. Claims made with zero sources at all.
Does not catch: invented world-facts with no source to check against ("unsupported" means not evidenced here, never false). Claims that ARE in the sources when the sources themselves are wrong, planted, or attacker-controlled — whoever controls the sources controls the verdict. Paraphrase and synonyms (keyword overlap, not semantics — false stops are the price). Negation ("not" is a stopword, so "authorized" and "NOT authorized" look the same).
In production this heuristic is a tripwire, not a proof. Pair it with a real decision model and treat every stop as "unverified", never "disproven."
The gate never calls a model directly. It calls a scorer:
scorer.score({ question, options, context })
// → { scores: { allow: 0.7, human: 0.25, stop: 0.05 }, confidence: 0.8 }
context carries { action, coverage, stateHash }. A Jev-style decision model (typed choices and scores, no text) plugs in as a thin adapter — see scorer.mjs. The shipped default is the heuristic; swap it without touching gate.mjs.
mcp-server.mjs is a stdio MCP server (zero dependencies) exposing two tools:
spd_decide { action, claim, sources[], question?, stateHash? } — the full gate; appends to the audit ledger.spd_receipt_check { claim, sources[] } — the Receipt evidence check only.// MCP client config
{
"mcpServers": {
"spd-gate": { "command": "node", "args": ["/path/to/spd-gate/mcp-server.mjs"] }
}
}
SPD is the general form of a pattern ScriptMasterLabs already runs in one domain: decision-gated machine payments — a decision model's confidence gating whether an x402 machine payment fires. That page is the payments instance; this page is the general pattern. The gate is the product, not the model: Jev, Laya, whatever comes next plugs into the same gate.
The first integration target is GatePay: SPD as the permit layer in front of its x402 payment flow, verifying payment claims against provided sources before money moves.
Code, public: gitlab.com/timothy.walton45/spd-gate — gate.mjs, receipt.mjs, scorer.mjs, ledger.mjs, mcp-server.mjs, tests. Zero dependencies, no network calls, no credentials.
Send / Pay / Delete — the three irreversible verbs an AI agent can perform. SPD is the gate that must permit each one before it happens.
No. SPD never calls a model directly. It calls a scorer interface; v1 ships with a heuristic scorer (receipt coverage × action-risk rules). A real decision model — e.g. a Jev-style typed decision model — plugs in as an adapter without touching the gate.
Whether the claim behind an action is evidenced by the sources the agent was given. It catches an agent asserting something that appears nowhere in its sources. It does not verify world-facts, does not detect wrong or planted sources, and does not understand paraphrase or negation — v1 is keyword overlap, a tripwire, not a proof.
Explicit rules: no sources or unsupported claim → stop for pay/delete, human for send. Delete always escalates to human even when supported, because it's irreversible. The scorer only decides the ambiguous middle: supported + reversible + confidence ≥ 0.6 → allow, else human.
Agent developers and agent-stack builders first — anyone whose agents send messages, spend money, or delete data. The first integration target is GatePay, ScriptMasterLabs' x402 payment flow, where SPD acts as the permit layer in front of machine payments.
Public on GitLab: timothy.walton45/spd-gate — gate.mjs, receipt.mjs, scorer.mjs, ledger.mjs, the stdio MCP server (mcp-server.mjs), and tests (9/9 gate scenarios + 7 MCP checks passing).
JEV DECIDES. SPD PERMITS. RECEIPT PROVES THE SOURCE SAID IT.