{"id":128445,"name":"Caruana Utilities","description":"Deterministic developer utilities for agents: encoding, hashing and checksum verification, certificate and key inspection, time-zone arithmetic, cron explanation, JSON validation and querying, text diffs and exact text statistics. Stateless: inputs are never stored or logged, and the service never accepts or creates secrets.","card_url":"https://util.caruana.me/.well-known/agent-card.json","endpoint":"https://util.caruana.me/a2a","protocol_version":"1.0","first_seen":"2026-10-15T12:03:49.057625+00:00","last_verified":"2026-10-15T14:09:04.055992+00:00","card":{"name":"Caruana Utilities","skills":[{"id":"register","name":"Register for credentials","tags":["auth","registration","onboarding"],"examples":["{\"skill\":\"register\",\"registration\":{\"client_name\":\"My agent\",\"agent\":{\"purpose\":\"Verify release checksums\"}}}"],"inputModes":["application/json"],"description":"Create a client_id and client_secret for this agent. No credentials required. Send a data part {\"skill\":\"register\",\"registration\":<document>} matching the registration schema in the registration extension.","outputModes":["application/json"],"securityRequirements":[]},{"id":"url_encode","name":"URL: Encode","tags":["Encoding","url"],"examples":["{\"skill\":\"url_encode\",\"arguments\":{\"input\":\"hello world & friends\"}}","{\"skill\":\"url_encode\",\"arguments\":{\"input\":\"a b+c\",\"mode\":\"form\"}}"],"inputModes":["application/json"],"description":"Percent-encode text (RFC 3986). Percent-encodes the UTF-8 bytes of `input`. `component` matches JavaScript encodeURIComponent, `uri` matches encodeURI, and `form` is application/x-www-form-urlencoded (spaces become `+`). Call with a data part {\"skill\":\"url_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_encode/","outputModes":["application/json"]},{"id":"url_decode","name":"URL: Decode","tags":["Encoding","url"],"examples":["{\"skill\":\"url_decode\",\"arguments\":{\"input\":\"a+b%3Dc\",\"mode\":\"form\"}}"],"inputModes":["application/json"],"description":"Decode percent-encoded text. Decodes `%XX` sequences as UTF-8. In `form` mode `+` is first turned into a space. Call with a data part {\"skill\":\"url_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_decode/","outputModes":["application/json"]},{"id":"base64_encode","name":"Base64: Encode","tags":["Encoding","base64"],"examples":["{\"skill\":\"base64_encode\",\"arguments\":{\"input\":\"héllo wörld\"}}","{\"skill\":\"base64_encode\",\"arguments\":{\"input\":\"??>\",\"mode\":\"url\"}}"],"inputModes":["application/json"],"description":"Encode text as Base64 (RFC 4648). Encodes the UTF-8 bytes of `input`. `standard` uses `+/` with `=` padding; `url` uses `-_` without padding. Call with a data part {\"skill\":\"base64_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/base64_encode/","outputModes":["application/json"]},{"id":"base64_decode","name":"Base64: Decode","tags":["Encoding","base64"],"examples":["{\"skill\":\"base64_decode\",\"arguments\":{\"input\":\"eyJhbGciOiJIUzI1NiJ9\",\"mode\":\"url\"}}"],"inputModes":["application/json"],"description":"Decode Base64 to UTF-8 text. Accepts either alphabet, with or without padding, and ignores whitespace. `mode` does not change decoding. Call with a data part {\"skill\":\"base64_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/base64_decode/","outputModes":["application/json"]},{"id":"html_encode","name":"HTML entities: Encode","tags":["Encoding","html"],"examples":["{\"skill\":\"html_encode\",\"arguments\":{\"input\":\"<a href=\\\"x\\\">Tom & Jerry</a>\"}}"],"inputModes":["application/json"],"description":"Escape text for HTML. `minimal` escapes `& < > \" '`, which is sufficient inside element content and quoted attributes. `ascii` additionally writes every non-ASCII code point as `&#x…;`. Call with a data part {\"skill\":\"html_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/html_encode/","outputModes":["application/json"]},{"id":"html_decode","name":"HTML entities: Decode","tags":["Encoding","html"],"examples":["{\"skill\":\"html_decode\",\"arguments\":{\"input\":\"&eacute;t&eacute; &#8364;5 &hearts;\"}}"],"inputModes":["application/json"],"description":"Decode HTML entities. Decodes all 2,231 named entities of the HTML Living Standard plus decimal and hex numeric references, using the HTML parser rules (legacy entities without `;` included). Call with a data part {\"skill\":\"html_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/html_decode/","outputModes":["application/json"]},{"id":"hex_encode","name":"Hex: Text → Hex","tags":["Encoding","hex"],"examples":["{\"skill\":\"hex_encode\",\"arguments\":{\"input\":\"Hi €\",\"mode\":\"spaced\"}}"],"inputModes":["application/json"],"description":"Text to hexadecimal UTF-8 bytes. Writes each UTF-8 byte of `input` as two lowercase hex digits in the chosen layout. Call with a data part {\"skill\":\"hex_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hex_encode/","outputModes":["application/json"]},{"id":"hex_decode","name":"Hex: Hex → Text","tags":["Encoding","hex"],"examples":["{\"skill\":\"hex_decode\",\"arguments\":{\"input\":\"0x48, 0x69\"}}"],"inputModes":["application/json"],"description":"Hexadecimal bytes to text. Accepts any mix of plain, spaced, `\\x`, `0x`, comma, and colon separated hex, in either case. Call with a data part {\"skill\":\"hex_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hex_decode/","outputModes":["application/json"]},{"id":"punycode_encode","name":"Punycode: To ASCII","tags":["Encoding","punycode"],"examples":["{\"skill\":\"punycode_encode\",\"arguments\":{\"input\":\"münchen.de\"}}"],"inputModes":["application/json"],"description":"Unicode domain to ASCII (IDNA / RFC 3492). `domain` converts each non-ASCII label to `xn--` form (dots and email local parts preserved). `raw` applies bare RFC 3492 Punycode with no prefix. Call with a data part {\"skill\":\"punycode_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/punycode_encode/","outputModes":["application/json"]},{"id":"punycode_decode","name":"Punycode: To Unicode","tags":["Encoding","punycode"],"examples":["{\"skill\":\"punycode_decode\",\"arguments\":{\"input\":\"xn--fiqs8s.xn--fiqz9s\"}}"],"inputModes":["application/json"],"description":"ASCII (xn--) domain to Unicode. `domain` decodes each `xn--` label. `raw` decodes a bare Punycode string. Call with a data part {\"skill\":\"punycode_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/punycode_decode/","outputModes":["application/json"]},{"id":"hash","name":"Hash","tags":["Hashing","hash"],"examples":["{\"skill\":\"hash\",\"arguments\":{\"input\":\"hello\",\"algorithm\":[\"sha256\"]}}","{\"skill\":\"hash\",\"arguments\":{\"input\":\"abc\",\"algorithm\":[\"md5\",\"sha256\",\"blake3\"]}}","{\"skill\":\"hash\",\"arguments\":{\"input_base64\":\"AAECAw==\",\"algorithm\":[\"sha384\"],\"encoding\":\"base64\"}}"],"inputModes":["application/json"],"description":"Digest data with one or more hash algorithms. Computes MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-512, BLAKE2b-512, BLAKE3 digests of the data. MD5 and SHA-1 are broken for collision resistance: use them only to match existing checksums. HMAC is deliberately not offered by the API, because it needs a secret key and this server never accepts secrets; compute HMACs on the page, which runs locally. Call with a data part {\"skill\":\"hash\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hash/","outputModes":["application/json"]},{"id":"hash_verify","name":"Verify a checksum","tags":["Hashing","hash-verify"],"examples":["{\"skill\":\"hash_verify\",\"arguments\":{\"input\":\"abc\",\"expected\":\"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\"}}","{\"skill\":\"hash_verify\",\"arguments\":{\"input\":\"abc\",\"filename\":\"b.txt\",\"expected\":\"900150983cd24fb0d6963f7d28e17f72  a.txt\\nba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad  b.txt\"}}"],"inputModes":["application/json"],"description":"Check data against an expected hash or a checksum list. Hashes the data with every algorithm whose digest length matches the expected hash (for 64 hex digits: SHA-256, SHA3-256 and BLAKE3) and reports whether any matches. `expected` may be hex, Base64, SRI (`sha384-…`), prefixed (`sha256:…`), or a whole GNU/BSD checksum file, in which case the line for `filename` (or the uploaded file name) is used. A mismatch is a successful response with `match: false`. Call with a data part {\"skill\":\"hash_verify\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hash_verify/","outputModes":["application/json"]},{"id":"fingerprint","name":"Key and certificate fingerprints","tags":["Keys & Certificates","fingerprint"],"examples":["{\"skill\":\"fingerprint\",\"arguments\":{\"input\":\"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHGVluSiNj6bqXsllRWYUFXc2JNxW9mDP9PntMYyVHeM me@host\"}}","{\"skill\":\"fingerprint\",\"arguments\":{\"input\":\"-----BEGIN PGP PUBLIC KEY BLOCK-----\\n\\nxioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf\\nGwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy\\nKwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw\\ngyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE\\nQsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn\\n+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh\\nBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8\\nj+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805\\nI8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==\\n-----END PGP PUBLIC KEY BLOCK-----\\n\"}}"],"inputModes":["application/json"],"description":"Fingerprint SSH keys, X.509 certificates, SPKI public keys, and OpenPGP keys. Finds every public key in `input` and returns its fingerprints in the formats other tools print. SSH: `ssh-keygen -l` SHA256 and MD5. Certificates: `openssl x509 -fingerprint` SHA-1 and SHA-256 over the DER, plus the RFC 7469 SPKI pin. PEM public keys: SHA-256 over the SubjectPublicKeyInfo. Where an equivalent exists, the SSH fingerprint of the same key is included, so you can confirm that a certificate and an SSH key share a key. OpenPGP: v4 (SHA-1) and v6 (SHA-256) fingerprints and key IDs for the primary key and subkeys. Private keys are refused. Call with a data part {\"skill\":\"fingerprint\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/fingerprint/","outputModes":["application/json"]},{"id":"cert_decode","name":"Decode certificates and CSRs","tags":["Keys & Certificates","cert"],"examples":["{\"skill\":\"cert_decode\",\"arguments\":{\"input\":\"-----BEGIN CERTIFICATE-----\\nMIIBYDCCARKgAwIBAgIQcuMlZ0gk8qldBRVY4uV0BTAFBgMrZXAwFjEUMBIGA1UE\\nAxMLZXhhbXBsZS5jb20wHhcNMjYxMDE0MDA1MjM5WhcNMjcxMDE0MDA1MjM5WjAW\\nMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAqMAUGAytlcAMhAHGVluSiNj6bqXsllRWY\\nUFXc2JNxW9mDP9PntMYyVHeMo3YwdDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQE\\nAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFAmd\\nd/YA6wQehHCnkI05mwtULXOMMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMAUGAytl\\ncANBAKbfzTFPGlLacXH+cIikicbI4CSvJj/ZkCgMWJNjq649UzUHvJvhe2rQoLwM\\nDFaoibsbMY3x6ucpRzC+yl9t7ww=\\n-----END CERTIFICATE-----\\n\",\"hostname\":\"example.com\"}}"],"inputModes":["application/json"],"description":"Decode X.509 certificates, chains, and certificate requests. Decodes every certificate (PEM, DER, Base64 DER, or PKCS#7 bundle) and CSR in the input. For chains it checks, for each adjacent pair, that the issuer name matches and that the signature verifies with the next certificate's key. With `hostname` it reports which certificates cover that name under RFC 6125 wildcard rules. It does not establish trust: there is no root store, and revocation (OCSP/CRL) is not checked. Call with a data part {\"skill\":\"cert_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/cert_decode/","outputModes":["application/json"]},{"id":"tls_check","name":"Check a server's TLS certificate","tags":["Keys & Certificates","tls"],"examples":["{\"skill\":\"tls_check\",\"arguments\":{\"host\":\"example.com\"}}"],"inputModes":["application/json"],"description":"Connect to a host and check the certificate chain it presents: trust, host name, expiry, protocol. Connects to `host:port` with OpenSSL 3, using SNI, and verifies the presented chain against the Mozilla root store, including host name verification (RFC 6125). It reports OpenSSL's verdict and every verify error with its chain depth, plus the negotiated protocol, cipher and key-exchange group. The chain is then decoded exactly as `cert_decode` would, with ordering, signature and expiry notes. Only direct TLS is supported (no STARTTLS). Revocation (OCSP/CRL) is not checked. Call with a data part {\"skill\":\"tls_check\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tls_check/","outputModes":["application/json"]},{"id":"jwt_decode","name":"Decode and verify a JWT","tags":["Inspect & Identify","jwt"],"examples":["{\"skill\":\"jwt_decode\",\"arguments\":{\"token\":\"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImV4YW1wbGUtMjAyNiJ9.eyJzY29wZSI6InJlYWQ6cmVwb3J0cyIsImVtYWlsIjoiYWRhQGV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmV4YW1wbGUuY29tLyIsInN1YiI6InVzZXItNDIiLCJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsImlhdCI6MTc2NzIyNTYwMCwibmJmIjoxNzY3MjI1NjAwLCJleHAiOjE3NjcyMjkyMDAsImp0aSI6ImI3ZTRjMmEwLTVmMWQtNGU4YS05YzNiLTJkNmY4YTFlMGM0NyJ9.I65iVa8TuYZWzTQrLDMQtUTiAvBx5ucG_bloyYh-4cmJGpXyB-gHHaEzUsvpf1P1FGIYEkropakR5Gi_cDoIGQ\",\"key\":\"{\\\"keys\\\":[{\\\"kty\\\":\\\"EC\\\",\\\"crv\\\":\\\"P-256\\\",\\\"x\\\":\\\"KvQwz-fAGPce4KhfOnfsQLYyMSQIyvO-gjZoneQ_QC4\\\",\\\"y\\\":\\\"hqZ-ZkRarQ1A-f0W87Kb-77GubouttkHeB4LhfUDKW0\\\",\\\"kid\\\":\\\"example-2026\\\",\\\"alg\\\":\\\"ES256\\\",\\\"use\\\":\\\"sig\\\"}]}\",\"at\":\"2026-01-01T00:30:00Z\"}}","{\"skill\":\"jwt_decode\",\"arguments\":{\"token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\",\"at\":\"2026-01-01T00:00:00Z\"}}"],"inputModes":["application/json"],"description":"Decode a JWT, check its claims and algorithm, and optionally verify it with a public key. Decodes a compact JWS (RFC 7515/7519): header, payload, and the registered claims, with `exp`, `nbf` and `iat` as ISO times and seconds relative to `at`. Flags expired, not-yet-valid, `alg: none`, weak or unusual algorithms, and a missing `exp`. A compact JWE (5 segments) is recognised and its header shown, but it cannot be decrypted. With `key`, verifies the signature using a PUBLIC key only: a JWK, a JWKS (selected by the token `kid`), a `PUBLIC KEY` PEM, or a `CERTIFICATE` PEM. HS256/HS384/HS512 cannot be verified here because they need a shared secret, which this service never accepts. The server never fetches keys: pass the JWKS JSON itself, not its URL. Decoding is not verification: never trust claims from a token whose `verification.outcome` is not `valid`. Call with a data part {\"skill\":\"jwt_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/jwt_decode/","outputModes":["application/json"]},{"id":"url_parse","name":"Parse a URL","tags":["Inspect & Identify","url-parse"],"examples":["{\"skill\":\"url_parse\",\"arguments\":{\"input\":\"https://user@Example.COM:443/a%20b/c?tag=x&tag=y&q=caf%C3%A9+au+lait#top\"}}","{\"skill\":\"url_parse\",\"arguments\":{\"input\":\"../img/logo.png?v=2\",\"base\":\"https://example.com/docs/guide/\"}}","{\"skill\":\"url_parse\",\"arguments\":{\"input\":\"http://[fd00::1]:8080/admin\"}}"],"inputModes":["application/json"],"description":"Split a URL into its parts with the WHATWG URL parser browsers use. Parses a URL exactly as browsers and Cloudflare Workers do (WHATWG URL Standard) and returns every component: scheme, username, host in ASCII and Unicode forms, port and default port, origin, path segments decoded, query parameters as an ordered list (duplicates kept), and fragment. It classifies the host (domain, IPv4, IPv6, localhost, private or other special-purpose range) without resolving DNS. A password, if present, is never returned: `hasPassword` is true and `href` shows `***` instead. With `base`, a relative reference is resolved first. Call with a data part {\"skill\":\"url_parse\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_parse/","outputModes":["application/json"]},{"id":"ip_inspect","name":"Inspect an IP address","tags":["Inspect & Identify","ip"],"examples":["{\"skill\":\"ip_inspect\",\"arguments\":{\"address\":\"::ffff:a00:1\"}}","{\"skill\":\"ip_inspect\",\"arguments\":{\"address\":\"0x7f.1\",\"cidrs\":[\"127.0.0.0/8\",\"10.0.0.0/8\"]}}","{\"skill\":\"ip_inspect\",\"arguments\":{\"address\":\"64:ff9b::c000:221/96\"}}"],"inputModes":["application/json"],"description":"Canonical form, special-purpose ranges, embedded IPv4 and global reachability of any IPv4 or IPv6 address. Parses an IPv4 or IPv6 address in any spelling and returns its canonical form (RFC 5952 for IPv6), the full expanded form and integer value, any IPv4 address embedded in an IPv6 address (IPv4-mapped, IPv4-compatible, IPv4-translated, NAT64 `64:ff9b::/96` and `64:ff9b:1::/48`, 6to4, Teredo), every range it falls in from the IANA IPv4 and IPv6 Special-Purpose Address Registries (with their source, destination, forwardable, globally-reachable and reserved columns), and whether it is globally reachable. An embedded IPv4 address is checked too, so `::ffff:a00:1` is reported as private-use `10.0.0.1`. Non-standard IPv4 spellings that browsers and `inet_aton` accept (`127.1`, `0x7f.0.0.1`, `0177.0.0.1`, `2130706433`) are read the way they are and flagged. A `/prefix` adds the network, and `cidrs` tests membership. Nothing is resolved or contacted. Call with a data part {\"skill\":\"ip_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/ip_inspect/","outputModes":["application/json"]},{"id":"uuid_generate","name":"Generate UUIDs","tags":["Inspect & Identify","uuid"],"examples":["{\"skill\":\"uuid_generate\",\"arguments\":{\"version\":\"4\"}}","{\"skill\":\"uuid_generate\",\"arguments\":{\"version\":\"7\",\"count\":5}}"],"inputModes":["application/json"],"description":"Generate random (v4) or time-ordered (v7) UUIDs, up to 1000 at a time. Generates RFC 9562 UUIDs. Version 4: 122 random bits from `crypto.randomUUID()`. Version 7: a 48-bit Unix millisecond timestamp, then a 42-bit counter (randomly seeded each millisecond, incremented within it) and 32 fresh random bits, so every batch is strictly increasing in both byte and string order. UUIDs are identifiers, not secrets: do not use them as passwords, API keys, session tokens or capability URLs, even though v4 uses a CSPRNG. Call with a data part {\"skill\":\"uuid_generate\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/uuid_generate/","outputModes":["application/json"]},{"id":"uuid_inspect","name":"Inspect a UUID","tags":["Inspect & Identify","uuid"],"examples":["{\"skill\":\"uuid_inspect\",\"arguments\":{\"input\":\"017F22E2-79B0-7CC3-98C4-DC0C0C07398F\"}}","{\"skill\":\"uuid_inspect\",\"arguments\":{\"input\":\"C232AB00-9414-11EC-B3C8-9F6BDECED846\"}}"],"inputModes":["application/json"],"description":"Read a UUID’s version, variant and embedded timestamp, clock sequence and node. Parses a UUID written as 8-4-4-4-12 hex, 32 hex digits, `{…}` or `urn:uuid:…` (any case) and reports its RFC 9562 variant and version, whether it is the Nil or Max UUID, and the fields its version defines: the timestamp of v1, v6 and v7 as ISO 8601 (v1/v6 to 100 ns), and the clock sequence and node of v1 and v6. It also returns the UUID in every common format. Call with a data part {\"skill\":\"uuid_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/uuid_inspect/","outputModes":["application/json"]},{"id":"text_inspect","name":"Inspect and count text","tags":["Text & Data","text"],"examples":["{\"skill\":\"text_inspect\",\"arguments\":{\"input\":\"strawberry\",\"find\":\"r\"}}","{\"skill\":\"text_inspect\",\"arguments\":{\"input\":\"Café 👍🏽​ ok\",\"breakdown\":8,\"locale\":\"en\"}}"],"inputModes":["application/json"],"description":"Exact counts of characters, bytes, words and lines; find substrings; reveal invisible characters. Counts text the ways software disagrees about: grapheme clusters (what people see as characters), code points, UTF-16 code units (JavaScript length) and UTF-8 bytes; lines with their line-ending style; words and sentences (Intl.Segmenter); and letters, digits, whitespace and punctuation by Unicode property. With `find`, counts occurrences of a substring or character and returns each position (e.g. `find=r` in `strawberry` is 3). It also reports invisible and deceptive characters with positions: zero-width characters, bidirectional controls (Trojan Source, CVE-2021-42574), unusual spaces such as NBSP, BOM, control characters, Unicode tag characters (hidden-prompt smuggling), and Latin look-alikes in mixed-script words. Use this instead of counting characters yourself. Call with a data part {\"skill\":\"text_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/text_inspect/","outputModes":["application/json"]},{"id":"time_now","name":"Current time","tags":["Time & Scheduling","time"],"examples":["{\"skill\":\"time_now\",\"arguments\":{}}","{\"skill\":\"time_now\",\"arguments\":{\"zones\":[\"UTC\",\"America/New_York\",\"Asia/Kolkata\"],\"formats\":[\"rfc2822\"]}}"],"inputModes":["application/json"],"description":"The current instant from the server clock, in one or more time zones. Returns the current time from the server's clock when the request is processed (millisecond resolution) as UTC, Unix seconds and milliseconds, and, for each requested zone, the local ISO 8601 time with offset, weekday, ISO week, day of year, zone abbreviation, UTC offset and whether DST is in effect. Use it instead of guessing today's date. Call with a data part {\"skill\":\"time_now\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_now/","outputModes":["application/json"]},{"id":"time_convert","name":"Convert a time","tags":["Time & Scheduling","time"],"examples":["{\"skill\":\"time_convert\",\"arguments\":{\"input\":\"1791900000\",\"zones\":[\"UTC\",\"Europe/Paris\"]}}","{\"skill\":\"time_convert\",\"arguments\":{\"input\":\"2026-03-08T02:30\",\"from_zone\":\"America/New_York\",\"zones\":[\"UTC\"]}}","{\"skill\":\"time_convert\",\"arguments\":{\"input\":\"Tue, 13 Oct 2026 14:30:00 +0200\",\"zones\":[\"Asia/Tokyo\"],\"formats\":[\"http\",\"iso_week_date\",\"human\"]}}"],"inputModes":["application/json"],"description":"Parse a date-time or Unix timestamp and show it in other zones and formats. Parses `input` and returns the instant in UTC, as Unix seconds and milliseconds, and in each zone of `zones`. The response says exactly how the input was read: the detected format, the inferred timestamp unit (with what the other units would have meant), and, for a wall-clock time without an offset, the zone used and whether that local time was unique, skipped by a DST gap, or repeated in a DST overlap. Call with a data part {\"skill\":\"time_convert\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_convert/","outputModes":["application/json"]},{"id":"time_diff","name":"Difference between two times","tags":["Time & Scheduling","time"],"examples":["{\"skill\":\"time_diff\",\"arguments\":{\"start\":\"2026-03-07T12:00\",\"end\":\"2026-03-08T12:00\",\"zone\":\"America/New_York\"}}","{\"skill\":\"time_diff\",\"arguments\":{\"start\":\"2026-01-31T10:00:00Z\",\"end\":\"2026-03-01T09:00:00Z\"}}"],"inputModes":["application/json"],"description":"Elapsed time and calendar difference between two instants, DST-aware. Computes `end` minus `start`. `total` is exact elapsed time (a day is 86,400,000 ms). `calendar` is the breakdown in years, months, days, hours, minutes, seconds and milliseconds as a calendar in `zone` sees it, counted forward from the earlier instant: adding it to the earlier instant with `time_add` in the same zone gives the later instant exactly. Across a DST change the two differ: 12:00 to 12:00 the next day is `P1D` on the calendar but 23 or 25 hours elapsed. `calendar_days` counts midnights crossed in `zone`. Call with a data part {\"skill\":\"time_diff\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_diff/","outputModes":["application/json"]},{"id":"time_add","name":"Add or subtract a duration","tags":["Time & Scheduling","time"],"examples":["{\"skill\":\"time_add\",\"arguments\":{\"input\":\"2026-03-07T12:00:00-05:00\",\"duration\":\"P1D\",\"zone\":\"America/New_York\"}}","{\"skill\":\"time_add\",\"arguments\":{\"input\":\"2026-01-31\",\"amount\":1,\"amount_unit\":\"months\"}}","{\"skill\":\"time_add\",\"arguments\":{\"input\":\"2026-10-13T00:30:00Z\",\"duration\":\"PT90M\",\"subtract\":true}}"],"inputModes":["application/json"],"description":"Add or subtract an ISO 8601 duration to an instant, calendar-aware in a time zone. Applies the duration the way JavaScript Temporal does (`ZonedDateTime.add`): years, months, weeks and days move the wall-clock date in `zone` and keep the wall-clock time, so `P1D` across a DST change lands at the same local time (23 or 25 hours later); a day of the month that does not exist is clamped to the last day (Jan 31 + `P1M` = Feb 28/29); then hours, minutes, seconds and milliseconds are added as exact elapsed time (`PT24H` is always 86,400 s). If the intermediate wall-clock time falls in a DST gap or overlap it is resolved with `disambiguation` and reported in `notes`. Call with a data part {\"skill\":\"time_add\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_add/","outputModes":["application/json"]},{"id":"cron_explain","name":"Explain a cron expression","tags":["Time & Scheduling","cron"],"examples":["{\"skill\":\"cron_explain\",\"arguments\":{\"expression\":\"*/15 9-17 * * 1-5\",\"zone\":\"America/New_York\",\"from\":\"2026-10-13T16:50:00Z\",\"count\":3}}","{\"skill\":\"cron_explain\",\"arguments\":{\"expression\":\"0 0 13 * 5\",\"from\":\"2026-11-01T00:00:00Z\",\"count\":4}}","{\"skill\":\"cron_explain\",\"arguments\":{\"expression\":\"30 2 * * *\",\"zone\":\"America/New_York\",\"from\":\"2026-03-07T00:00:00-05:00\",\"count\":3}}"],"inputModes":["application/json"],"description":"Validate a cron expression, describe it in English, and list its next run times in a zone. Accepts the 5-field crontab form (minute hour day-of-month month day-of-week), a 6-field form whose first field is seconds, and the macros @yearly, @annually, @monthly, @weekly, @daily, @midnight, @hourly. Returns an English description, a field-by-field breakdown with the expanded values, the day-matching rule in effect, and the next run times after `from` in `zone`. Day-of-month and day-of-week follow Vixie cron: when both are restricted a day matches if EITHER matches (`0 0 13 * 5` runs on every 13th AND every Friday); a field starting with `*` (such as `*/2`) counts as unrestricted, and then a day must match both. Errors name the offending field. Call with a data part {\"skill\":\"cron_explain\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/cron_explain/","outputModes":["application/json"]},{"id":"text_diff","name":"Compare two texts","tags":["Text & Data","diff"],"examples":["{\"skill\":\"text_diff\",\"arguments\":{\"before\":\"alpha\\nbeta\\ngamma\\n\",\"after\":\"alpha\\nBETA\\ngamma\\ndelta\\n\",\"from_label\":\"a/notes.txt\",\"to_label\":\"b/notes.txt\"}}","{\"skill\":\"text_diff\",\"arguments\":{\"before\":\"The quick brown fox\",\"after\":\"the quick red fox\",\"mode\":\"words\",\"ignore_case\":true}}"],"inputModes":["application/json"],"description":"Diff two texts by line, word or character: unified diff, structured changes, and stats. Compares `before` with `after` using jsdiff (Myers' O(ND) algorithm). `changes` is the full sequence of added, removed and unchanged pieces at the chosen granularity; concatenating the unchanged and removed values gives `before`, unchanged and added gives `after` (when ignoring whitespace or case, unchanged pieces are taken from `after`). `unified` and `hunks` are always a line-level unified diff (GNU `diff -u` format) with `context` lines, whatever the mode. `identical` is true when no differences remain under the chosen options; `exact_match` compares the raw strings. Limits: 200,000 characters per text; at most 5000 differing lines, or 2000 differing words or characters. Call with a data part {\"skill\":\"text_diff\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/text_diff/","outputModes":["application/json"]},{"id":"json_format","name":"Format and validate JSON","tags":["Text & Data","json"],"examples":["{\"skill\":\"json_format\",\"arguments\":{\"input\":\"{\\\"b\\\":[1,2,{\\\"d\\\":1.0,\\\"c\\\":null}],\\\"a\\\":\\\"x\\\"}\",\"sort_keys\":true}}","{\"skill\":\"json_format\",\"arguments\":{\"input\":\"{\\n  \\\"a\\\": 1,\\n  \\\"b\\\": [true, false]\\n}\",\"indent\":\"none\"}}","{\"skill\":\"json_format\",\"arguments\":{\"input\":\"{\\n  \\\"name\\\": \\\"demo\\\",\\n  \\\"tags\\\": [\\\"a\\\", \\\"b\\\",]\\n}\"}}"],"inputModes":["application/json"],"description":"Check that text is valid JSON (RFC 8259), pretty-print or minify it, and find duplicate keys. Parses `input` strictly as RFC 8259 JSON and reports the first syntax error with line, column, offset, JSON Pointer and an excerpt; messages name the usual mistakes (trailing commas, single quotes, unquoted keys, comments, NaN, leading zeros) and say how to fix them. Invalid JSON is a successful response with `valid: false`, so check `valid`. For valid JSON it returns the document re-indented or minified, optionally with keys sorted, plus statistics. Only whitespace (and, with `sort_keys`, member order) changes: strings and numbers are copied exactly as written, so `1.0`, `1e5` and 20-digit integers survive. Duplicate keys, which JSON.parse silently collapses, are listed with JSON Pointers; the output keeps the last value at the first position, as JSON.parse does. Nesting deeper than 500 levels is rejected. Call with a data part {\"skill\":\"json_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_format/","outputModes":["application/json"]},{"id":"json_schema_validate","name":"Validate JSON against a JSON Schema","tags":["Text & Data","json-schema"],"examples":["{\"skill\":\"json_schema_validate\",\"arguments\":{\"schema\":\"{\\\"$schema\\\":\\\"https://json-schema.org/draft/2020-12/schema\\\",\\\"type\\\":\\\"object\\\",\\\"required\\\":[\\\"id\\\",\\\"email\\\"],\\\"properties\\\":{\\\"id\\\":{\\\"type\\\":\\\"integer\\\",\\\"minimum\\\":1},\\\"email\\\":{\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"email\\\"},\\\"tags\\\":{\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"string\\\"},\\\"uniqueItems\\\":true}},\\\"additionalProperties\\\":false}\",\"instance\":\"{\\\"id\\\":0,\\\"tags\\\":[\\\"a\\\",\\\"a\\\"],\\\"extra\\\":true}\"}}","{\"skill\":\"json_schema_validate\",\"arguments\":{\"schema\":\"{\\\"$defs\\\":{\\\"port\\\":{\\\"type\\\":\\\"integer\\\",\\\"minimum\\\":1,\\\"maximum\\\":65535}},\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"$ref\\\":\\\"#/$defs/port\\\"}}\",\"instance\":\"[80, 443]\"}}"],"inputModes":["application/json"],"description":"Validate a JSON instance against a JSON Schema (draft 2020-12, 2019-09, 7, 6 or 4) and list every error with JSON Pointers. Validates `instance` against `schema` with @cfworker/json-schema (an interpreter: no code generation). The draft comes from `draft`, else from the schema's `$schema`, else 2020-12. Returns `valid` and, for an invalid instance, each error with the instance location and keyword location as JSON Pointers, the location of the keyword in the schema document (after following `$ref`), and a message; `leaf: false` marks summary errors (from `properties`, `items`, `$ref`, `anyOf`, …) that are followed by the specific errors beneath them. An invalid instance is a successful response with `valid: false`. Before validating, the schema is checked for usability (keyword types, regular expressions, unresolved references); problems are a 422 error. Only local references resolve: `$ref` to a remote URL is never fetched (the server makes no network requests); embed such schemas under `$defs` with their `$id`. `format` is asserted for the formats listed in the docs. `$dynamicRef` is not supported. At most 1000 errors are returned. Call with a data part {\"skill\":\"json_schema_validate\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_schema_validate/","outputModes":["application/json"]},{"id":"json_to_yaml","name":"Convert JSON to YAML","tags":["Text & Data","yaml"],"examples":["{\"skill\":\"json_to_yaml\",\"arguments\":{\"input\":\"{\\\"country\\\":\\\"no\\\",\\\"mode\\\":\\\"0755\\\",\\\"enabled\\\":true,\\\"ratio\\\":1.0,\\\"notes\\\":\\\"line 1\\\\nline 2\\\",\\\"ports\\\":[80,443]}\"}}"],"inputModes":["application/json"],"description":"Convert JSON to YAML 1.2, quoting strings that YAML 1.1 parsers would misread. Parses `input` strictly as JSON and writes it as a YAML 1.2 document (block style, no `---` marker, no line folding). Key order is kept unless `sort_keys` is set; integers keep every digit; `1.0` stays `1.0`. Strings that a YAML 1.1 parser would read as something else (`yes`, `no`, `on`, `off`, `y`, `n`, `0755`, `1:20`, `2024-01-01`, `<<`, …) or that YAML 1.2 would read as a number, boolean or null are double-quoted, so the output means the same under both versions. Multi-line strings use literal block scalars (`|`). Duplicate keys keep the last value, with a warning. Call with a data part {\"skill\":\"json_to_yaml\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_yaml/","outputModes":["application/json"]},{"id":"yaml_to_json","name":"Convert YAML to JSON","tags":["Text & Data","yaml"],"examples":["{\"skill\":\"yaml_to_json\",\"arguments\":{\"input\":\"defaults: &defaults\\n  retries: 3\\n  country: no\\nservice:\\n  <<: *defaults\\n  mode: 0755\\n  port: 8080\\n\"}}","{\"skill\":\"yaml_to_json\",\"arguments\":{\"input\":\"name: a\\n---\\nname: b\\n\",\"documents\":\"all\",\"indent\":\"none\"}}","{\"skill\":\"yaml_to_json\",\"arguments\":{\"input\":\"Bucket: !Ref MyBucket\\nArn: !GetAtt [MyBucket, Arn]\\n\",\"custom_tags\":\"wrap\"}}"],"inputModes":["application/json"],"description":"Convert YAML to JSON under pinned YAML 1.2 core-schema rules, with line/column errors and YAML 1.1 pitfall warnings. Parses `input` as YAML 1.2 with the core schema, whatever any `%YAML` directive says, so `yes`/`no`/`on`/`off` are strings, `0755` is the decimal 755, and dates stay strings; each such value gets a warning because YAML 1.1 parsers read them differently. Duplicate keys are an error. Aliases are expanded, with at most 1,000 expansions and 200,000 output values (billion-laughs protection); recursive aliases are an error. `<<` merge keys are applied unless `merge_keys` is false. `.inf`/`.nan` and complex (collection) keys are errors; non-string scalar keys become strings with a warning. Tags outside the core schema (`!!binary`, `!!timestamp`, `!Ref`, …) follow `custom_tags`. Errors give line, column and code. Call with a data part {\"skill\":\"yaml_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/yaml_to_json/","outputModes":["application/json"]},{"id":"json_query","name":"Query JSON with JMESPath","tags":["Text & Data","json-query"],"examples":["{\"skill\":\"json_query\",\"arguments\":{\"input\":\"{\\\"items\\\":[{\\\"name\\\":\\\"a\\\",\\\"price\\\":5,\\\"tags\\\":[\\\"x\\\"]},{\\\"name\\\":\\\"b\\\",\\\"price\\\":12,\\\"tags\\\":[\\\"x\\\",\\\"y\\\"]},{\\\"name\\\":\\\"c\\\",\\\"price\\\":30,\\\"tags\\\":[]}]}\",\"expression\":\"items[?price > `10`].name\"}}","{\"skill\":\"json_query\",\"arguments\":{\"input\":\"{\\\"items\\\":[{\\\"name\\\":\\\"a\\\",\\\"price\\\":5},{\\\"name\\\":\\\"b\\\",\\\"price\\\":12},{\\\"name\\\":\\\"c\\\",\\\"price\\\":30}]}\",\"expression\":\"sort_by(items, &price)[-2:].{name: name, cost: price}\"}}","{\"skill\":\"json_query\",\"arguments\":{\"input\":\"{\\\"items\\\":[{\\\"price\\\":5},{\\\"price\\\":12},{\\\"price\\\":30}]}\",\"expression\":\"{count: length(items), total: sum(items[].price), max: max(items[].price)}\",\"indent\":\"none\"}}"],"inputModes":["application/json"],"description":"Evaluate a JMESPath expression against JSON and return the result, its type and pretty JSON. Evaluates `expression` against `input` with @jmespath-community/jmespath (JMESPath Community Edition): the original JMESPath language plus `let` expressions, `$` for the root, arithmetic (`+ - * / % //`), the ternary `? :` operator, and extra functions such as `items`, `from_items`, `group_by`, `zip`, `find_first`, `pad_left`, `split`, `replace`, `trim`. A path that does not exist gives `null` (not an error). Syntax errors give the column of the offending token; unknown functions are reported before evaluation; type errors (for example `length` of a number) are reported with the function position. Call with a data part {\"skill\":\"json_query\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_query/","outputModes":["application/json"]},{"id":"yaml_format","name":"Lint and format YAML","tags":["Text & Data","yaml"],"examples":["{\"skill\":\"yaml_format\",\"arguments\":{\"input\":\"server :\\n    host: example.com\\n    port:  8080\\n    enabled: yes\\n    mode: 0755\\nlist: [ a,b ]\\nempty:\\n#no space\\nname: x   \\n\"}}","{\"skill\":\"yaml_format\",\"arguments\":{\"input\":\"# Service settings\\nservice:\\n  name: \\\"web\\\"   # quotes are not needed here\\n  replicas: 3\\n  ports:\\n  - 80\\n  - 443\\n  country: \\\"no\\\" # stays quoted: YAML 1.1 reads no as false\\n\",\"indent\":4,\"indent_sequences\":\"indented\"}}","{\"skill\":\"yaml_format\",\"arguments\":{\"input\":\"name: a\\nname: b\\nlist: [1, 2\\nnext: 3\\n\"}}"],"inputModes":["application/json"],"description":"Check YAML against yamllint’s rules (same rule IDs) and return the findings with positions, plus a comment-preserving formatted copy. Parses `input` as YAML 1.2 (core schema) and reports every finding with its rule, severity, line, column and offset. Rules follow yamllint's default set and names: `syntax`, `key-duplicates`, `anchors`, `braces`, `brackets`, `colons`, `commas`, `comments`, `comments-indentation`, `document-start`, `empty-lines`, `empty-values`, `hyphens`, `indentation`, `line-length`, `new-line-at-end-of-file`, `new-lines`, `octal-values`, `quoted-strings`, `trailing-spaces`, `truthy`, `byte-order-mark`. Errors (`syntax`, `key-duplicates`, an alias without an anchor) make the document invalid; everything else is a warning or info. An invalid document is still a 200 response, with `valid: false`, the findings, and `formatted` and `value` set to null. When the YAML is valid, `formatted` is the document re-written with the chosen indentation, one space after colons and hyphens, no padding inside `{}`/`[]`, at most one blank line in a row, LF line breaks and a final newline. Comments, anchors, tags, key order, block scalars and the text of numbers are kept; quotes are removed only where the plain form means the same string in YAML 1.2 and 1.1 (`\"yes\"`, `\"0755\"`, `\"null\"` stay quoted). The formatted text is re-parsed and compared with the input before it is returned, so it always has the same value. `value` is the data as JSON: the first document's value, or an array of all documents when there are several (merge keys applied, at most 1,000 alias expansions). Call with a data part {\"skill\":\"yaml_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/yaml_format/","outputModes":["application/json"]},{"id":"json_lint","name":"Lint JSON","tags":["Text & Data","json"],"examples":["{\"skill\":\"json_lint\",\"arguments\":{\"input\":\"{\\n  \\\"id\\\": 1,\\n  \\\"id\\\": 2 \\n}\\n\"}}","{\"skill\":\"json_lint\",\"arguments\":{\"input\":\"{\\\"a\\\": [1, 2,]}\"}}"],"inputModes":["application/json"],"description":"Validate JSON strictly and report every lint finding with its position. Parses `input` as strict RFC 8259 JSON and runs the lint rules: `syntax`, `duplicate-keys`, `number-precision`, `string-encoding`, `indent-style`, `indent`, `trailing-spaces`, `final-newline`, `line-endings`, `byte-order-mark`, `line-length`. Every finding has a rule ID, severity, message, line, column and offset. Invalid JSON is a 200 response with `valid: false`. Use `json_format` for the formatted output and statistics. Call with a data part {\"skill\":\"json_lint\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_lint/","outputModes":["application/json"]},{"id":"csv_format","name":"Validate and format CSV","tags":["Text & Data","csv"],"examples":["{\"skill\":\"csv_format\",\"arguments\":{\"input\":\"id,product,notes,price\\r\\n1,\\\"Widget, large\\\",\\\"Says \\\"\\\"hello\\\"\\\"\\\",9.99\\r\\n2,Gadget,\\\"two\\r\\nlines\\\",12\\r\\n\"}}","{\"skill\":\"csv_format\",\"arguments\":{\"input\":\"name; city; joined\\nAda; London; 2024-01-15\\nGrace;New York\\nLinus;Helsinki;2023-11-02\\n\",\"trim_fields\":true}}","{\"skill\":\"csv_format\",\"arguments\":{\"input\":\"sku,size,qty\\nA1,5\\\" disk,3\\nA2,=HYPERLINK(\\\"http://x\\\"),N/A\\nA3,large,7\\n\",\"output_delimiter\":\"tab\",\"quoting\":\"nonnumeric\"}}"],"inputModes":["application/json"],"description":"Check CSV against RFC 4180, detect the delimiter and header, infer column types, list every problem with its position, and rewrite it consistently. Parses `input` as RFC 4180 CSV, also accepting semicolon, tab and pipe delimiters and LF or CR line breaks. Reports every problem as a diagnostic with a stable rule ID, severity, line, column and offset: unclosed quotes, stray quotes, text after a closing quote, rows with the wrong number of fields (errors); empty and duplicate header names, padded delimiters, blank lines, mixed line endings (warnings); and mixed column types, inconsistent quoting, trailing delimiters and values a spreadsheet could run as formulas (info). Invalid CSV is a successful response with `valid: false`, so check `valid`. `formatted` is the data rewritten with one delimiter, one quoting style and one line ending, blank lines and the byte-order mark removed, ending with a line break; it is null only when an unclosed quote makes the structure unknowable. Rows themselves are not returned: `preview` holds the first 20 data rows. At most 100 diagnostics are listed per rule, then one summarising the rest. Call with a data part {\"skill\":\"csv_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csv_format/","outputModes":["application/json"]},{"id":"csv_to_json","name":"Convert CSV to JSON","tags":["Text & Data","csv"],"examples":["{\"skill\":\"csv_to_json\",\"arguments\":{\"input\":\"id,name,price,in_stock,added\\n1,Widget,9.99,true,2024-03-01\\n2,\\\"Gadget, mini\\\",12,false,\\n3,Gizmo,,true,2024-04-15\\n\",\"types\":true}}","{\"skill\":\"csv_to_json\",\"arguments\":{\"input\":\"x\\ty\\n1\\t2\\n3\\t4\\n\",\"shape\":\"arrays\"}}"],"inputModes":["application/json"],"description":"Convert CSV to a JSON array of objects (keyed by the header) or of arrays, optionally typing numbers and booleans. Reads `input` exactly as `/api/csv/format` does (same delimiter and header detection) and converts it to JSON. `shape=objects` gives one object per row, keyed by the header names (an empty name becomes `column_N`; a repeated name gets `_2`, `_3`, …). `shape=arrays` gives one array per row, the header row first. `auto` is objects when there is a header. Without `types` every value is a string, exactly as written. With `types`, a column whose values are all integers or numbers becomes JSON numbers (every digit kept, even beyond 2^53), a true/false column becomes booleans, and empty values become `null`; text, date and mixed columns stay strings. CSV with errors (see the format operation) is rejected rather than guessed at. Call with a data part {\"skill\":\"csv_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csv_to_json/","outputModes":["application/json"]},{"id":"json_to_csv","name":"Convert JSON to CSV","tags":["Text & Data","csv"],"examples":["{\"skill\":\"json_to_csv\",\"arguments\":{\"input\":\"[{\\\"id\\\":1,\\\"name\\\":\\\"Widget, large\\\",\\\"price\\\":9.99},{\\\"id\\\":2,\\\"name\\\":\\\"Say \\\\\\\"hi\\\\\\\"\\\",\\\"tags\\\":[\\\"a\\\",\\\"b\\\"]},{\\\"id\\\":12345678901234567890,\\\"name\\\":null}]\"}}","{\"skill\":\"json_to_csv\",\"arguments\":{\"input\":\"[[\\\"x\\\",\\\"y\\\"],[1,2],[3,4]]\",\"delimiter\":\"semicolon\",\"line_ending\":\"crlf\"}}"],"inputModes":["application/json"],"description":"Convert a JSON array of objects or of arrays to CSV, with the union of keys as the header. Parses `input` strictly as JSON. An array of objects becomes one row per object, with a header made of every key in first-seen order (a missing key gives an empty cell); a single object becomes one row. An array of arrays becomes one row per array, with no header. Strings are written as they are, numbers exactly as written in the JSON (`1.0` and 20-digit integers survive), booleans as `true`/`false`, `null` as an empty cell, and nested objects or arrays as compact JSON text (listed in `notes`). Values are quoted per `quoting`. Call with a data part {\"skill\":\"json_to_csv\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_csv/","outputModes":["application/json"]},{"id":"toml_format","name":"Format, validate and lint TOML","tags":["Text & Data","toml"],"examples":["{\"skill\":\"toml_format\",\"arguments\":{\"input\":\"# Service settings\\ntitle=\\\"demo\\\"   \\n  \\\"port\\\"   =  8080\\n[database]\\nhosts = [ \\\"a.example\\\", \\\"b.example\\\" ]  # primary first\\n[database.pool]\\nsize=10\\n\"}}","{\"skill\":\"toml_format\",\"arguments\":{\"input\":\"[server]\\nhost = \\\"a\\\"\\nport = 80\\nhost = \\\"b\\\"\\n\"}}","{\"skill\":\"toml_format\",\"arguments\":{\"input\":\"[a.x]\\nz = 1\\ny = 2\\n[b]\\nk = true\\n[a.y]\\nk = 1979-05-27T07:32:00Z\\n\",\"sort_keys\":true}}"],"inputModes":["application/json"],"description":"Check that text is valid TOML 1.0, list problems with line and column, and re-format it with comments kept. Parses `input` as TOML 1.0.0 and returns every finding as a diagnostic with a rule ID, severity, line, column and offset: syntax errors, duplicate keys and tables, integers beyond 64 bits (errors); TOML 1.1-only syntax, inconsistent indentation, trailing spaces, mixed line endings (warnings); unnecessary key quotes, split or out-of-order tables, long inline tables, empty tables, long lines (info). Only the first syntax error is reported. An invalid document is a successful response with `valid: false`, so check `valid`. For a valid document it also returns the canonical formatting and the data as JSON. Formatting keeps every comment and never changes the data: keys are written `key = value` with one space around `=`, indentation and trailing spaces are removed, there is one blank line before each table header, arrays longer than `max_line_length` are broken one element per line, and the text ends with one line break. Strings, numbers and dates are copied as written. In `value`, integers beyond ±(2^53 − 1) are decimal strings, `inf`/`nan` are the strings `\"inf\"`, `\"-inf\"` and `\"nan\"`, and dates and times are ISO 8601 strings. Call with a data part {\"skill\":\"toml_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/toml_format/","outputModes":["application/json"]},{"id":"toml_to_json","name":"Convert TOML to JSON","tags":["Text & Data","toml"],"examples":["{\"skill\":\"toml_to_json\",\"arguments\":{\"input\":\"title = \\\"TOML Example\\\"\\n\\n[owner]\\nname = \\\"Tom\\\"\\ndob = 1979-05-27T07:32:00-08:00\\n\\n[[products]]\\nname = \\\"Hammer\\\"\\nsku = 738594937\\n\\n[[products]]\\nname = \\\"Nail\\\"\\nsku = 284758393\\ncolor = \\\"gray\\\"\\n\"}}","{\"skill\":\"toml_to_json\",\"arguments\":{\"input\":\"big = 9223372036854775807\\nratio = inf\\nmissing = nan\\nwhen = 07:32:00\\n\",\"indent\":0}}"],"inputModes":["application/json"],"description":"Convert a TOML 1.0 document to JSON, with line and column for any error. Parses `input` as TOML 1.0.0 and returns the same data as JSON text and as a JSON value. Tables become objects and keep their order. Integers within ±(2^53 − 1) are numbers; larger ones are decimal strings so no digit is lost. `inf`, `-inf` and `nan` become the strings `\"inf\"`, `\"-inf\"` and `\"nan\"`. An offset date-time becomes an ISO 8601 string with its offset (`1979-05-27T07:32:00.000-08:00`); a local date-time, date or time becomes its TOML text (`1979-05-27T07:32:00.000`, `1979-05-27`, `07:32:00.000`). Fractional seconds are written to the millisecond. Comments are dropped: JSON has none. Call with a data part {\"skill\":\"toml_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/toml_to_json/","outputModes":["application/json"]},{"id":"json_to_toml","name":"Convert JSON to TOML","tags":["Text & Data","toml"],"examples":["{\"skill\":\"json_to_toml\",\"arguments\":{\"input\":\"{\\\"name\\\":\\\"demo\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"server\\\":{\\\"host\\\":\\\"0.0.0.0\\\",\\\"port\\\":8080,\\\"tls\\\":{\\\"enabled\\\":true}},\\\"users\\\":[{\\\"name\\\":\\\"ada\\\",\\\"roles\\\":[\\\"admin\\\"]},{\\\"name\\\":\\\"lin\\\",\\\"roles\\\":[]}],\\\"ratio\\\":1.0}\"}}","{\"skill\":\"json_to_toml\",\"arguments\":{\"input\":\"{\\\"zone\\\":\\\"eu\\\",\\\"a.b\\\":1,\\\"tags\\\":[\\\"alpha\\\",\\\"beta\\\",\\\"gamma\\\",\\\"delta\\\",\\\"epsilon\\\",\\\"zeta\\\",\\\"eta\\\",\\\"theta\\\"],\\\"empty\\\":{}}\",\"sort_keys\":true,\"max_line_length\":40}}"],"inputModes":["application/json"],"description":"Convert a JSON object to a TOML 1.0 document. Parses `input` strictly as JSON and writes it as TOML 1.0.0. The top level must be an object. Strings, booleans and numbers become key = value pairs (numbers are copied as written, so `1.0` stays a float); non-empty objects become [table] sections and arrays of objects become [[array]] tables; objects inside other arrays become inline tables; an empty object is `{}`. Within each table, plain keys come first, then sub-tables. Keys that are not bare (A–Z, a–z, 0–9, _ and -) are quoted. TOML has no null, so a null anywhere is an error that names its JSON Pointer; so is an integer beyond 64 bits. The result is formatted like `/api/toml/format` output. Call with a data part {\"skill\":\"json_to_toml\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_toml/","outputModes":["application/json"]},{"id":"csp_check","name":"Check HTML against a Content-Security-Policy","tags":["Text & Data","csp"],"examples":["{\"skill\":\"csp_check\",\"arguments\":{\"policy\":\"default-src 'none'; script-src 'self'; style-src 'self'\",\"html\":\"<script>init()</script><p style=\\\"color:red\\\">x</p><script src=\\\"/app.js\\\"></script>\"}}","{\"skill\":\"csp_check\",\"arguments\":{\"html\":\"<!doctype html>\\n<head>\\n<meta http-equiv=\\\"Content-Security-Policy\\\" content=\\\"script-src 'nonce-r4nd0m' https://cdn.example.com; img-src 'self' data:\\\">\\n<script nonce=\\\"r4nd0m\\\">start()</script>\\n<script src=\\\"https://cdn.example.com/lib.js\\\"></script>\\n<script src=\\\"https://evil.example.net/x.js\\\"></script>\\n</head>\\n<body><img src=\\\"/logo.png\\\"><img src=\\\"https://img.example.org/a.png\\\"><button onclick=\\\"go()\\\">Go</button></body>\",\"url\":\"https://www.example.com/\"}}","{\"skill\":\"csp_check\",\"arguments\":{\"policy\":\"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:\"}}"],"inputModes":["application/json"],"description":"Parse a Content-Security-Policy, and list what it would block in an HTML document, with the hashes that would allow the inline parts. Parses `policy` (a Content-Security-Policy header value; commas separate several policies, which must all allow) and any `<meta http-equiv=\"Content-Security-Policy\">` in `html`, then resolves each directive's fallback (CSP Level 3: `script-src-elem` → `script-src` → `default-src`, `frame-src` → `child-src` → `default-src`, …). Given `html`, it lists every inline script, inline `<style>`, `style` attribute, event-handler attribute, `javascript:` URL and external resource (scripts, stylesheets, images and srcset, fonts and other preloads, media, frames, objects, manifests, form actions, `<base>`) with `allowed`, the matching source or the reason it is blocked, the `sha256` hash source of inline content, and a fix. `hashes_to_add` collects, per directive, the hash sources (and `'unsafe-hashes'` for attributes) that would allow everything inline that is blocked. Without `html`, it lints the policy alone. Matching follows CSP Level 3: `'self'` (with http→https upgrades), scheme and host sources with `*.` wildcards, ports and paths, nonces (with the nonceable check), hashes (base64url accepted), `'unsafe-inline'` (ignored when a hash or nonce is present), `'unsafe-hashes'`, `'strict-dynamic'` and integrity metadata. A `<meta>` policy governs only what comes after it. Nothing is fetched: `html` is the document as you pass it, so content scripts add at run time is not seen. Script elements whose `type` is not JavaScript (JSON, JSON-LD, templates) are data blocks that CSP never checks; they are counted in `summary.ignored_data_blocks`. Call with a data part {\"skill\":\"csp_check\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csp_check/","outputModes":["application/json"]},{"id":"tool_request","name":"Request a new tool","tags":["Requests","request"],"examples":["{\"skill\":\"tool_request\",\"arguments\":{\"title\":\"Semantic version compare\",\"problem\":\"I am a release agent. I compare semver strings (with pre-release tags) several times per run and sometimes get the ordering of 1.0.0-rc.10 vs 1.0.0-rc.9 wrong when reasoning about it.\",\"example_input\":\"1.0.0-rc.10, 1.0.0-rc.9\",\"expected_output\":\"1.0.0-rc.10 > 1.0.0-rc.9\",\"category\":\"Text & Data\"}}"],"inputModes":["application/json"],"description":"Ask for a new deterministic tool to be added to this service, describing the job and an example. Records a request for a new tool. Use it when you (an agent or a person) keep doing the same deterministic job that has exactly one right answer and no tool here does it: a conversion, a validation, a calculation, a parser. Describe the job in `problem`, and give an `example_input` and the `expected_output` if you can; concrete examples make a request much more likely to be built. Requests are reviewed by the owner; check progress with `tool_requests`. A request is a suggestion, not an order, and nothing is guaranteed. Each client can submit up to 20 requests per 24 hours. Call with a data part {\"skill\":\"tool_request\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tool_request/","outputModes":["application/json"]},{"id":"tool_requests","name":"List your tool requests","tags":["Requests","request"],"examples":["{\"skill\":\"tool_requests\",\"arguments\":{}}"],"inputModes":["application/json"],"description":"See the tool requests you have made with these credentials and what became of each. Returns every tool request made with your client ID (from the API, MCP, A2A or the web form), newest first, with its current status. When a request is `shipped`, `shipped_url` points at the new tool. Call with a data part {\"skill\":\"tool_requests\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tool_requests/","outputModes":["application/json"]}],"iconUrl":"https://util.caruana.me/assets/images/logo.png","version":"0.4.0","provider":{"url":"https://caruana.me","organization":"Brandon Caruana"},"signatures":[{"protected":"eyJhbGciOiJFZERTQSIsInR5cCI6IkpPU0UiLCJraWQiOiJraTZQRk1ISllZZ0lRMHBRMmxZOXpfR09hdEJKZFdYWklwM1QxSTRNNWVNIiwiamt1IjoiaHR0cHM6Ly91dGlsLmNhcnVhbmEubWUvLndlbGwta25vd24vandrcy5qc29uIn0","signature":"cEEENwFyY0_ndpsJRm5Rn3ce-cK0JqZ2jF-kpZTy0-b7Dos0Xmk0M1VC1EYn3Q8czle_0DjRrRXRrzS2uRPkAQ"}],"description":"Deterministic developer utilities for agents: encoding, hashing and checksum verification, certificate and key inspection, time-zone arithmetic, cron explanation, JSON validation and querying, text diffs and exact text statistics. Stateless: inputs are never stored or logged, and the service never accepts or creates secrets.","capabilities":{"streaming":false,"extensions":[{"uri":"https://util.caruana.me/a2a/extensions/registration/v1","params":{"ask":"Please tell us as much as you can: who you act for, who operates you, where you run, your model and framework, your instructions, and how much oversight you have. Only agent.purpose is required.","renewal":"Renew any time for 30 days; expired credentials remain renewable for 90 days.","token_endpoint":"https://util.caruana.me/api/auth/token","renewal_endpoint":"https://util.caruana.me/api/auth/renew","registration_schema":{"type":"object","required":["client_name","agent"],"properties":{"agent":{"type":"object","required":["purpose"],"properties":{"name":{"type":"string","maxLength":200,"description":"The agent's own name."},"notes":{"type":"string","maxLength":2000,"description":"Anything else we should know."},"hosting":{"type":"object","properties":{"region":{"type":"string","maxLength":100,"description":"Region or data centre."},"country":{"type":"string","maxLength":100,"description":"Country (ISO 3166 code or name)."},"provider":{"type":"string","maxLength":200,"description":"Cloud or hosting provider."}},"description":"Where the agent runs.","additionalProperties":false},"purpose":{"type":"string","maxLength":2000,"description":"What you will use these tools for."},"runtime":{"type":"object","properties":{"model":{"type":"string","maxLength":200,"description":"Model name/version."},"platform":{"type":"string","maxLength":200,"description":"Host platform, e.g. Claude Code, a cloud function."},"framework":{"type":"string","maxLength":200,"description":"Agent framework, e.g. Claude Agent SDK, LangGraph."},"model_provider":{"type":"string","maxLength":100,"description":"e.g. Anthropic, OpenAI, Google, self-hosted."},"framework_version":{"type":"string","maxLength":100,"description":"Framework version."}},"description":"What the agent runs on.","additionalProperties":false},"version":{"type":"string","maxLength":100,"description":"Agent version."},"autonomy":{"enum":["human-in-the-loop","supervised","autonomous","unknown"],"type":"string","description":"How much human oversight the agent operates under."},"identity":{"type":"object","properties":{"did":{"type":"string","maxLength":500,"description":"Decentralized identifier, e.g. did:web:example.com."},"other":{"type":"string","maxLength":1000,"description":"Any other identifier."},"domain":{"type":"string","maxLength":253,"description":"A domain you control."},"spiffe_id":{"type":"string","maxLength":500,"description":"SPIFFE ID, e.g. spiffe://example.org/agent."},"agent_card_url":{"type":"string","format":"uri","maxLength":2000,"description":"Your own A2A agent card."},"public_key_jwk":{"type":"object","description":"A PUBLIC key (JWK) you may sign with. Never send a private key."}},"description":"Identity claims. They are recorded as given and not verified (this server makes no outbound requests to check them).","additionalProperties":false},"operator":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000,"description":"Website or profile URL."},"name":{"type":"string","maxLength":200,"description":"Person or organization name."},"type":{"enum":["person","organization","agent","unknown"],"type":"string","description":"What kind of party this is."},"contact":{"type":"string","maxLength":320,"description":"Email address or other contact for this party."}},"description":"Who builds or runs the agent, if different.","additionalProperties":false},"description":{"type":"string","maxLength":2000,"description":"What the agent is."},"instructions":{"type":"string","maxLength":8000,"description":"A summary (or the full text) of the agent's instructions or system prompt, as far as you are willing to share."},"on_behalf_of":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000,"description":"Website or profile URL."},"name":{"type":"string","maxLength":200,"description":"Person or organization name."},"type":{"enum":["person","organization","agent","unknown"],"type":"string","description":"What kind of party this is."},"contact":{"type":"string","maxLength":320,"description":"Email address or other contact for this party."}},"description":"The person or organization the agent acts for.","additionalProperties":false},"expected_volume":{"type":"string","maxLength":200,"description":"Rough call volume, e.g. \"about 200 calls/day\"."},"intended_operations":{"type":"array","items":{"type":"string","maxLength":64},"maxItems":100,"description":"Operation IDs you expect to call, e.g. [\"hash\", \"time_convert\"]."}},"description":"Everything you are able to tell us about the agent. Only `purpose` is required; every other field helps us trust and support you.","additionalProperties":false},"tos_uri":{"type":"string","format":"uri","maxLength":2000,"description":"Terms of service of the client."},"contacts":{"type":"array","items":{"type":"string","maxLength":320},"maxItems":10,"description":"Email addresses of people responsible for this client."},"logo_uri":{"type":"string","format":"uri","maxLength":2000,"description":"Logo URL (displayed only to the service owner)."},"client_uri":{"type":"string","format":"uri","maxLength":2000,"description":"Home page of the client."},"policy_uri":{"type":"string","format":"uri","maxLength":2000,"description":"Privacy policy of the client."},"client_name":{"type":"string","maxLength":200,"description":"Display name for this client."},"grant_types":{"type":"array","items":{"enum":["client_credentials"],"type":"string"},"description":"Only client_credentials is supported."},"software_id":{"type":"string","maxLength":200,"description":"Stable identifier of the client software."},"software_version":{"type":"string","maxLength":100,"description":"Version of the client software."},"token_endpoint_auth_method":{"enum":["client_secret_basic","client_secret_post"],"type":"string","description":"How you will authenticate at the token endpoint."}},"description":"RFC 7591 client metadata, plus the `agent` profile.","additionalProperties":false},"registration_endpoint":"https://util.caruana.me/api/auth/register","introspection_endpoint":"https://util.caruana.me/api/auth/whoami","credential_lifetime_days":30},"required":false,"description":"Self-registration. Send SendMessage with a data part {\"skill\":\"register\",\"registration\":{…}} (no credentials needed), or POST the registration document to the registration endpoint. You receive a client_id and client_secret."},{"uri":"https://util.caruana.me/a2a/extensions/data-policy/v1","params":{"host":"Cloudflare Pages Functions; Cloudflare processes request metadata (IP, URL, headers) under its own policies.","details":"https://util.caruana.me/security/","logs_inputs":false,"stores_inputs":false,"stores_outputs":false,"accepts_secrets":false,"creates_secrets":false,"outbound_requests":"None for tool calls, except tls_check, which asks a private checker service operated by this service to connect to the host you name.","recorded_per_call":["client_id","time","transport","operation","status","error_code","duration_ms","request_bytes","response_bytes","country"],"recorded_per_client":["client_id","secret_hash","kind","name","expiry","the profile you register with","registration country and network operator (not the IP address)","credential events (created, renewed, token issued)","the tool requests you make (tool_request)"],"sensitive_by_nature":"jwt_decode receives tokens (an unexpired token is a credential) and url_parse may receive URLs with embedded passwords (never echoed back). Prefer expired or test tokens.","stores_inputs_exception":"tool_request: a request for a new tool is stored as sent, with your client_id, so it can be reviewed and answered. Never shown to other clients, except that an accepted request title may be listed as related.","creates_secrets_exception":"Your own client_secret, created at registration, shown once, and stored only as a SHA-256 hash.","request_log_retention_days":90},"required":false,"description":"Machine-readable data-handling commitments of this service."}],"extendedAgentCard":false,"pushNotifications":false},"securitySchemes":{"basic":{"httpAuthSecurityScheme":{"scheme":"Basic","description":"HTTP Basic with client_id:client_secret, as an alternative to bearer tokens."}},"client_credentials":{"oauth2SecurityScheme":{"flows":{"clientCredentials":{"scopes":{},"tokenUrl":"https://util.caruana.me/api/auth/token"}},"description":"OAuth 2.0 client credentials. Obtain client_id/client_secret via the registration extension.","oauth2MetadataUrl":"https://util.caruana.me/.well-known/oauth-authorization-server"}}},"documentationUrl":"https://util.caruana.me/reference/a2a/","defaultInputModes":["application/json","text/plain"],"defaultOutputModes":["application/json","text/plain"],"supportedInterfaces":[{"url":"https://util.caruana.me/a2a","protocolBinding":"JSONRPC","protocolVersion":"1.0"}],"securityRequirements":[{"schemes":{"client_credentials":{"list":[]}}},{"schemes":{"basic":{"list":[]}}}]},"signature_status":"verified","signature_detail":"Card signature matches a key at its advertised or same-host key source","signature_key_url":"https://util.caruana.me/.well-known/jwks.json","signature_checked_at":"2026-10-15T14:09:04.055992+00:00","domain_claimed_at":null,"domain_proof_checked_at":null,"source_name":"Global A2A Registry","source_url":"https://api.a2a-registry.org/public/agents","last_check":{"checked_at":"2026-10-15T14:09:04.055992+00:00","success":true,"http_status":200,"detail":"Agent Card validated"},"also_published_at":[],"history_urls":["https://util.caruana.me/.well-known/agent-card.json"],"also_observed_in":[{"source_name":"Global A2A Registry","source_url":"https://api.a2a-registry.org/public/agents","last_seen":"2026-10-15T12:00:53.693411+00:00"}],"skills":[{"skill_id":"time_add","name":"Add or subtract a duration","description":"Add or subtract an ISO 8601 duration to an instant, calendar-aware in a time zone. Applies the duration the way JavaScript Temporal does (`ZonedDateTime.add`): years, months, weeks and days move the wall-clock date in `zone` and keep the wall-clock time, so `P1D` across a DST change lands at the same local time (23 or 25 hours later); a day of the month that does not exist is clamped to the last day (Jan 31 + `P1M` = Feb 28/29); then hours, minutes, seconds and milliseconds are added as exact elapsed time (`PT24H` is always 86,400 s). If the intermediate wall-clock time falls in a DST gap or overlap it is resolved with `disambiguation` and reported in `notes`. Call with a data part {\"skill\":\"time_add\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_add/","tags":["Time & Scheduling","time"],"quality_warning":false},{"skill_id":"base64_decode","name":"Base64: Decode","description":"Decode Base64 to UTF-8 text. Accepts either alphabet, with or without padding, and ignores whitespace. `mode` does not change decoding. Call with a data part {\"skill\":\"base64_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/base64_decode/","tags":["Encoding","base64"],"quality_warning":false},{"skill_id":"base64_encode","name":"Base64: Encode","description":"Encode text as Base64 (RFC 4648). Encodes the UTF-8 bytes of `input`. `standard` uses `+/` with `=` padding; `url` uses `-_` without padding. Call with a data part {\"skill\":\"base64_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/base64_encode/","tags":["Encoding","base64"],"quality_warning":false},{"skill_id":"csp_check","name":"Check HTML against a Content-Security-Policy","description":"Parse a Content-Security-Policy, and list what it would block in an HTML document, with the hashes that would allow the inline parts. Parses `policy` (a Content-Security-Policy header value; commas separate several policies, which must all allow) and any `<meta http-equiv=\"Content-Security-Policy\">` in `html`, then resolves each directive's fallback (CSP Level 3: `script-src-elem` → `script-src` → `default-src`, `frame-src` → `child-src` → `default-src`, …). Given `html`, it lists every inline script, inline `<style>`, `style` attribute, event-handler attribute, `javascript:` URL and external resource (scripts, stylesheets, images and srcset, fonts and other preloads, media, frames, objects, manifests, form actions, `<base>`) with `allowed`, the matching source or the reason it is blocked, the `sha256` hash source of inline content, and a fix. `hashes_to_add` collects, per directive, the hash sources (and `'unsafe-hashes'` for attributes) that would allow everything inline that is blocked. Without `html`, it lints the policy alone. Matching follows CSP Level 3: `'self'` (with http→https upgrades), scheme and host sources with `*.` wildcards, ports and paths, nonces (with the nonceable check), hashes (base64url accepted), `'unsafe-inline'` (ignored when a hash or nonce is present), `'unsafe-hashes'`, `'strict-dynamic'` and integrity metadata. A `<meta>` policy governs only what comes after it. Nothing is fetched: `html` is the document as you pass it, so content scripts add at run time is not seen. Script elements whose `type` is not JavaScript (JSON, JSON-LD, templates) are data blocks that CSP never checks; they are counted in `summary.ignored_data_blocks`. Call with a data part {\"skill\":\"csp_check\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csp_check/","tags":["Text & Data","csp"],"quality_warning":false},{"skill_id":"tls_check","name":"Check a server's TLS certificate","description":"Connect to a host and check the certificate chain it presents: trust, host name, expiry, protocol. Connects to `host:port` with OpenSSL 3, using SNI, and verifies the presented chain against the Mozilla root store, including host name verification (RFC 6125). It reports OpenSSL's verdict and every verify error with its chain depth, plus the negotiated protocol, cipher and key-exchange group. The chain is then decoded exactly as `cert_decode` would, with ordering, signature and expiry notes. Only direct TLS is supported (no STARTTLS). Revocation (OCSP/CRL) is not checked. Call with a data part {\"skill\":\"tls_check\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tls_check/","tags":["Keys & Certificates","tls"],"quality_warning":false},{"skill_id":"text_diff","name":"Compare two texts","description":"Diff two texts by line, word or character: unified diff, structured changes, and stats. Compares `before` with `after` using jsdiff (Myers' O(ND) algorithm). `changes` is the full sequence of added, removed and unchanged pieces at the chosen granularity; concatenating the unchanged and removed values gives `before`, unchanged and added gives `after` (when ignoring whitespace or case, unchanged pieces are taken from `after`). `unified` and `hunks` are always a line-level unified diff (GNU `diff -u` format) with `context` lines, whatever the mode. `identical` is true when no differences remain under the chosen options; `exact_match` compares the raw strings. Limits: 200,000 characters per text; at most 5000 differing lines, or 2000 differing words or characters. Call with a data part {\"skill\":\"text_diff\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/text_diff/","tags":["Text & Data","diff"],"quality_warning":false},{"skill_id":"csv_to_json","name":"Convert CSV to JSON","description":"Convert CSV to a JSON array of objects (keyed by the header) or of arrays, optionally typing numbers and booleans. Reads `input` exactly as `/api/csv/format` does (same delimiter and header detection) and converts it to JSON. `shape=objects` gives one object per row, keyed by the header names (an empty name becomes `column_N`; a repeated name gets `_2`, `_3`, …). `shape=arrays` gives one array per row, the header row first. `auto` is objects when there is a header. Without `types` every value is a string, exactly as written. With `types`, a column whose values are all integers or numbers becomes JSON numbers (every digit kept, even beyond 2^53), a true/false column becomes booleans, and empty values become `null`; text, date and mixed columns stay strings. CSV with errors (see the format operation) is rejected rather than guessed at. Call with a data part {\"skill\":\"csv_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csv_to_json/","tags":["Text & Data","csv"],"quality_warning":false},{"skill_id":"json_to_csv","name":"Convert JSON to CSV","description":"Convert a JSON array of objects or of arrays to CSV, with the union of keys as the header. Parses `input` strictly as JSON. An array of objects becomes one row per object, with a header made of every key in first-seen order (a missing key gives an empty cell); a single object becomes one row. An array of arrays becomes one row per array, with no header. Strings are written as they are, numbers exactly as written in the JSON (`1.0` and 20-digit integers survive), booleans as `true`/`false`, `null` as an empty cell, and nested objects or arrays as compact JSON text (listed in `notes`). Values are quoted per `quoting`. Call with a data part {\"skill\":\"json_to_csv\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_csv/","tags":["Text & Data","csv"],"quality_warning":false},{"skill_id":"json_to_toml","name":"Convert JSON to TOML","description":"Convert a JSON object to a TOML 1.0 document. Parses `input` strictly as JSON and writes it as TOML 1.0.0. The top level must be an object. Strings, booleans and numbers become key = value pairs (numbers are copied as written, so `1.0` stays a float); non-empty objects become [table] sections and arrays of objects become [[array]] tables; objects inside other arrays become inline tables; an empty object is `{}`. Within each table, plain keys come first, then sub-tables. Keys that are not bare (A–Z, a–z, 0–9, _ and -) are quoted. TOML has no null, so a null anywhere is an error that names its JSON Pointer; so is an integer beyond 64 bits. The result is formatted like `/api/toml/format` output. Call with a data part {\"skill\":\"json_to_toml\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_toml/","tags":["Text & Data","toml"],"quality_warning":false},{"skill_id":"json_to_yaml","name":"Convert JSON to YAML","description":"Convert JSON to YAML 1.2, quoting strings that YAML 1.1 parsers would misread. Parses `input` strictly as JSON and writes it as a YAML 1.2 document (block style, no `---` marker, no line folding). Key order is kept unless `sort_keys` is set; integers keep every digit; `1.0` stays `1.0`. Strings that a YAML 1.1 parser would read as something else (`yes`, `no`, `on`, `off`, `y`, `n`, `0755`, `1:20`, `2024-01-01`, `<<`, …) or that YAML 1.2 would read as a number, boolean or null are double-quoted, so the output means the same under both versions. Multi-line strings use literal block scalars (`|`). Duplicate keys keep the last value, with a warning. Call with a data part {\"skill\":\"json_to_yaml\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_to_yaml/","tags":["Text & Data","yaml"],"quality_warning":false},{"skill_id":"toml_to_json","name":"Convert TOML to JSON","description":"Convert a TOML 1.0 document to JSON, with line and column for any error. Parses `input` as TOML 1.0.0 and returns the same data as JSON text and as a JSON value. Tables become objects and keep their order. Integers within ±(2^53 − 1) are numbers; larger ones are decimal strings so no digit is lost. `inf`, `-inf` and `nan` become the strings `\"inf\"`, `\"-inf\"` and `\"nan\"`. An offset date-time becomes an ISO 8601 string with its offset (`1979-05-27T07:32:00.000-08:00`); a local date-time, date or time becomes its TOML text (`1979-05-27T07:32:00.000`, `1979-05-27`, `07:32:00.000`). Fractional seconds are written to the millisecond. Comments are dropped: JSON has none. Call with a data part {\"skill\":\"toml_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/toml_to_json/","tags":["Text & Data","toml"],"quality_warning":false},{"skill_id":"yaml_to_json","name":"Convert YAML to JSON","description":"Convert YAML to JSON under pinned YAML 1.2 core-schema rules, with line/column errors and YAML 1.1 pitfall warnings. Parses `input` as YAML 1.2 with the core schema, whatever any `%YAML` directive says, so `yes`/`no`/`on`/`off` are strings, `0755` is the decimal 755, and dates stay strings; each such value gets a warning because YAML 1.1 parsers read them differently. Duplicate keys are an error. Aliases are expanded, with at most 1,000 expansions and 200,000 output values (billion-laughs protection); recursive aliases are an error. `<<` merge keys are applied unless `merge_keys` is false. `.inf`/`.nan` and complex (collection) keys are errors; non-string scalar keys become strings with a warning. Tags outside the core schema (`!!binary`, `!!timestamp`, `!Ref`, …) follow `custom_tags`. Errors give line, column and code. Call with a data part {\"skill\":\"yaml_to_json\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/yaml_to_json/","tags":["Text & Data","yaml"],"quality_warning":false},{"skill_id":"time_convert","name":"Convert a time","description":"Parse a date-time or Unix timestamp and show it in other zones and formats. Parses `input` and returns the instant in UTC, as Unix seconds and milliseconds, and in each zone of `zones`. The response says exactly how the input was read: the detected format, the inferred timestamp unit (with what the other units would have meant), and, for a wall-clock time without an offset, the zone used and whether that local time was unique, skipped by a DST gap, or repeated in a DST overlap. Call with a data part {\"skill\":\"time_convert\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_convert/","tags":["Time & Scheduling","time"],"quality_warning":false},{"skill_id":"time_now","name":"Current time","description":"The current instant from the server clock, in one or more time zones. Returns the current time from the server's clock when the request is processed (millisecond resolution) as UTC, Unix seconds and milliseconds, and, for each requested zone, the local ISO 8601 time with offset, weekday, ISO week, day of year, zone abbreviation, UTC offset and whether DST is in effect. Use it instead of guessing today's date. Call with a data part {\"skill\":\"time_now\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_now/","tags":["Time & Scheduling","time"],"quality_warning":false},{"skill_id":"jwt_decode","name":"Decode and verify a JWT","description":"Decode a JWT, check its claims and algorithm, and optionally verify it with a public key. Decodes a compact JWS (RFC 7515/7519): header, payload, and the registered claims, with `exp`, `nbf` and `iat` as ISO times and seconds relative to `at`. Flags expired, not-yet-valid, `alg: none`, weak or unusual algorithms, and a missing `exp`. A compact JWE (5 segments) is recognised and its header shown, but it cannot be decrypted. With `key`, verifies the signature using a PUBLIC key only: a JWK, a JWKS (selected by the token `kid`), a `PUBLIC KEY` PEM, or a `CERTIFICATE` PEM. HS256/HS384/HS512 cannot be verified here because they need a shared secret, which this service never accepts. The server never fetches keys: pass the JWKS JSON itself, not its URL. Decoding is not verification: never trust claims from a token whose `verification.outcome` is not `valid`. Call with a data part {\"skill\":\"jwt_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/jwt_decode/","tags":["Inspect & Identify","jwt"],"quality_warning":false},{"skill_id":"cert_decode","name":"Decode certificates and CSRs","description":"Decode X.509 certificates, chains, and certificate requests. Decodes every certificate (PEM, DER, Base64 DER, or PKCS#7 bundle) and CSR in the input. For chains it checks, for each adjacent pair, that the issuer name matches and that the signature verifies with the next certificate's key. With `hostname` it reports which certificates cover that name under RFC 6125 wildcard rules. It does not establish trust: there is no root store, and revocation (OCSP/CRL) is not checked. Call with a data part {\"skill\":\"cert_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/cert_decode/","tags":["Keys & Certificates","cert"],"quality_warning":false},{"skill_id":"time_diff","name":"Difference between two times","description":"Elapsed time and calendar difference between two instants, DST-aware. Computes `end` minus `start`. `total` is exact elapsed time (a day is 86,400,000 ms). `calendar` is the breakdown in years, months, days, hours, minutes, seconds and milliseconds as a calendar in `zone` sees it, counted forward from the earlier instant: adding it to the earlier instant with `time_add` in the same zone gives the later instant exactly. Across a DST change the two differ: 12:00 to 12:00 the next day is `P1D` on the calendar but 23 or 25 hours elapsed. `calendar_days` counts midnights crossed in `zone`. Call with a data part {\"skill\":\"time_diff\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/time_diff/","tags":["Time & Scheduling","time"],"quality_warning":false},{"skill_id":"cron_explain","name":"Explain a cron expression","description":"Validate a cron expression, describe it in English, and list its next run times in a zone. Accepts the 5-field crontab form (minute hour day-of-month month day-of-week), a 6-field form whose first field is seconds, and the macros @yearly, @annually, @monthly, @weekly, @daily, @midnight, @hourly. Returns an English description, a field-by-field breakdown with the expanded values, the day-matching rule in effect, and the next run times after `from` in `zone`. Day-of-month and day-of-week follow Vixie cron: when both are restricted a day matches if EITHER matches (`0 0 13 * 5` runs on every 13th AND every Friday); a field starting with `*` (such as `*/2`) counts as unrestricted, and then a day must match both. Errors name the offending field. Call with a data part {\"skill\":\"cron_explain\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/cron_explain/","tags":["Time & Scheduling","cron"],"quality_warning":false},{"skill_id":"json_format","name":"Format and validate JSON","description":"Check that text is valid JSON (RFC 8259), pretty-print or minify it, and find duplicate keys. Parses `input` strictly as RFC 8259 JSON and reports the first syntax error with line, column, offset, JSON Pointer and an excerpt; messages name the usual mistakes (trailing commas, single quotes, unquoted keys, comments, NaN, leading zeros) and say how to fix them. Invalid JSON is a successful response with `valid: false`, so check `valid`. For valid JSON it returns the document re-indented or minified, optionally with keys sorted, plus statistics. Only whitespace (and, with `sort_keys`, member order) changes: strings and numbers are copied exactly as written, so `1.0`, `1e5` and 20-digit integers survive. Duplicate keys, which JSON.parse silently collapses, are listed with JSON Pointers; the output keeps the last value at the first position, as JSON.parse does. Nesting deeper than 500 levels is rejected. Call with a data part {\"skill\":\"json_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_format/","tags":["Text & Data","json"],"quality_warning":false},{"skill_id":"toml_format","name":"Format, validate and lint TOML","description":"Check that text is valid TOML 1.0, list problems with line and column, and re-format it with comments kept. Parses `input` as TOML 1.0.0 and returns every finding as a diagnostic with a rule ID, severity, line, column and offset: syntax errors, duplicate keys and tables, integers beyond 64 bits (errors); TOML 1.1-only syntax, inconsistent indentation, trailing spaces, mixed line endings (warnings); unnecessary key quotes, split or out-of-order tables, long inline tables, empty tables, long lines (info). Only the first syntax error is reported. An invalid document is a successful response with `valid: false`, so check `valid`. For a valid document it also returns the canonical formatting and the data as JSON. Formatting keeps every comment and never changes the data: keys are written `key = value` with one space around `=`, indentation and trailing spaces are removed, there is one blank line before each table header, arrays longer than `max_line_length` are broken one element per line, and the text ends with one line break. Strings, numbers and dates are copied as written. In `value`, integers beyond ±(2^53 − 1) are decimal strings, `inf`/`nan` are the strings `\"inf\"`, `\"-inf\"` and `\"nan\"`, and dates and times are ISO 8601 strings. Call with a data part {\"skill\":\"toml_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/toml_format/","tags":["Text & Data","toml"],"quality_warning":false},{"skill_id":"uuid_generate","name":"Generate UUIDs","description":"Generate random (v4) or time-ordered (v7) UUIDs, up to 1000 at a time. Generates RFC 9562 UUIDs. Version 4: 122 random bits from `crypto.randomUUID()`. Version 7: a 48-bit Unix millisecond timestamp, then a 42-bit counter (randomly seeded each millisecond, incremented within it) and 32 fresh random bits, so every batch is strictly increasing in both byte and string order. UUIDs are identifiers, not secrets: do not use them as passwords, API keys, session tokens or capability URLs, even though v4 uses a CSPRNG. Call with a data part {\"skill\":\"uuid_generate\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/uuid_generate/","tags":["Inspect & Identify","uuid"],"quality_warning":false},{"skill_id":"html_decode","name":"HTML entities: Decode","description":"Decode HTML entities. Decodes all 2,231 named entities of the HTML Living Standard plus decimal and hex numeric references, using the HTML parser rules (legacy entities without `;` included). Call with a data part {\"skill\":\"html_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/html_decode/","tags":["Encoding","html"],"quality_warning":false},{"skill_id":"html_encode","name":"HTML entities: Encode","description":"Escape text for HTML. `minimal` escapes `& < > \" '`, which is sufficient inside element content and quoted attributes. `ascii` additionally writes every non-ASCII code point as `&#x…;`. Call with a data part {\"skill\":\"html_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/html_encode/","tags":["Encoding","html"],"quality_warning":false},{"skill_id":"hash","name":"Hash","description":"Digest data with one or more hash algorithms. Computes MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-512, BLAKE2b-512, BLAKE3 digests of the data. MD5 and SHA-1 are broken for collision resistance: use them only to match existing checksums. HMAC is deliberately not offered by the API, because it needs a secret key and this server never accepts secrets; compute HMACs on the page, which runs locally. Call with a data part {\"skill\":\"hash\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hash/","tags":["Hashing","hash"],"quality_warning":false},{"skill_id":"hex_decode","name":"Hex: Hex → Text","description":"Hexadecimal bytes to text. Accepts any mix of plain, spaced, `\\x`, `0x`, comma, and colon separated hex, in either case. Call with a data part {\"skill\":\"hex_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hex_decode/","tags":["Encoding","hex"],"quality_warning":false},{"skill_id":"hex_encode","name":"Hex: Text → Hex","description":"Text to hexadecimal UTF-8 bytes. Writes each UTF-8 byte of `input` as two lowercase hex digits in the chosen layout. Call with a data part {\"skill\":\"hex_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hex_encode/","tags":["Encoding","hex"],"quality_warning":false},{"skill_id":"uuid_inspect","name":"Inspect a UUID","description":"Read a UUID’s version, variant and embedded timestamp, clock sequence and node. Parses a UUID written as 8-4-4-4-12 hex, 32 hex digits, `{…}` or `urn:uuid:…` (any case) and reports its RFC 9562 variant and version, whether it is the Nil or Max UUID, and the fields its version defines: the timestamp of v1, v6 and v7 as ISO 8601 (v1/v6 to 100 ns), and the clock sequence and node of v1 and v6. It also returns the UUID in every common format. Call with a data part {\"skill\":\"uuid_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/uuid_inspect/","tags":["Inspect & Identify","uuid"],"quality_warning":false},{"skill_id":"ip_inspect","name":"Inspect an IP address","description":"Canonical form, special-purpose ranges, embedded IPv4 and global reachability of any IPv4 or IPv6 address. Parses an IPv4 or IPv6 address in any spelling and returns its canonical form (RFC 5952 for IPv6), the full expanded form and integer value, any IPv4 address embedded in an IPv6 address (IPv4-mapped, IPv4-compatible, IPv4-translated, NAT64 `64:ff9b::/96` and `64:ff9b:1::/48`, 6to4, Teredo), every range it falls in from the IANA IPv4 and IPv6 Special-Purpose Address Registries (with their source, destination, forwardable, globally-reachable and reserved columns), and whether it is globally reachable. An embedded IPv4 address is checked too, so `::ffff:a00:1` is reported as private-use `10.0.0.1`. Non-standard IPv4 spellings that browsers and `inet_aton` accept (`127.1`, `0x7f.0.0.1`, `0177.0.0.1`, `2130706433`) are read the way they are and flagged. A `/prefix` adds the network, and `cidrs` tests membership. Nothing is resolved or contacted. Call with a data part {\"skill\":\"ip_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/ip_inspect/","tags":["Inspect & Identify","ip"],"quality_warning":false},{"skill_id":"text_inspect","name":"Inspect and count text","description":"Exact counts of characters, bytes, words and lines; find substrings; reveal invisible characters. Counts text the ways software disagrees about: grapheme clusters (what people see as characters), code points, UTF-16 code units (JavaScript length) and UTF-8 bytes; lines with their line-ending style; words and sentences (Intl.Segmenter); and letters, digits, whitespace and punctuation by Unicode property. With `find`, counts occurrences of a substring or character and returns each position (e.g. `find=r` in `strawberry` is 3). It also reports invisible and deceptive characters with positions: zero-width characters, bidirectional controls (Trojan Source, CVE-2021-42574), unusual spaces such as NBSP, BOM, control characters, Unicode tag characters (hidden-prompt smuggling), and Latin look-alikes in mixed-script words. Use this instead of counting characters yourself. Call with a data part {\"skill\":\"text_inspect\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/text_inspect/","tags":["Text & Data","text"],"quality_warning":false},{"skill_id":"fingerprint","name":"Key and certificate fingerprints","description":"Fingerprint SSH keys, X.509 certificates, SPKI public keys, and OpenPGP keys. Finds every public key in `input` and returns its fingerprints in the formats other tools print. SSH: `ssh-keygen -l` SHA256 and MD5. Certificates: `openssl x509 -fingerprint` SHA-1 and SHA-256 over the DER, plus the RFC 7469 SPKI pin. PEM public keys: SHA-256 over the SubjectPublicKeyInfo. Where an equivalent exists, the SSH fingerprint of the same key is included, so you can confirm that a certificate and an SSH key share a key. OpenPGP: v4 (SHA-1) and v6 (SHA-256) fingerprints and key IDs for the primary key and subkeys. Private keys are refused. Call with a data part {\"skill\":\"fingerprint\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/fingerprint/","tags":["Keys & Certificates","fingerprint"],"quality_warning":false},{"skill_id":"json_lint","name":"Lint JSON","description":"Validate JSON strictly and report every lint finding with its position. Parses `input` as strict RFC 8259 JSON and runs the lint rules: `syntax`, `duplicate-keys`, `number-precision`, `string-encoding`, `indent-style`, `indent`, `trailing-spaces`, `final-newline`, `line-endings`, `byte-order-mark`, `line-length`. Every finding has a rule ID, severity, message, line, column and offset. Invalid JSON is a 200 response with `valid: false`. Use `json_format` for the formatted output and statistics. Call with a data part {\"skill\":\"json_lint\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_lint/","tags":["Text & Data","json"],"quality_warning":false},{"skill_id":"yaml_format","name":"Lint and format YAML","description":"Check YAML against yamllint’s rules (same rule IDs) and return the findings with positions, plus a comment-preserving formatted copy. Parses `input` as YAML 1.2 (core schema) and reports every finding with its rule, severity, line, column and offset. Rules follow yamllint's default set and names: `syntax`, `key-duplicates`, `anchors`, `braces`, `brackets`, `colons`, `commas`, `comments`, `comments-indentation`, `document-start`, `empty-lines`, `empty-values`, `hyphens`, `indentation`, `line-length`, `new-line-at-end-of-file`, `new-lines`, `octal-values`, `quoted-strings`, `trailing-spaces`, `truthy`, `byte-order-mark`. Errors (`syntax`, `key-duplicates`, an alias without an anchor) make the document invalid; everything else is a warning or info. An invalid document is still a 200 response, with `valid: false`, the findings, and `formatted` and `value` set to null. When the YAML is valid, `formatted` is the document re-written with the chosen indentation, one space after colons and hyphens, no padding inside `{}`/`[]`, at most one blank line in a row, LF line breaks and a final newline. Comments, anchors, tags, key order, block scalars and the text of numbers are kept; quotes are removed only where the plain form means the same string in YAML 1.2 and 1.1 (`\"yes\"`, `\"0755\"`, `\"null\"` stay quoted). The formatted text is re-parsed and compared with the input before it is returned, so it always has the same value. `value` is the data as JSON: the first document's value, or an array of all documents when there are several (merge keys applied, at most 1,000 alias expansions). Call with a data part {\"skill\":\"yaml_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/yaml_format/","tags":["Text & Data","yaml"],"quality_warning":false},{"skill_id":"tool_requests","name":"List your tool requests","description":"See the tool requests you have made with these credentials and what became of each. Returns every tool request made with your client ID (from the API, MCP, A2A or the web form), newest first, with its current status. When a request is `shipped`, `shipped_url` points at the new tool. Call with a data part {\"skill\":\"tool_requests\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tool_requests/","tags":["Requests","request"],"quality_warning":false},{"skill_id":"url_parse","name":"Parse a URL","description":"Split a URL into its parts with the WHATWG URL parser browsers use. Parses a URL exactly as browsers and Cloudflare Workers do (WHATWG URL Standard) and returns every component: scheme, username, host in ASCII and Unicode forms, port and default port, origin, path segments decoded, query parameters as an ordered list (duplicates kept), and fragment. It classifies the host (domain, IPv4, IPv6, localhost, private or other special-purpose range) without resolving DNS. A password, if present, is never returned: `hasPassword` is true and `href` shows `***` instead. With `base`, a relative reference is resolved first. Call with a data part {\"skill\":\"url_parse\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_parse/","tags":["Inspect & Identify","url-parse"],"quality_warning":false},{"skill_id":"punycode_encode","name":"Punycode: To ASCII","description":"Unicode domain to ASCII (IDNA / RFC 3492). `domain` converts each non-ASCII label to `xn--` form (dots and email local parts preserved). `raw` applies bare RFC 3492 Punycode with no prefix. Call with a data part {\"skill\":\"punycode_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/punycode_encode/","tags":["Encoding","punycode"],"quality_warning":false},{"skill_id":"punycode_decode","name":"Punycode: To Unicode","description":"ASCII (xn--) domain to Unicode. `domain` decodes each `xn--` label. `raw` decodes a bare Punycode string. Call with a data part {\"skill\":\"punycode_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/punycode_decode/","tags":["Encoding","punycode"],"quality_warning":false},{"skill_id":"json_query","name":"Query JSON with JMESPath","description":"Evaluate a JMESPath expression against JSON and return the result, its type and pretty JSON. Evaluates `expression` against `input` with @jmespath-community/jmespath (JMESPath Community Edition): the original JMESPath language plus `let` expressions, `$` for the root, arithmetic (`+ - * / % //`), the ternary `? :` operator, and extra functions such as `items`, `from_items`, `group_by`, `zip`, `find_first`, `pad_left`, `split`, `replace`, `trim`. A path that does not exist gives `null` (not an error). Syntax errors give the column of the offending token; unknown functions are reported before evaluation; type errors (for example `length` of a number) are reported with the function position. Call with a data part {\"skill\":\"json_query\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_query/","tags":["Text & Data","json-query"],"quality_warning":false},{"skill_id":"register","name":"Register for credentials","description":"Create a client_id and client_secret for this agent. No credentials required. Send a data part {\"skill\":\"register\",\"registration\":<document>} matching the registration schema in the registration extension.","tags":["auth","registration","onboarding"],"quality_warning":false},{"skill_id":"tool_request","name":"Request a new tool","description":"Ask for a new deterministic tool to be added to this service, describing the job and an example. Records a request for a new tool. Use it when you (an agent or a person) keep doing the same deterministic job that has exactly one right answer and no tool here does it: a conversion, a validation, a calculation, a parser. Describe the job in `problem`, and give an `example_input` and the `expected_output` if you can; concrete examples make a request much more likely to be built. Requests are reviewed by the owner; check progress with `tool_requests`. A request is a suggestion, not an order, and nothing is guaranteed. Each client can submit up to 20 requests per 24 hours. Call with a data part {\"skill\":\"tool_request\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/tool_request/","tags":["Requests","request"],"quality_warning":false},{"skill_id":"url_decode","name":"URL: Decode","description":"Decode percent-encoded text. Decodes `%XX` sequences as UTF-8. In `form` mode `+` is first turned into a space. Call with a data part {\"skill\":\"url_decode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_decode/","tags":["Encoding","url"],"quality_warning":false},{"skill_id":"url_encode","name":"URL: Encode","description":"Percent-encode text (RFC 3986). Percent-encodes the UTF-8 bytes of `input`. `component` matches JavaScript encodeURIComponent, `uri` matches encodeURI, and `form` is application/x-www-form-urlencoded (spaces become `+`). Call with a data part {\"skill\":\"url_encode\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/url_encode/","tags":["Encoding","url"],"quality_warning":false},{"skill_id":"json_schema_validate","name":"Validate JSON against a JSON Schema","description":"Validate a JSON instance against a JSON Schema (draft 2020-12, 2019-09, 7, 6 or 4) and list every error with JSON Pointers. Validates `instance` against `schema` with @cfworker/json-schema (an interpreter: no code generation). The draft comes from `draft`, else from the schema's `$schema`, else 2020-12. Returns `valid` and, for an invalid instance, each error with the instance location and keyword location as JSON Pointers, the location of the keyword in the schema document (after following `$ref`), and a message; `leaf: false` marks summary errors (from `properties`, `items`, `$ref`, `anyOf`, …) that are followed by the specific errors beneath them. An invalid instance is a successful response with `valid: false`. Before validating, the schema is checked for usability (keyword types, regular expressions, unresolved references); problems are a 422 error. Only local references resolve: `$ref` to a remote URL is never fetched (the server makes no network requests); embed such schemas under `$defs` with their `$id`. `format` is asserted for the formats listed in the docs. `$dynamicRef` is not supported. At most 1000 errors are returned. Call with a data part {\"skill\":\"json_schema_validate\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/json_schema_validate/","tags":["Text & Data","json-schema"],"quality_warning":false},{"skill_id":"csv_format","name":"Validate and format CSV","description":"Check CSV against RFC 4180, detect the delimiter and header, infer column types, list every problem with its position, and rewrite it consistently. Parses `input` as RFC 4180 CSV, also accepting semicolon, tab and pipe delimiters and LF or CR line breaks. Reports every problem as a diagnostic with a stable rule ID, severity, line, column and offset: unclosed quotes, stray quotes, text after a closing quote, rows with the wrong number of fields (errors); empty and duplicate header names, padded delimiters, blank lines, mixed line endings (warnings); and mixed column types, inconsistent quoting, trailing delimiters and values a spreadsheet could run as formulas (info). Invalid CSV is a successful response with `valid: false`, so check `valid`. `formatted` is the data rewritten with one delimiter, one quoting style and one line ending, blank lines and the byte-order mark removed, ending with a line break; it is null only when an unclosed quote makes the structure unknowable. Rows themselves are not returned: `preview` holds the first 20 data rows. At most 100 diagnostics are listed per rule, then one summarising the rest. Call with a data part {\"skill\":\"csv_format\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/csv_format/","tags":["Text & Data","csv"],"quality_warning":false},{"skill_id":"hash_verify","name":"Verify a checksum","description":"Check data against an expected hash or a checksum list. Hashes the data with every algorithm whose digest length matches the expected hash (for 64 hex digits: SHA-256, SHA3-256 and BLAKE3) and reports whether any matches. `expected` may be hex, Base64, SRI (`sha384-…`), prefixed (`sha256:…`), or a whole GNU/BSD checksum file, in which case the line for `filename` (or the uploaded file name) is used. A mismatch is a successful response with `match: false`. Call with a data part {\"skill\":\"hash_verify\",\"arguments\":{…}}. Reference: https://util.caruana.me/reference/hash_verify/","tags":["Hashing","hash-verify"],"quality_warning":false}],"quality_flags":[],"check_history":{"checks":2,"passed":2},"recent_checks":[{"card_url":"https://util.caruana.me/.well-known/agent-card.json","checked_at":"2026-10-15T14:09:04.055992+00:00","success":true,"http_status":200,"detail":"Agent Card validated"},{"card_url":"https://util.caruana.me/.well-known/agent-card.json","checked_at":"2026-10-15T12:03:49.057625+00:00","success":true,"http_status":200,"detail":"Agent Card validated"}],"endpoint_tls_check":{"checked_at":"2026-10-15T14:09:04.055992+00:00","success":true,"detail":"Valid TLS connection to advertised endpoint host; no A2A request sent"},"protocol_check":{"checked_at":"2026-10-15T12:03:49.057625+00:00","state":"a2a_response","http_status":404,"detail":"A2A task-not-found response to a read-only task lookup"},"x402_price_check":null,"events":[],"relationships":[],"verification":{"agent_card_url":"https://util.caruana.me/.well-known/agent-card.json","last_successful_card_check":"2026-10-15T14:09:04.055992+00:00","latest_card_check":{"checked_at":"2026-10-15T14:09:04.055992+00:00","success":true,"http_status":200,"detail":"Agent Card validated"},"signature_status":"verified","signature_checked_at":"2026-10-15T14:09:04.055992+00:00","task_endpoint_tested":true,"task_execution_tested":false,"endpoint_tls_checked_at":"2026-10-15T14:09:04.055992+00:00","endpoint_tls_reachable":true,"protocol_check_state":"a2a_response","protocol_checked_at":"2026-10-15T12:03:49.057625+00:00","provider_identity_verified":false,"domain_claimed_at":null,"domain_proof_checked_at":null}}