{
  "schemaVersion": "0.1.0",
  "name": "Aaron Chartier — client-side tools",
  "description": "Free deterministic developer tools that run entirely in the visitor's browser. No backend, no tracking; input you type or pass in the URL #fragment is never sent to the server. Discoverable and invocable by agents in-page (window.__tools), via URL #fragment parameters, and via WebMCP where supported.",
  "url": "https://aaronchartier.com",
  "contact": {
    "url": "https://github.com/AaronChartier"
  },
  "capabilities": {
    "webmcp": true,
    "a2a": false,
    "auth": "none"
  },
  "invocation": {
    "summary": "Each tool is a deterministic client-side function. Load the tool page, then call it.",
    "pageApi": "After hydration window.__tools[slug] exposes run(input) and describe(); describe() returns { slug, params, returns }.",
    "urlParams": "Documented parameters in the URL #fragment (e.g. /tools/base64#input=hello) pre-fill inputs and auto-run; the fragment is never sent to the server. A ?query form also works for back-compat but is part of the request and may be logged.",
    "output": "Results render into the element with id 'tool-output'.",
    "webmcp": "Where the browser exposes navigator.modelContext (WebMCP), each tool is also registered there automatically and read-only."
  },
  "tools": [
    {
      "name": "base64",
      "title": "base64 encoder / decoder",
      "description": "Unicode-safe Base64 encode and decode, with URL-safe variant.",
      "category": "encode",
      "status": "live",
      "url": "https://aaronchartier.com/tools/base64",
      "manifest": "https://aaronchartier.com/tools/base64.json",
      "keywords": [
        "base64",
        "encode",
        "decode",
        "btoa",
        "atob"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"base64\"].run(input)",
        "describe": "window.__tools[\"base64\"].describe()",
        "webmcpName": "base64",
        "output": "#tool-output"
      }
    },
    {
      "name": "url",
      "title": "url encoder / decoder",
      "description": "Percent-encode and decode URLs and query components.",
      "category": "encode",
      "status": "live",
      "url": "https://aaronchartier.com/tools/url",
      "manifest": "https://aaronchartier.com/tools/url.json",
      "keywords": [
        "url",
        "percent",
        "encode",
        "decode",
        "query string"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"url\"].run(input)",
        "describe": "window.__tools[\"url\"].describe()",
        "webmcpName": "url",
        "output": "#tool-output"
      }
    },
    {
      "name": "jwt",
      "title": "jwt encoder / decoder",
      "description": "Decode a JWT's header, payload and time claims — or encode and HMAC-sign a new token. All in the browser.",
      "category": "encode",
      "status": "live",
      "url": "https://aaronchartier.com/tools/jwt",
      "manifest": "https://aaronchartier.com/tools/jwt.json",
      "keywords": [
        "jwt",
        "json web token",
        "decode",
        "encode",
        "sign",
        "hmac",
        "claims",
        "exp"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"jwt\"].run(input)",
        "describe": "window.__tools[\"jwt\"].describe()",
        "webmcpName": "jwt",
        "output": "#tool-output"
      }
    },
    {
      "name": "hash",
      "title": "hash digest",
      "description": "SHA-1 / SHA-256 / SHA-384 / SHA-512 of text or files, via WebCrypto.",
      "category": "encode",
      "status": "live",
      "url": "https://aaronchartier.com/tools/hash",
      "manifest": "https://aaronchartier.com/tools/hash.json",
      "keywords": [
        "hash",
        "sha256",
        "sha512",
        "checksum",
        "digest"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"hash\"].run(input)",
        "describe": "window.__tools[\"hash\"].describe()",
        "webmcpName": "hash",
        "output": "#tool-output"
      }
    },
    {
      "name": "radix",
      "title": "number base converter",
      "description": "Binary, octal, decimal, hex — arbitrary precision via BigInt.",
      "category": "convert",
      "status": "live",
      "url": "https://aaronchartier.com/tools/radix",
      "manifest": "https://aaronchartier.com/tools/radix.json",
      "keywords": [
        "binary",
        "hex",
        "octal",
        "decimal",
        "base",
        "radix"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"radix\"].run(input)",
        "describe": "window.__tools[\"radix\"].describe()",
        "webmcpName": "radix",
        "output": "#tool-output"
      }
    },
    {
      "name": "timestamp",
      "title": "unix timestamp converter",
      "description": "Epoch seconds/millis ⇄ human dates, timezone-aware, with relative time.",
      "category": "time",
      "status": "live",
      "url": "https://aaronchartier.com/tools/timestamp",
      "manifest": "https://aaronchartier.com/tools/timestamp.json",
      "keywords": [
        "unix",
        "epoch",
        "timestamp",
        "date",
        "timezone"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"timestamp\"].run(input)",
        "describe": "window.__tools[\"timestamp\"].describe()",
        "webmcpName": "timestamp",
        "output": "#tool-output"
      }
    },
    {
      "name": "cron",
      "title": "cron explainer",
      "description": "Cron expression → plain-English schedule + the next run times.",
      "category": "time",
      "status": "live",
      "url": "https://aaronchartier.com/tools/cron",
      "manifest": "https://aaronchartier.com/tools/cron.json",
      "keywords": [
        "cron",
        "crontab",
        "schedule",
        "expression"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"cron\"].run(input)",
        "describe": "window.__tools[\"cron\"].describe()",
        "webmcpName": "cron",
        "output": "#tool-output"
      }
    },
    {
      "name": "uuid",
      "title": "uuid generator",
      "description": "UUID v4 and v7, single or bulk, copy-ready.",
      "category": "generate",
      "status": "live",
      "url": "https://aaronchartier.com/tools/uuid",
      "manifest": "https://aaronchartier.com/tools/uuid.json",
      "keywords": [
        "uuid",
        "guid",
        "v4",
        "v7",
        "generator"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"uuid\"].run(input)",
        "describe": "window.__tools[\"uuid\"].describe()",
        "webmcpName": "uuid",
        "output": "#tool-output"
      }
    },
    {
      "name": "json",
      "title": "json formatter & validator",
      "description": "Pretty-print, minify, validate — with precise error positions.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/json",
      "manifest": "https://aaronchartier.com/tools/json.json",
      "keywords": [
        "json",
        "format",
        "validate",
        "minify",
        "pretty print"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"json\"].run(input)",
        "describe": "window.__tools[\"json\"].describe()",
        "webmcpName": "json",
        "output": "#tool-output"
      }
    },
    {
      "name": "case",
      "title": "case converter",
      "description": "camelCase, snake_case, kebab-case, Title Case, CONSTANT_CASE and more.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/case",
      "manifest": "https://aaronchartier.com/tools/case.json",
      "keywords": [
        "case",
        "camel",
        "snake",
        "kebab",
        "convert"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"case\"].run(input)",
        "describe": "window.__tools[\"case\"].describe()",
        "webmcpName": "case",
        "output": "#tool-output"
      }
    },
    {
      "name": "diff",
      "title": "text diff",
      "description": "Line and word diff of two texts, computed locally.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/diff",
      "manifest": "https://aaronchartier.com/tools/diff.json",
      "keywords": [
        "diff",
        "compare",
        "text",
        "patch"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"diff\"].run(input)",
        "describe": "window.__tools[\"diff\"].describe()",
        "webmcpName": "diff",
        "output": "#tool-output"
      }
    },
    {
      "name": "regex",
      "title": "regex tester",
      "description": "Live match highlighting, capture groups, and a common-pattern library.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/regex",
      "manifest": "https://aaronchartier.com/tools/regex.json",
      "keywords": [
        "regex",
        "regexp",
        "match",
        "test",
        "pattern"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"regex\"].run(input)",
        "describe": "window.__tools[\"regex\"].describe()",
        "webmcpName": "regex",
        "output": "#tool-output"
      }
    },
    {
      "name": "markdown",
      "title": "markdown editor",
      "description": "Split-pane markdown editor — live preview, right-to-left aware, copy as HTML, Markdown, or rich text.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/markdown",
      "manifest": "https://aaronchartier.com/tools/markdown.json",
      "keywords": [
        "markdown",
        "preview",
        "editor",
        "md",
        "rtl",
        "hebrew",
        "arabic",
        "rich text",
        "html"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"markdown\"].run(input)",
        "describe": "window.__tools[\"markdown\"].describe()",
        "webmcpName": "markdown",
        "output": "#tool-output"
      }
    },
    {
      "name": "count",
      "title": "word & character counter",
      "description": "Words, characters, lines, reading time, and word frequency.",
      "category": "text",
      "status": "live",
      "url": "https://aaronchartier.com/tools/count",
      "manifest": "https://aaronchartier.com/tools/count.json",
      "keywords": [
        "word count",
        "character count",
        "reading time"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"count\"].run(input)",
        "describe": "window.__tools[\"count\"].describe()",
        "webmcpName": "count",
        "output": "#tool-output"
      }
    },
    {
      "name": "plot",
      "title": "graphing calculator",
      "description": "Plot functions on an interactive canvas — pan, zoom, multiple expressions, shareable links.",
      "category": "math",
      "status": "live",
      "url": "https://aaronchartier.com/tools/plot",
      "manifest": "https://aaronchartier.com/tools/plot.json",
      "keywords": [
        "graph",
        "plot",
        "function",
        "calculator",
        "math"
      ],
      "invocation": {
        "pageApi": "window.__tools[\"plot\"].run(input)",
        "describe": "window.__tools[\"plot\"].describe()",
        "webmcpName": "plot",
        "output": "#tool-output"
      }
    }
  ]
}