Skip to content

selfradiance/ActionProof

Repository files navigation

ActionProof

ActionProof is a narrow local TypeScript CLI that decides allow or deny before a credentialed, side-effecting tool request would execute.

v0.1.0 locks the proof surface to one tool only:

  • send_email

The claim is intentionally small and honest: a send_email request can be evaluated locally, deterministically, and before execution by explicit machine-readable policy rules.

What It Does

ActionProof reads:

  1. a request JSON file
  2. a policy JSON file

It then:

  • validates both files with Zod
  • evaluates the request in a fixed rule order
  • returns allow or deny
  • includes the exact decisive rule code and reason
  • prints readable terminal output
  • writes a machine-readable JSON decision artifact

What It Does Not Do

v0.1.0 does not do any of the following:

  • send real email
  • call external APIs
  • talk to Gmail
  • use MCP
  • integrate with AgentGate
  • put an LLM in the critical path
  • provide sandboxing
  • act as DLP
  • orchestrate broad policy across many tools

Request Shape

{
  "actor": "ops-bot",
  "tool": "send_email",
  "to": ["alice@example.com"],
  "cc": ["vendor.contact@vendor.test"],
  "subject": "Status update",
  "body": "Deployment completed successfully.",
  "hasAttachments": false,
  "purpose": "status_update"
}

Policy Shape

{
  "allowedTools": ["send_email"],
  "allowedActorIds": ["ops-bot", "support-agent-1"],
  "allowedRecipientDomains": ["example.com", "vendor.test"],
  "blockedRecipients": ["ceo@example.com"],
  "allowAttachments": false,
  "maxRecipients": 3,
  "maxSubjectLength": 120,
  "maxBodyChars": 500,
  "allowedPurposes": ["status_update", "customer_support"],
  "defaultDecision": "deny"
}

Deterministic Evaluation Order

Rules run in this exact order:

  1. allowedTools
  2. allowedActorIds
  3. blockedRecipients
  4. allowedRecipientDomains
  5. allowAttachments
  6. maxRecipients
  7. maxSubjectLength
  8. maxBodyChars
  9. allowedPurposes

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.

CLI Usage

Build first:

npm install
npm run build

Run with explicit paths:

node dist/cli.js \
  --request fixtures/requests/allow-basic.request.json \
  --policy fixtures/policies/baseline.policy.json \
  --output ./allow-basic.decision.json

If --output is omitted, ActionProof writes ./actionproof-decision.json.

Exit Codes

  • 0 = allow
  • 1 = deny
  • 2 = invalid input or runtime error

Scripts

  • npm test
  • npm run typecheck
  • npm run build

Fixtures

Sample request and policy files live in fixtures/.

License

MIT