CrawlCheck
API · preflight

Policy as code

Keep your agent’s preflight policy in your repository as crawlcheck-policy.json: defaults, rules per action, and tests that say what decision you expect. It gets a content id, preflight uses it by id, and every receipt names the policy that decided.

1. Write the file

{
  "kind": "crawlcheck-policy",
  "v": 1,
  "name": "Shopping agent, production",
  "description": "Cite and read freely on fresh readings; a person approves every purchase; never touch accounts.",
  "defaults": {
    "max_age_hours": 168
  },
  "actions": {
    "cite": {
      "require_entity": true,
      "on_warn": "require_confirmation"
    },
    "connect": {
      "max_age_hours": 72,
      "on_warn": "require_confirmation"
    },
    "transact": {
      "max_age_hours": 24,
      "on_warn": "block",
      "human_approval": [
        "transact"
      ]
    },
    "administer": {
      "on_warn": "block",
      "deny": [
        "example.net"
      ]
    }
  },
  "tests": [
    {
      "domain": "crawlcheck.io",
      "action": "read",
      "expect": [
        "allow",
        "warn"
      ],
      "note": "our own site reads cleanly"
    },
    {
      "domain": "crawlcheck.io",
      "action": "transact",
      "expect": [
        "require_confirmation",
        "block",
        "unsupported"
      ],
      "note": "a purchase always needs a person"
    }
  ]
}

Fields per action: max_age_hours, on_warn (warn, require_confirmation or block), require_entity, human_approval, allow, deny. defaults apply to every action; actions.<action> overrides them. A policy can only make a decision stricter, never looser. JSON Schema: /schemas/policy.json.

2. Check and test it

Download crawlcheck-policy.mjs (zero dependencies, Node 20+):

node crawlcheck-policy.mjs lint crawlcheck-policy.json      # errors, and the policy id
node crawlcheck-policy.mjs test crawlcheck-policy.json      # runs tests[] against today's answers; exit 1 on a failure
node crawlcheck-policy.mjs publish crawlcheck-policy.json   # stores it under its id

In CI (GitHub Actions):

- run: curl -fsSO https://crawlcheck.io/crawlcheck-policy.mjs && node crawlcheck-policy.mjs test crawlcheck-policy.json

3. Use it by id

POST /api/v1/preflight
{"domain": "shop.example", "action": "transact", "policy_id": "pol1:<sha256>"}

The id is sha256 over the canonical normalised file, so the same rules always carry the same id, and the script re-checks the id the server returns. Stored policies never change; GET /api/v1/policy?id=… returns the exact file. A template or inline policy sent with policy_id combines with it, and the strictest value of each field wins.

API: POST /api/v1/policy · POST /api/v1/policy/test · preflight