{"_id":"@alokraj68/craftkit","_rev":"5-befc6cd0fbdff8737180c4125bb589e3","name":"@alokraj68/craftkit","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.0":{"name":"@alokraj68/craftkit","version":"1.0.0","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"author":{"url":"https://alokraj68.in","name":"Alok Rajasukumaran"},"license":"MIT","_id":"@alokraj68/craftkit@1.0.0","maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"homepage":"https://github.com/alokraj68/craftkit#readme","bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"bin":{"craftkit":"toolkit/onboard.mjs"},"dist":{"shasum":"92060cb01821236bd844a732a7dd3912e7ea8855","tarball":"https://registry.npmjs.org/@alokraj68/craftkit/-/craftkit-1.0.0.tgz","fileCount":5,"integrity":"sha512-ApkrF6QckER/CUmbHKJt1NKi1zBCKV6oSs6NZAS0Ct/UFtf/B2NlW3L4KVM8rFv33ESTmTuRVnF1E23mMZqjrQ==","signatures":[{"sig":"MEUCIC65uUvMkYFFThE713VSu0K0zwo6t4uvBhVN3b7myl40AiEA30B1gGwalaEdt4SveIf3E9R0+2YpPnXq0Gk8jbKjqzM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40058},"type":"module","engines":{"node":">=18"},"gitHead":"4c12c29484577adbd096f254aec68c01c78c763a","scripts":{"test":"node plugins/plainspoken/test/run.mjs && node plugins/ats-resume/test/run.mjs && node plugins/pagecheck/test/run.mjs","onboard":"node toolkit/onboard.mjs","test:page":"node plugins/pagecheck/test/run.mjs","lint:prose":"node plugins/plainspoken/bin/plainspoken.mjs README.md CLAUDE.md plugins/*/README.md plugins/*/skills/*/SKILL.md","test:prose":"node plugins/plainspoken/test/run.mjs","test:resume":"node plugins/ats-resume/test/run.mjs"},"_npmUser":{"name":"alokraj68","email":"alokraj68@gmail.com"},"repository":{"url":"git+https://github.com/alokraj68/craftkit.git","type":"git"},"_npmVersion":"11.13.0","description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","directories":{},"_nodeVersion":"24.16.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/craftkit_1.0.0_1787120307617_0.2286177195177268","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@alokraj68/craftkit","version":"1.0.1","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"author":{"url":"https://alokraj68.in","name":"Alok Rajasukumaran"},"license":"MIT","_id":"@alokraj68/craftkit@1.0.1","maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"homepage":"https://github.com/alokraj68/craftkit#readme","bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"bin":{"craftkit":"toolkit/onboard.mjs"},"dist":{"shasum":"acc31f47d0a91e665253d30f9e3d24b9e3bb6928","tarball":"https://registry.npmjs.org/@alokraj68/craftkit/-/craftkit-1.0.1.tgz","fileCount":6,"integrity":"sha512-2U4aGoIO/znavUBXpSzN+fixshiiNz91NGfMuLuVTNVo4s/aHBOJR5ut3ha4HWDq+6xhYBFfrSUP75u5hoV4rg==","signatures":[{"sig":"MEQCIDwmnKiDr8J0CgmmqDu3ck1nIClFt5qg3hCkdcP9v3qHAiBuQtYzN7kTdzarMVf9VZkoZMUbqjB3O4246fPEi0WvAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alokraj68%2fcraftkit@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":47996},"type":"module","engines":{"node":">=18"},"gitHead":"600f7b29b2ee878679b6f46db6e1e15c7d1606a4","scripts":{"test":"node plugins/plainspoken/test/run.mjs && node plugins/ats-resume/test/run.mjs && node plugins/pagecheck/test/run.mjs","onboard":"node toolkit/onboard.mjs","release":"node toolkit/release.mjs","test:page":"node plugins/pagecheck/test/run.mjs","lint:prose":"node plugins/plainspoken/bin/plainspoken.mjs README.md CLAUDE.md plugins/*/README.md plugins/*/skills/*/SKILL.md","test:prose":"node plugins/plainspoken/test/run.mjs","test:resume":"node plugins/ats-resume/test/run.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:35ce6103-1639-4605-8688-a9fc67acfc9c"}},"repository":{"url":"git+https://github.com/alokraj68/craftkit.git","type":"git"},"_npmVersion":"12.0.2","description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/craftkit_1.0.1_1787122730499_0.02672510227882441","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@alokraj68/craftkit","version":"1.0.2","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"author":{"url":"https://alokraj68.in","name":"Alok Rajasukumaran"},"license":"MIT","_id":"@alokraj68/craftkit@1.0.2","maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"homepage":"https://github.com/alokraj68/craftkit#readme","bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"bin":{"craftkit":"toolkit/onboard.mjs"},"dist":{"shasum":"f235fe9947ae5f518fd3cace85adedc8d2b3150c","tarball":"https://registry.npmjs.org/@alokraj68/craftkit/-/craftkit-1.0.2.tgz","fileCount":9,"integrity":"sha512-jXWlYeRTJ3uJPFIjlyzUrjgMoCUgohxOOTKlfjmbV/WyVLEzgfmIdC/B0M5B/X/hn2FNi6ubUxWscKqDqsLt+Q==","signatures":[{"sig":"MEUCIQDDz1Aj1OXHNEzfiNpa9SWembASj3peWrDho4j7K9TSlgIgUv9qduylOKxIORwnpNVMiS00barH8BYSmXQPU7y1nUg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alokraj68%2fcraftkit@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":69669},"type":"module","engines":{"node":">=18"},"gitHead":"8daf28449d234ea33b996e4d9c1ce08eac72402e","scripts":{"test":"node plugins/plainspoken/test/run.mjs && node plugins/ats-resume/test/run.mjs && node plugins/pagecheck/test/run.mjs","agents":"node toolkit/gen-agents.mjs","onboard":"node toolkit/onboard.mjs","release":"node toolkit/release.mjs","test:page":"node plugins/pagecheck/test/run.mjs","lint:prose":"node plugins/plainspoken/bin/plainspoken.mjs README.md CLAUDE.md plugins/*/README.md plugins/*/skills/*/SKILL.md","test:prose":"node plugins/plainspoken/test/run.mjs","test:resume":"node plugins/ats-resume/test/run.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:35ce6103-1639-4605-8688-a9fc67acfc9c"}},"repository":{"url":"git+https://github.com/alokraj68/craftkit.git","type":"git"},"_npmVersion":"12.0.2","description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/craftkit_1.0.2_1787143275781_0.4841781128899847","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@alokraj68/craftkit","version":"1.0.3","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"author":{"url":"https://alokraj68.in","name":"Alok Rajasukumaran"},"license":"MIT","_id":"@alokraj68/craftkit@1.0.3","maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"homepage":"https://github.com/alokraj68/craftkit#readme","bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"bin":{"craftkit":"toolkit/onboard.mjs"},"dist":{"shasum":"dc2107534e499c3e3c941fa6f3f5e508ba0fd756","tarball":"https://registry.npmjs.org/@alokraj68/craftkit/-/craftkit-1.0.3.tgz","fileCount":9,"integrity":"sha512-OeqTw04ufic0o1cxwR/QFrK+RFkoEl9kapgVBZl1o6uEY3xZ0dYnvRQdvfka/XtmvHeqaRzdcJREgA/i7MBmxw==","signatures":[{"sig":"MEYCIQCfU+eIDo3IW5XgS/5RYeu2TFA+IcOamlPNfvII6X7t0wIhAKsQ4hxTefghE23r19/l+RHZ4bH+ZrSjMxjHeeZofcJf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alokraj68%2fcraftkit@1.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":70460},"type":"module","engines":{"node":">=18"},"gitHead":"6a104567001eecde56da879ba1c2b957654dc8b1","scripts":{"test":"node plugins/plainspoken/test/run.mjs && node plugins/ats-resume/test/run.mjs && node plugins/pagecheck/test/run.mjs","agents":"node toolkit/gen-agents.mjs","onboard":"node toolkit/onboard.mjs","release":"node toolkit/release.mjs","test:page":"node plugins/pagecheck/test/run.mjs","lint:prose":"node plugins/plainspoken/bin/plainspoken.mjs README.md CLAUDE.md plugins/*/README.md plugins/*/skills/*/SKILL.md","test:prose":"node plugins/plainspoken/test/run.mjs","test:resume":"node plugins/ats-resume/test/run.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:35ce6103-1639-4605-8688-a9fc67acfc9c"}},"repository":{"url":"git+https://github.com/alokraj68/craftkit.git","type":"git"},"_npmVersion":"12.0.2","description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","directories":{},"_nodeVersion":"22.23.2","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/craftkit_1.0.3_1787147474884_0.8822162790676698","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@alokraj68/craftkit","version":"1.0.4","description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"license":"MIT","author":{"name":"Alok Rajasukumaran","url":"https://alokraj68.in"},"funding":[{"type":"github","url":"https://github.com/sponsors/alokraj68"},{"type":"buymeacoffee","url":"https://buymeacoffee.com/alokraj68"}],"repository":{"type":"git","url":"git+https://github.com/alokraj68/craftkit.git"},"homepage":"https://github.com/alokraj68/craftkit#readme","bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"type":"module","engines":{"node":">=18"},"bin":{"craftkit":"toolkit/onboard.mjs"},"scripts":{"test":"node plugins/plainspoken/test/run.mjs && node plugins/ats-resume/test/run.mjs && node plugins/pagecheck/test/run.mjs","test:prose":"node plugins/plainspoken/test/run.mjs","test:resume":"node plugins/ats-resume/test/run.mjs","test:page":"node plugins/pagecheck/test/run.mjs","lint:prose":"node plugins/plainspoken/bin/plainspoken.mjs README.md CLAUDE.md plugins/*/README.md plugins/*/skills/*/SKILL.md","onboard":"node toolkit/onboard.mjs","release":"node toolkit/release.mjs","agents":"node toolkit/gen-agents.mjs"},"gitHead":"3441a627b3328561f493710d37efd93a23066626","_id":"@alokraj68/craftkit@1.0.4","_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-XltsCvp6fH8GmvoWPFl37RnFuxP/FxkKWvxO/J1WQ9QwvsqLzVWFTskCW5LK3c1ED4BQcIRVlNtr9CdPrl4I5w==","shasum":"498f7423c23232ad18a4e4cb6c20de2243f33bab","tarball":"https://registry.npmjs.org/@alokraj68/craftkit/-/craftkit-1.0.4.tgz","fileCount":10,"unpackedSize":75596,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alokraj68%2fcraftkit@1.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGQALf4kiv/sH4aPBbZ9EyY3/fjQQaGpdsjIeAGEF71vAiB9cikHswEtPbKJ23yUmQzKi0/g7pbrSjPwoQoHuHSkpQ=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:35ce6103-1639-4605-8688-a9fc67acfc9c"}},"directories":{},"maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/craftkit_1.0.4_1787150854613_0.83614857759439"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-19T06:18:27.492Z","modified":"2026-08-19T14:47:35.068Z","1.0.0":"2026-08-19T06:18:27.760Z","1.0.1":"2026-08-19T06:58:50.635Z","1.0.2":"2026-08-19T12:41:15.929Z","1.0.3":"2026-08-19T13:51:15.031Z","1.0.4":"2026-08-19T14:47:34.753Z"},"bugs":{"url":"https://github.com/alokraj68/craftkit/issues"},"author":{"name":"Alok Rajasukumaran","url":"https://alokraj68.in"},"license":"MIT","homepage":"https://github.com/alokraj68/craftkit#readme","keywords":["claude-code","onboarding","setup","plugins","skills","cli","agent","developer-tools"],"repository":{"type":"git","url":"git+https://github.com/alokraj68/craftkit.git"},"description":"Set up Claude Code for what you actually do on this machine. Asks whether you are doing UI, writing, coding, resumes or SEO, then installs only those plugins and skills.","maintainers":[{"name":"alokraj68","email":"alokraj68@gmail.com"}],"readme":"<div align=\"center\">\n\n# 🧰 craftkit\n\n**Green means it was checked. Not that nobody looked.**\n\nFour Claude Code plugins that turn \"looks fine to me\" into a build that fails. Prose that reads as machine-written, pages that break on a phone, résumés no parser can read, and agents that say \"done\" without running anything: each one gets a gate instead of a good intention.\n\n[![CI](https://github.com/alokraj68/craftkit/actions/workflows/ci.yml/badge.svg)](https://github.com/alokraj68/craftkit/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/alokraj68/craftkit/actions/workflows/codeql.yml/badge.svg)](https://github.com/alokraj68/craftkit/actions/workflows/codeql.yml)\n[![npm version](https://img.shields.io/npm/v/@alokraj68/craftkit.svg)](https://www.npmjs.com/package/@alokraj68/craftkit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![Node >=18](https://img.shields.io/badge/Node-%3E%3D18-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org)\n[![plugins](https://img.shields.io/badge/plugins-4-6E56CF.svg)](#-the-four-plugins)\n[![tests](https://img.shields.io/badge/tests-91-2EA043.svg)](#-the-filter-every-rule-had-to-pass)\n[![runtime deps](https://img.shields.io/badge/runtime%20deps-0-2EA043.svg)](#-how-it-works)\n[![Platforms](https://github.com/alokraj68/craftkit/actions/workflows/platforms.yml/badge.svg)](https://github.com/alokraj68/craftkit/actions/workflows/platforms.yml)\n[![Claude Code](https://img.shields.io/badge/Claude%20Code-plugin%20marketplace-D97757.svg)](https://claude.com/claude-code)\n[![AGENTS.md](https://img.shields.io/badge/AGENTS.md-any%20agent-4A5568.svg)](#-any-agent-not-just-claude-code)\n[![platforms](https://img.shields.io/badge/win%20%7C%20mac%20%7C%20linux%20%7C%20alpine-tested-2EA043.svg)](#-runs-everywhere-checked-not-claimed)\n\n```\nnpx @alokraj68/craftkit\n```\n\n</div>\n\n---\n\n## ✨ Why craftkit?\n\nMost quality tooling fails the same way: it fires on work that was already correct. One noisy run and everybody adds `--no-verify` to muscle memory. After that the checker catches nothing, forever.\n\nSo every rule here had to clear two bars, not one. **Fire on writing built to trip it, and stay silent on writing that is merely factual.** Both halves are in the test suite. The second half is why most of a well-known 980-line de-slop catalogue is *not* in this repo.\n\n| | |\n|---|---|\n| ✍️ **`plainspoken`** | Fails the build when prose reads as machine-written. AI phrases, vague tails, paired adjectives, tool-list endings, abstraction ratios |\n| 📱 **`pagecheck`** | Fails when a page breaks on a phone. Overflow and the element causing it, ragged lines, sub-12px text, tap targets under 44px, WCAG AA contrast |\n| 📄 **`ats-resume`** | Fails when an applicant tracking system cannot parse the file. Built on the [JSON Resume](https://jsonresume.org) schema, with job-description gap analysis |\n| 🧭 **`craft-setup`** | The working agreement. Verify before claiming done, never commit unasked, enforce in code rather than in a checklist |\n| 🎒 **`toolkit/`** | 47 curated third-party skills, installed from upstream. Nothing vendored, nothing relicensed |\n| 🪶 **Zero runtime deps** | `plainspoken` and `ats-resume` have none at all. `pagecheck` takes Playwright as an optional peer |\n\n## 📚 Table of Contents\n\n- [Requirements](#-requirements)\n- [Install](#-install)\n- [The four plugins](#-the-four-plugins)\n- [The filter every rule had to pass](#-the-filter-every-rule-had-to-pass)\n- [Runs everywhere](#-runs-everywhere-checked-not-claimed)\n- [Any agent, not just Claude Code](#-any-agent-not-just-claude-code)\n- [The curated toolkit](#-the-curated-toolkit)\n- [How it works](#-how-it-works)\n- [For AI coding agents](#-for-ai-coding-agents)\n- [Roadmap](#-roadmap)\n- [Contributing](#-contributing)\n- [Credits](#-credits)\n- [License](#-license)\n\n## ✅ Requirements\n\n- **Node** `>=18`, ESM only, no build step\n- **Claude Code** for the plugin and skill half. The CLIs run standalone without it\n- **Playwright** only for `pagecheck`, and only for the browser half of its tests\n\n## 📦 Install\n\nOne command. It asks what you do on this machine, then installs only that.\n\n```bash\nnpx @alokraj68/craftkit\n```\n\n```\n  What will you be doing on this machine?\n  Pick any number of them.\n\n    1  📦  Everything\n    2  🎨  UI / UX and frontend design\n    3  ✍️  Writing, docs and READMEs\n    4  💻  Coding\n    5  📄  Résumé and job search\n    6  🔍  SEO and content strategy\n\n  Whatever you pick, caveman and lean-ctx are installed too.\n\n  Numbers (e.g. 2,4), or blank to cancel:\n```\n\nIt then enables the plugins by writing `settings.json`, clones the skills from\ntheir own upstreams, and runs the two installers that cannot be a plain copy.\n\n| | |\n|---|---|\n| 🎨 **ui** | frontend-design, ui-ux-pro-max, design-taste-frontend, nine Emil Kowalski motion skills, impeccable, `pagecheck` |\n| ✍️ **writing** | `plainspoken` |\n| 💻 **coding** | ponytail, karpathy-guidelines, `craft-setup` |\n| 📄 **resume** | `ats-resume`, `plainspoken` |\n| 🔍 **seo** | ~30 SEO skills |\n| ⚙️ **always** | caveman, lean-ctx |\n\n```bash\nnpx @alokraj68/craftkit --list          # the whole catalogue, install nothing\nnpx @alokraj68/craftkit ui coding       # skip the question\nnpx @alokraj68/craftkit ui --dry-run    # show exactly what would happen\nnpx @alokraj68/craftkit --all --yes     # everything, no prompts\nnpx @alokraj68/craftkit writing --project   # write ./.claude/settings.json, not ~/\n```\n\n**Nothing runs before you have seen it.** The plan lists every plugin, every\nrepository, and the exact text of every command, including the one that pipes a\nremote script into bash. Your `settings.json` is backed up before it is touched.\n\n### Just the plugins\n\nIf you would rather skip the wizard:\n\n```\n/plugin marketplace add alokraj68/craftkit\n\n/plugin install plainspoken@craftkit\n/plugin install pagecheck@craftkit\n/plugin install ats-resume@craftkit\n/plugin install craft-setup@craftkit\n```\n\nOr install a CLI on its own:\n\n```bash\nnpm i -D @alokraj68/plainspoken\nnpm i -D @alokraj68/pagecheck playwright\nnpm i -D @alokraj68/ats-resume\n```\n\n## 🧩 The four plugins\n\n### ✍️ plainspoken\n\n[npm](https://www.npmjs.com/package/@alokraj68/plainspoken) · [docs](./plugins/plainspoken) · [skill](./plugins/plainspoken/skills/plain-writing/SKILL.md)\n\nReads Markdown and plain text, so it works on docs, READMEs, release notes, landing copy and CVs alike.\n\n```bash\nnode plugins/plainspoken/bin/plainspoken.mjs docs/\n```\n\n```\ndocs/architecture.md\n  error   14  ai-phrase        \"proven track record\" has no defensible use\n  error   31  vague-tail       trails off into a vague clause instead of landing on a result\n        Built the reporting layer, enabling improved efficiency\n  warn    22  ai-word          \"leverage\" - try: use, apply, draw on\n```\n\n| | |\n|---|---|\n| 🔴 **Errors** | Fixed phrases with no defensible use. `\"proven track record\"` is never correct |\n| 🟡 **Warnings** | Ratios and rhythm. A short factual README trips the abstraction ratio, and failing a build over that is how a linter gets deleted |\n| 🎚️ **Presets** | `docs` (default), `resume` (ratios become gates), `strict` (everything fails) |\n| 🤫 **Suppression** | `<!-- plainspoken-disable-next-line -->`, because a style guide has to quote its own banned list |\n| 🙈 **Never linted** | Code fences, inline code, frontmatter, URLs, link targets, HTML tags, tables, with line numbers still pointing at the original file |\n\n### 📱 pagecheck\n\n[npm](https://www.npmjs.com/package/@alokraj68/pagecheck) · [docs](./plugins/pagecheck) · [skill](./plugins/pagecheck/skills/page-audit/SKILL.md)\n\n```bash\nnode plugins/pagecheck/bin/pagecheck.mjs ./dist\nnode plugins/pagecheck/bin/pagecheck.mjs https://example.com\n```\n\nCatches horizontal overflow **and names the element causing it**, ragged line endings, text under 12px, tap targets under 44px, plus size, leading, weight, measure and contrast per text style.\n\nThree false positives had to die before its numbers meant anything:\n\n- `getClientRects()` returns one rect per inline-block box, not one per rendered line. An element holding `<b>`, an icon or per-word animation spans reports a dozen \"lines\" for one\n- Scroll animations leave every element at its own transform mid-scrub\n- Stacked block children (a title over a subtitle over a date) are separate lines by design, and read as a catastrophic gap when measured as wrapped prose\n\n### 📄 ats-resume\n\n[npm](https://www.npmjs.com/package/@alokraj68/ats-resume) · [docs](./plugins/ats-resume) · [skill](./plugins/ats-resume/skills/tailor-resume/SKILL.md)\n\n```bash\nnode plugins/ats-resume/bin/ats-resume.mjs lint resume.json\nnode plugins/ats-resume/bin/ats-resume.mjs tailor resume.json posting.txt\n```\n\nTwo passes, because they catch different things. The **source pass** reads `resume.json` and finds promotion chains in the title field, non-ISO dates, glyphs a parser chokes on. The **extraction pass** reads the text pulled out of the built PDF and finds what source inspection cannot:\n\n> Flexbox gaps do not exist in extracted text, and standalone separator elements can be dropped from a PDF's text layer entirely, leaving one unsplittable string where a parser expected four fields. It looks perfect in the DOM. Only reading the extraction finds it.\n\nTailoring filters job-description terms to what the posting **names**: a word capitalised mid-sentence is nearly always a technology, while \"heavily\" and \"expected\" never are. On a sample posting that dropped eleven noise terms and moved the reported match from 42% to 60%.\n\n### 🧭 craft-setup\n\n[docs](./plugins/craft-setup) · [skill](./plugins/craft-setup/skills/craft-setup/SKILL.md) · not on npm, no code to ship\n\nSkill only, no code. What an agent does before it says a thing is done: run the typecheck, run the linter on every file it touched, run the build once, and **name what it could not verify** instead of implying it did.\n\nDistilled from running agents across a résumé generator, an Angular ERP, a NestJS backend and several Flutter apps.\n\n## 🧪 The filter every rule had to pass\n\n**91 tests.** Every suite asserts twice — fire on input built to trip it, stay silent on input that is merely factual.\n\n| Suite | Tests | Fires on | Silent on |\n|---|---|---|---|\n| `plainspoken` | 33 | `fixtures/slop.md` | `fixtures/clean.md` |\n| `ats-resume` | 37 | `fixtures/broken.json` | `fixtures/good.json` |\n| `pagecheck` | 21 | `fixtures/broken/` | `fixtures/clean/` |\n\n```bash\nnpm test\n```\n\nThe `clean` fixtures are the important ones. If a change makes any of them produce a finding, the change is wrong until proven otherwise.\n\nThree of the tests exist purely to keep out patterns that looked reasonable and were not: a real port (\"from Java to C#\") is not a false range, a list of places (\"Australia, Europe and the US\") is not tricolon abuse, and a factual stack list is not slop.\n\n`plainspoken` also lints this repository's own prose in CI. A prose linter that cannot survive its own README is not usable.\n\n## 🖥️ Runs everywhere, checked not claimed\n\nEvery push runs the real installer on five targets: download the release, verify\nthe published SHA256, unpack it, and execute the binary.\n\n| | Verified by |\n|---|---|\n| 🪟 **Windows** x64 and ARM | `windows-latest`, install and run |\n| 🐧 **Linux** x64 and ARM (glibc) | `ubuntu-latest`, install and run |\n| 🏔️ **Alpine** and musl | `node:22-alpine`, musl detection then install and run |\n| 🍎 **macOS** Apple silicon | `macos-latest`, install and run |\n| 🍏 **macOS** Intel | `macos-13`, install and run |\n\nThat matrix exists because \"works on my Mac\" was wrong three times in a row. A\nreal Windows run found the installer reporting success while installing nothing:\nthe main-module guard compared `import.meta.url` against `'file://' +\nprocess.argv[1]`, which never matches on a drive path. Alpine found `renameSync`\nfailing with `EXDEV`, because a container's `/tmp` and `$HOME` are different\nmounts. Both are now asserted in `toolkit/test-platforms.mjs` so they cannot come\nback quietly.\n\nAlpine gets its own job for a reason: Node reports plain `linux-x64` there, so\nthe glibc build would be picked and would die at load time with an error naming\nnothing useful.\n\n## 🤖 Any agent, not just Claude Code\n\nThe CLIs are **npm packages that exit non-zero**. They need no harness at all,\nand behave the same from a terminal, from CI, or from inside an agent.\n\n```bash\nnpx @alokraj68/craftkit agents            # write AGENTS.md\nnpx @alokraj68/craftkit agents --cursor   # and .cursor/rules/craftkit.mdc\nnpx @alokraj68/craftkit agents --print    # inspect it first\n```\n\n`AGENTS.md` is the convention Codex, Cursor, opencode, Copilot, Gemini CLI and\nothers already read, so one file reaches all of them.\n\n| Harness | How it gets the gates | How it gets the judgement |\n|---|---|---|\n| **Claude Code** | `/plugin marketplace add alokraj68/craftkit` | skills, installed as plugins |\n| **Codex, opencode, Copilot** | `AGENTS.md` | same file |\n| **Cursor** | `AGENTS.md` | `.cursor/rules/craftkit.mdc` |\n| **Anything else** | `npx @alokraj68/plainspoken` | `node_modules/@alokraj68/*/skills/*/SKILL.md` |\n| **No agent at all** | the CLIs, in CI or a terminal | read the README |\n\nEvery package ships its `SKILL.md` inside the npm tarball, so an agent that only\nran `npm i` can read the reasoning without ever touching a marketplace. It will\nnot overwrite an `AGENTS.md` that craftkit did not write.\n\n## 🎒 The curated toolkit\n\n`toolkit/catalogue.json` is the whole set, grouped by what you do rather than by\nwho wrote it. `npx @alokraj68/craftkit` reads it.\n\n**Nothing third-party is vendored here.** Of the 47 skills this grew from, **26\ncarry no licence file at all**, which under copyright means the author kept every\nright. Public is not the same as redistributable. The installer clones from each\nupstream instead, so their name stays on the work and their fixes reach you.\n\nTwo details a manual copy gets wrong, and the installer does not:\n\n- A skill installs under its **declared `name:`**, not its directory name.\n  `leonxlnx/taste-skill` ships in `taste-skill` and declares\n  `design-taste-frontend`\n- **`impeccable` must run its own installer.** Its `SKILL.md` is generated from\n  `SKILL.src.md` and still holds `{{scripts_path}}` placeholders, so a plain copy\n  installs a broken skill\n\n## 🧠 How it works\n\nPlain ESM, no build step, no bundler. Each plugin is a directory under `plugins/` holding a `.claude-plugin/plugin.json`, a skill, and (for three of them) a CLI and its own `package.json`, so each publishes to npm independently.\n\nTwo design rules run through all of it:\n\n**Fixed patterns gate, heuristics advise.** A phrase either appears or it does not. A ratio is a judgement, and judgements make bad gates.\n\n**The analyzer matters more than the rules.** `plainspoken/src/analyze.mjs` decides what counts as prose, and getting it wrong produces noise no rule tuning can fix. It blanks non-prose while preserving byte offsets, treats a blank line as a sentence boundary, treats list items as their own units, and never splits on `Node.js`, `e.g.`, an initial or a decimal.\n\n`pagecheck` hands its audits to `page.evaluate()` as string expressions, which is why they live as exported template literals. The pure, testable half stays outside the browser.\n\n## 🤖 For AI coding agents\n\nEvery plugin ships a `SKILL.md` that is the agent-facing spec: the judgement a regex cannot encode, written to be read rather than parsed.\n\nEvery one also ships **inside its npm tarball**, so an agent can read it from\n`node_modules/<pkg>/skills/` without ever touching the marketplace.\n\n| Skill | Covers |\n|---|---|\n| [`plain-writing`](./plugins/plainspoken/skills/plain-writing/SKILL.md) | Why detectors flag abstraction rather than vocabulary, and the plain word to use instead |\n| [`page-audit`](./plugins/pagecheck/skills/page-audit/SKILL.md) | Reading the output, and the layout defects worth knowing before you hit them |\n| [`tailor-resume`](./plugins/ats-resume/skills/tailor-resume/SKILL.md) | The five readers, and the three honest outcomes for a missing keyword |\n| [`craft-setup`](./plugins/craft-setup/skills/craft-setup/SKILL.md) | The working agreement itself |\n\nPoint your agent at this repo, or add a line to your own `AGENTS.md` / `CLAUDE.md`:\n\n```md\nProse gates come from craftkit/plainspoken. Before claiming work is done,\nfollow craftkit/craft-setup: run the checks and name what went unverified.\n```\n\n## 🚢 Releasing\n\nOne command, all four packages:\n\n```bash\nnpm run release -- --dry-run     # what would go out, and why\nnpm run release                  # publish whatever is not on npm yet\nnpm run release -- --bump patch  # move all versions in step, then publish\n```\n\nIt runs every test suite before publishing anything, skips versions already on\nnpm, and asks for the 2FA code once rather than four times.\n\nOnce a trusted publisher is configured on npmjs.com for each package\n(`alokraj68` / `craftkit` / `publish.yml`), releasing is just `git push`:\n`.github/workflows/publish.yml` does the same work over OIDC, with provenance\nand no token anywhere in the repository.\n\n## 🗺️ Roadmap\n\n**Shipped**\n\n- [x] All four packages on npm under `@alokraj68`, published from CI over OIDC with SLSA provenance\n- [x] `npx @alokraj68/craftkit` onboarding, with upstream skills pinned to commits\n- [x] Retired the duplicated `check-mobile` and `check-type` from\n      [alokraj68.in](https://github.com/alokraj68/alokraj68.in): 329 lines deleted, replaced by `@alokraj68/pagecheck`\n\n**Next**\n\n- [ ] Retire the seven duplicated rule sets in alokraj68.in's `src/data/ats.ts`. Blocked on\n      `plainspoken` exposing its thresholds as importable config, since that repo applies\n      them at résumé strictness rather than the defaults\n- [ ] `.docx` and PDF export for `ats-resume`, or a documented handoff to an existing JSON Resume theme\n- [ ] A `--fix` mode for the mechanical half of `plainspoken`\n- [ ] More `pagecheck` viewports, and a stored baseline so a regression is visible as a diff\n- [ ] Publish `craft-setup` somewhere installable without the marketplace\n\n## 🤝 Contributing\n\nTwo rules, and they are the ones that matter:\n\n1. **A new rule ships with both halves.** It must fire on input built to trip it *and* stay silent on real known-good work. Add fixtures for each.\n2. **Never weaken a gate to make something pass.** A red check means something broke. Fix the input.\n\nBeyond that: run `npm test`, run `npm run lint:prose`, and say in the pull request what you ran and what you could not verify.\n\nEvery rule carries a comment explaining why it survived. If you add one, say what it caught and what it was tested against. A rule with no recorded reason gets deleted by the next person, or kept without anyone knowing why.\n\n## 🙏 Credits\n\n`plainspoken`'s AI-fingerprint rules build on [ARPeeketi/claude-resume-kit](https://github.com/ARPeeketi/claude-resume-kit). Seven prose patterns are distilled from the `deslop` skill in [every-app/open-seo](https://github.com/every-app/open-seo): the seven that survived the false-positive filter above.\n\nCurated third-party work belongs to its authors: [pbakaus/impeccable](https://github.com/pbakaus/impeccable), [leonxlnx/taste-skill](https://github.com/leonxlnx/taste-skill), [emilkowalski/skills](https://github.com/emilkowalski/skills), [multica-ai/andrej-karpathy-skills](https://github.com/multica-ai/andrej-karpathy-skills), [AgriciDaniel/claude-seo](https://github.com/AgriciDaniel/claude-seo), [nextlevelbuilder/ui-ux-pro-max-skill](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill), [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail), [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman), [yvgude/lean-ctx](https://github.com/yvgude/lean-ctx).\n\n### Elsewhere\n\n- 🛡️ [`eslint-plugin-typeorm-enterprise`](https://www.npmjs.com/package/eslint-plugin-typeorm-enterprise) — the same\n  principle pointed at TypeORM: block raw SQL, require transactions, guard multi-tenant\n  queries. Not part of craftkit; it fails a build the same way.\n  [docs](https://github.com/alokraj68/eslint-plugin-typeorm-enterprise)\n- 🌐 [alokraj68.in](https://alokraj68.in) — who writes these, and what they were built for.\n\n## 📄 License\n\n[MIT](./LICENSE) © [Alok Rajasukumaran](https://alokraj68.in)\n","readmeFilename":"README.md"}