ActionProof is a narrow local TypeScript CLI that returns a deterministic allow or deny decision before a credentialed, side-effecting request would execute.
v0.2.0 does not do any of the following:
- control a real browser
- intercept live browser activity
- enforce the decision against a runtime
- verify approver identity
- verify signatures
- send real email
- submit real forms
- call external APIs
- use MCP
- integrate with AgentGate
- put an LLM in the critical path
- provide sandboxing
- act as DLP
- make broad browser security claims
v0.2.0 has two proof surfaces:
send_emailform_submit
Given a JSON description of a proposed send_email or form_submit request and a JSON policy, ActionProof returns a deterministic allow/deny decision and a rule trace, locally, with no network calls and no LLM. It does not execute the request, intercept browser activity, or enforce the decision against any agent runtime.
ActionProof evaluates a proposed form submission request before execution. It evaluates the JSON intent description, not the actual browser action.
The CLI reads:
- a request JSON file
- a policy JSON file
It then:
- validates both files with Zod
- evaluates the request in a fixed rule order
- returns
allowordeny - includes the exact decisive rule code and reason
- prints readable terminal output
- writes a machine-readable JSON decision artifact
Future tool classes require fresh scope review before they are added.
{
"actor": "ops-bot",
"tool": "send_email",
"to": ["[email protected]"],
"cc": ["[email protected]"],
"subject": "Status update",
"body": "Deployment completed successfully.",
"hasAttachments": false,
"purpose": "status_update"
}{
"tool": "form_submit",
"actor": "browser-agent",
"targetUrl": "https://example.com/signup",
"method": "POST",
"fields": [
{ "name": "email", "hasValue": true },
{ "name": "name", "hasValue": true }
],
"purpose": "submit newsletter signup",
"approvalAsserted": {
"asserted": true,
"approver": "james",
"approvedAt": "2026-04-25T15:00:00Z"
}
}targetUrl must parse as a URL. method must be POST, PUT, or PATCH. Form fields contain field names and hasValue only; field values are intentionally excluded.
approvalAsserted is optional at the schema level. When policy requires it, ActionProof checks only that the assertion is structurally present: asserted is true, approver is non-empty, and approvedAt is a valid ISO 8601 datetime. It does not verify approver identity, approval recency, signatures, tokens, or keys.
{
"allowedTools": ["send_email", "form_submit"],
"allowedActorIds": ["ops-bot", "support-agent-1", "browser-agent"],
"allowedRecipientDomains": ["example.com", "vendor.test"],
"blockedRecipients": ["[email protected]"],
"allowAttachments": false,
"maxRecipients": 3,
"maxSubjectLength": 120,
"maxBodyChars": 500,
"allowedPurposes": ["status_update", "customer_support"],
"formSubmit": {
"allowedDomains": ["example.com"],
"blockedDomains": ["bank.com", "amazon.com"],
"allowedMethods": ["POST", "PUT", "PATCH"],
"blockedFieldNames": ["password", "credit_card", "ssn", "api_key"],
"requireApprovalAssertion": true
},
"defaultDecision": "deny"
}defaultDecision remains fixed to "deny".
send_email rules run in this order:
allowedToolsallowedActorIdsblockedRecipientsallowedRecipientDomainsallowAttachmentsmaxRecipientsmaxSubjectLengthmaxBodyCharsallowedPurposes
form_submit rules run in this order:
FORM_SUBMIT_TOOL_ALLOWEDFORM_SUBMIT_ACTOR_ALLOWEDFORM_SUBMIT_URL_VALIDFORM_SUBMIT_DOMAIN_NOT_BLOCKEDFORM_SUBMIT_DOMAIN_ALLOWEDFORM_SUBMIT_BLOCKED_FIELD_NAMESFORM_SUBMIT_METHOD_ALLOWEDFORM_SUBMIT_APPROVAL_ASSERTEDFORM_SUBMIT_ALLOW
If every check passes, the request is allowed. If any check fails, the first failing rule becomes the decisive rule. If a request is not explicitly covered by the allow conditions, defaultDecision: "deny" is what wins.
Build first:
npm install
npm run buildRun with explicit paths:
node dist/cli.js \
--request fixtures/requests/form_submit_allowed.request.json \
--policy fixtures/policies/form_submit.policy.json \
--output ./form-submit.decision.jsonIf --output is omitted, ActionProof writes ./actionproof-decision.json.
0= allow1= deny2= invalid input or runtime error
npm testnpm run typechecknpm run build
Sample request and policy files live in fixtures/.
See DECISIONS.md.
MIT