{"name":"validate","intro":"The objective replacement for an LLM judge. `assert` evaluates a list of `{path, op, value}` rules over a JSON document and returns pass/fail per rule, the actual value that was seen, and a weighted score — reproducible, explainable and free. Around it sit JSON Schema validation, checksum-verified identifiers (card, IBAN, GSTIN, PAN, Aadhaar, ISBN, EAN, VIN…), email/URL/phone/IP syntax, and a SQL parser that flags writes before you run them.","when_to_use":["Scoring a document or an agent's output against explicit rules, instead of asking a model.","Validating a payload against a JSON Schema before sending it on.","Verifying an identifier by its checksum — not by whether it looks plausible.","Checking an email, URL, phone number or IP without a network round trip.","Inspecting SQL before execution: what it writes, which tables, whether it has a WHERE."],"network":false,"related":"[`text`](/docs/tools/text) `extract` to find identifiers before checking them · [`collections`](/docs/tools/collections) to reshape a document into the paths your rules expect · [`encode`](/docs/tools/encode) `jwt_decode` for token claims.","docs_url":"/docs/tools/validate","modes":[{"name":"json_schema","purpose":"Validate a document against a JSON Schema.","description":"Validates `data` against `schema` using the draft the schema declares, with format checking on. Every violation comes back with its JSON path, the validator that failed and the message — a failing document is a successful call (`ok: true`, `valid: false`), because “the document is invalid” is an answer, not an error. A schema that is itself malformed *is* an error, as is one that nests more than 50 levels deep or refers to itself (`{\"$ref\": \"#\"}`), which no validator can terminate on. A `pattern` or `patternProperties` key that can backtrack exponentially is refused too: jsonschema runs them on the same stdlib engine `text` does.","parameters":[{"name":"schema","type":"object","required":true,"doc":"The JSON Schema.","default":null},{"name":"data","type":"string \\| number \\| integer \\| boolean \\| array \\| object","required":false,"doc":"The document to validate.","default":null}],"examples":[{"mode":"json_schema","schema":{"$ref":"#"},"data":1},{"mode":"json_schema","schema":{"type":"object","required":["employee","leave"],"properties":{"employee":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"}}},"leave":{"type":"object","required":["type","days"],"properties":{"type":{"enum":["casual","sick","earned"]},"days":{"type":"integer","minimum":1,"maximum":2}}}}},"data":{"employee":{"id":"E-19","email":"asha@example.com"},"leave":{"type":"casual","days":3,"start":"2025-09-01"},"approvals":["manager"]}},{"mode":"json_schema","schema":{"type":"object","required":["employee","leave"],"properties":{"employee":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string"},"email":{"type":"string","format":"email"}}},"leave":{"type":"object","required":["type","days"],"properties":{"type":{"enum":["casual","sick","earned"]},"days":{"type":"integer","minimum":1,"maximum":2}}}}},"data":{"employee":{"id":"E-19","email":"asha@example.com"},"leave":{"type":"sick","days":2}}},{"mode":"json_schema","schema":{"type":"nonsense"},"data":{}}]},{"name":"assert","purpose":"Score a document against explicit rules.","description":"Evaluates rules of the form `{path, op, value}` over a document. `path` is a dotted path (`leave.days`, `items[0].sku`), `op` is one of `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `between`, `in`, `not_in`, `contains`, `contains_all`, `contains_any`, `starts_with`, `ends_with`, `matches`, `type`, `exists`, `missing`, `empty`, `not_empty`, `len_eq`/`len_gt`/`len_lt`/`len_between`, `before`, `after`, `on_or_after`, `is_email`, `is_url`, `is_date`, `is_uuid`, `unique`, `sum_eq`, `each`. Numbers compare numerically even when they arrive as strings, and dates compare as dates. Each rule may carry an `id`, a `message` shown when it fails and a `weight`; the response gives per-rule results, the failures on their own, and a weighted `score`.","parameters":[{"name":"data","type":"string \\| number \\| integer \\| boolean \\| array \\| object","required":false,"doc":"The document the rules are evaluated against.","default":null},{"name":"rules","type":"object[] \\| object","required":true,"doc":"The rules: `{path, op, value, id?, message?, weight?}`.","default":null}],"examples":[{"mode":"assert","data":{"employee":{"id":"E-19","email":"asha@example.com"},"leave":{"type":"casual","days":3,"start":"2025-09-01"},"approvals":["manager"]},"rules":[{"id":"days","path":"leave.days","op":"lte","value":2,"message":"casual leave is capped at 2 days","weight":3},{"id":"type","path":"leave.type","op":"in","value":["casual","sick","earned"]},{"id":"email","path":"employee.email","op":"is_email"},{"id":"start","path":"leave.start","op":"after","value":"2025-08-31"}]},{"mode":"assert","data":{"total":"1200.50","skus":["A1","B2","A1"]},"rules":[{"path":"total","op":"gt","value":1000},{"path":"skus","op":"unique"},{"path":"skus","op":"len_eq","value":3}]},{"mode":"assert","data":{"lines":[{"qty":2},{"qty":0}]},"rules":[{"path":"lines","op":"each","value":{"path":"qty","op":"gt","value":0}}]},{"mode":"assert","data":{"a":1},"rules":[{"path":"a","op":"frobnicate","value":1}]},{"mode":"assert","data":{"a":1},"rules":[{"path":"a","op":"between","value":5}]},{"mode":"assert","data":{"a":1},"rules":[{"path":"a","op":"type","value":"decimal"}]}]},{"name":"id","purpose":"Verify an identifier by its checksum.","description":"Checks an identifier against its real check-digit algorithm, not a regex that “looks right”. `kind` picks the scheme: `card`/`luhn`, `iban` (mod-97 plus country length), `gstin`, `pan`, `aadhaar` (Verhoeff), `isbn`, `ean`/`upc`/`gtin`, `ifsc`, `vin`, `uuid`, `upi`, `pincode`, `ssn`, `verhoeff`, `mod97`. An identifier that fails its checksum is a successful call reporting `valid: false` — only an unknown `kind` or a missing value is an error. Card numbers come back masked, never echoed in full. A valid ISBN is returned in both forms (`isbn10`, `isbn13`); a 979 book has no ISBN-10.","parameters":[{"name":"kind","type":"string","required":true,"doc":"Which scheme to check against.","default":null},{"name":"value","type":"string \\| number \\| integer","required":true,"doc":"The identifier.","default":null}],"examples":[{"mode":"id","kind":"card","value":"4111 1111 1111 1111"},{"mode":"id","kind":"card","value":"4111 1111 1111 1112"},{"mode":"id","kind":"iban","value":"GB82 WEST 1234 5698 7654 32"},{"mode":"id","kind":"gstin","value":"19ABCDE1234F1ZX"},{"mode":"id","kind":"pan","value":"ABCDE1234F"},{"mode":"id","kind":"aadhaar","value":"2345 6789 0124"},{"mode":"id","kind":"isbn","value":"0-306-40615-2"},{"mode":"id","kind":"card"}]},{"name":"email","purpose":"Check an address's syntax and shape.","description":"Validates the syntax of an email address, splits it into local part and domain, normalises the domain to lower case, checks the 64-character local-part limit and flags known disposable domains. This is a syntax check only — deliverability is not tested, and the response says so. An invalid address is reported as `valid: false`; this mode never returns `ok: false`.","parameters":[{"name":"value","type":"string \\| number \\| integer","required":true,"doc":"The address to check.","default":null}],"examples":[{"mode":"email","value":"Asha.Roy@Example.COM"},{"mode":"email","value":"throwaway@mailinator.com"},{"mode":"email","value":"asha@@example..com"}],"never_fails":"Nothing makes this mode return `ok: false`. A missing or malformed address is reported as `valid: false` with a `reason`, because “this address is invalid” is the answer you asked for."},{"name":"url","purpose":"Parse and check a URL.","description":"Parses a URL into scheme, host, port, path, query and fragment, notes whether the host is an IP literal, extracts the TLD and reports whether the scheme is secure. Accepted schemes are `http`, `https`, `ftp`, `ftps`, `mailto`, `tel` and `file`. Two things a syntax check can still tell you are warned about: credentials before the `@` (`https://user:pass@evil.example.com` reads as though it points at `user`), and a punycode or non-ASCII host, which can imitate another name. Like `email`, this is syntax only and never returns `ok: false`.","parameters":[{"name":"value","type":"string \\| number \\| integer","required":true,"doc":"The URL to check.","default":null}],"examples":[{"mode":"url","value":"https://user:pass@xn--80ak6aa92e.com/x"},{"mode":"url","value":"https://leftbrain.dev:8443/docs/tools?q=math#eval"},{"mode":"url","value":"leftbrain.dev/docs"},{"mode":"url","value":"http://192.168.1.10:8080/health"}],"never_fails":"Nothing makes this mode return `ok: false`. An unusable URL comes back as `valid: false` with a `reason`."},{"name":"phone","purpose":"Check a phone number against a country's format.","description":"Validates a phone number and normalises it to E.164. A number starting with `+` (or `00`) is checked against the country code it carries and the region is guessed back; a national number needs a `region` so the tool knows which rules to apply — asking for one rather than assuming the caller's. Trunk prefixes are stripped and that is reported. A number that does not fit the pattern is `valid: false`, not an error; a missing or unsupported `region` is.","parameters":[{"name":"value","type":"string \\| number \\| integer","required":true,"doc":"The number, in any punctuation.","default":null},{"name":"region","type":"string","required":false,"doc":"ISO country code, required for national numbers.","default":null}],"examples":[{"mode":"phone","value":"+91 98765 43210"},{"mode":"phone","value":"098765 43210","region":"IN"},{"mode":"phone","value":"12345 67890","region":"IN"},{"mode":"phone","value":"9876543210"},{"mode":"phone","value":"9876543210","region":"ZZ"}]},{"name":"ip","purpose":"Parse an IP address or CIDR network.","description":"Parses an IPv4 or IPv6 address and reports whether it is private, loopback, multicast, globally routable or reserved, along with its compressed and exploded forms. A value containing `/` is read as a network and returns its size and first and last addresses. A link-local address may carry a zone id (`fe80::1%eth0`, RFC 4007), which is reported as `zone`. Never returns `ok: false`.","parameters":[{"name":"value","type":"string \\| number \\| integer","required":true,"doc":"An IP address or CIDR network.","default":null}],"examples":[{"mode":"ip","value":"192.168.1.10"},{"mode":"ip","value":"10.0.0.0/24"},{"mode":"ip","value":"2001:db8::1"},{"mode":"ip","value":"300.1.1.1"}],"never_fails":"Nothing makes this mode return `ok: false`. An unparseable value comes back as `valid: false` with the parser's reason."},{"name":"cidr","purpose":"Membership and overlap of CIDR blocks.","description":"Answers the two questions an allowlist raises: is this address (or smaller block) inside that network — `contains` — and do these blocks overlap. One `network` returns its size, usable host count, bounds and masks; add `value` for membership. A list of two or more networks returns every pair with its relation — `equal`, `a_contains_b`, `b_contains_a` or `disjoint`; CIDR blocks cannot partially overlap. A block written with host bits set is read as its network and the reading recorded. An unparseable network or value is an error; a mixed IPv4/IPv6 comparison is a `contains: false` with the reason in `assumptions`.","parameters":[{"name":"network","type":"string \\| string[]","required":true,"doc":"A CIDR block, or a list of two or more to compare.","default":null},{"name":"value","type":"string \\| number \\| integer","required":false,"doc":"An address or block to test for membership in `network`.","default":null}],"examples":[{"mode":"cidr","network":"10.0.0.0/24","value":"10.0.0.200"},{"mode":"cidr","network":["10.0.0.0/16","10.0.5.0/24","192.168.0.0/24"]},{"mode":"cidr","network":"192.168.1.77/24"},{"mode":"cidr","network":"10.0.0.0/33"}]},{"name":"sql_parse","purpose":"Inspect SQL before running it.","description":"Parses SQL with sqlglot and reports, per statement: the statement type, whether it writes, which tables it reads and writes, the columns referenced, whether it has a `WHERE` and a `LIMIT`, and a normalised form. `UPDATE`/`DELETE` without a `WHERE` and any `DROP`/`TRUNCATE` are raised in `warnings`. A trailing comment or a stray semicolon is not counted as a statement. Syntactically invalid SQL is a successful call reporting `valid: false` — that is the answer you wanted.","parameters":[{"name":"sql","type":"string","required":true,"doc":"One or more SQL statements.","default":null},{"name":"dialect","type":"string","required":false,"doc":"sqlglot dialect, e.g. `postgres`, `mysql`, `snowflake`.","default":"generic"}],"examples":[{"mode":"sql_parse","sql":"SELECT o.id, c.name FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.total > 100 LIMIT 50"},{"mode":"sql_parse","sql":"DELETE FROM sessions"},{"mode":"sql_parse","sql":"SELCT * FROM t WHERE"},{"mode":"sql_parse","sql":"SELECT 1","dialect":"klingon"}]},{"name":"regex","purpose":"Check that a pattern compiles.","description":"Compiles a regular expression and reports its group count and named groups, or why it failed and at which character. Use it to validate a user-supplied pattern before handing it to [`text`](/docs/tools/text). A pattern that does not compile is `valid: false`, not an error. This mode judges a pattern rather than running it, so one that can backtrack exponentially is still `valid: true` — with `backtracking_risk` naming the shape and a warning saying so. The same pattern handed to `text.regex_match` is refused outright.","parameters":[{"name":"pattern","type":"string","required":true,"doc":"The regular expression to compile.","default":null}],"examples":[{"mode":"regex","pattern":"(a+)+$"},{"mode":"regex","pattern":"(?P<year>\\d{4})-(?P<month>\\d{2})"},{"mode":"regex","pattern":"([a-z"},{"mode":"regex"}]}]}