@alokraj68/craftkit
v1.0.4
Published
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
Readme
🧰 craftkit
Green means it was checked. Not that nobody looked.
Four 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.
npx @alokraj68/craftkit✨ Why craftkit?
Most 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.
So 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.
| | |
|---|---|
| ✍️ plainspoken | Fails the build when prose reads as machine-written. AI phrases, vague tails, paired adjectives, tool-list endings, abstraction ratios |
| 📱 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 |
| 📄 ats-resume | Fails when an applicant tracking system cannot parse the file. Built on the JSON Resume schema, with job-description gap analysis |
| 🧭 craft-setup | The working agreement. Verify before claiming done, never commit unasked, enforce in code rather than in a checklist |
| 🎒 toolkit/ | 47 curated third-party skills, installed from upstream. Nothing vendored, nothing relicensed |
| 🪶 Zero runtime deps | plainspoken and ats-resume have none at all. pagecheck takes Playwright as an optional peer |
📚 Table of Contents
- Requirements
- Install
- The four plugins
- The filter every rule had to pass
- Runs everywhere
- Any agent, not just Claude Code
- The curated toolkit
- How it works
- For AI coding agents
- Roadmap
- Contributing
- Credits
- License
✅ Requirements
- Node
>=18, ESM only, no build step - Claude Code for the plugin and skill half. The CLIs run standalone without it
- Playwright only for
pagecheck, and only for the browser half of its tests
📦 Install
One command. It asks what you do on this machine, then installs only that.
npx @alokraj68/craftkit What will you be doing on this machine?
Pick any number of them.
1 📦 Everything
2 🎨 UI / UX and frontend design
3 ✍️ Writing, docs and READMEs
4 💻 Coding
5 📄 Résumé and job search
6 🔍 SEO and content strategy
Whatever you pick, caveman and lean-ctx are installed too.
Numbers (e.g. 2,4), or blank to cancel:It then enables the plugins by writing settings.json, clones the skills from
their own upstreams, and runs the two installers that cannot be a plain copy.
| | |
|---|---|
| 🎨 ui | frontend-design, ui-ux-pro-max, design-taste-frontend, nine Emil Kowalski motion skills, impeccable, pagecheck |
| ✍️ writing | plainspoken |
| 💻 coding | ponytail, karpathy-guidelines, craft-setup |
| 📄 resume | ats-resume, plainspoken |
| 🔍 seo | ~30 SEO skills |
| ⚙️ always | caveman, lean-ctx |
npx @alokraj68/craftkit --list # the whole catalogue, install nothing
npx @alokraj68/craftkit ui coding # skip the question
npx @alokraj68/craftkit ui --dry-run # show exactly what would happen
npx @alokraj68/craftkit --all --yes # everything, no prompts
npx @alokraj68/craftkit writing --project # write ./.claude/settings.json, not ~/Nothing runs before you have seen it. The plan lists every plugin, every
repository, and the exact text of every command, including the one that pipes a
remote script into bash. Your settings.json is backed up before it is touched.
Just the plugins
If you would rather skip the wizard:
/plugin marketplace add alokraj68/craftkit
/plugin install plainspoken@craftkit
/plugin install pagecheck@craftkit
/plugin install ats-resume@craftkit
/plugin install craft-setup@craftkitOr install a CLI on its own:
npm i -D @alokraj68/plainspoken
npm i -D @alokraj68/pagecheck playwright
npm i -D @alokraj68/ats-resume🧩 The four plugins
✍️ plainspoken
Reads Markdown and plain text, so it works on docs, READMEs, release notes, landing copy and CVs alike.
node plugins/plainspoken/bin/plainspoken.mjs docs/docs/architecture.md
error 14 ai-phrase "proven track record" has no defensible use
error 31 vague-tail trails off into a vague clause instead of landing on a result
Built the reporting layer, enabling improved efficiency
warn 22 ai-word "leverage" - try: use, apply, draw on| | |
|---|---|
| 🔴 Errors | Fixed phrases with no defensible use. "proven track record" is never correct |
| 🟡 Warnings | Ratios and rhythm. A short factual README trips the abstraction ratio, and failing a build over that is how a linter gets deleted |
| 🎚️ Presets | docs (default), resume (ratios become gates), strict (everything fails) |
| 🤫 Suppression | <!-- plainspoken-disable-next-line -->, because a style guide has to quote its own banned list |
| 🙈 Never linted | Code fences, inline code, frontmatter, URLs, link targets, HTML tags, tables, with line numbers still pointing at the original file |
📱 pagecheck
node plugins/pagecheck/bin/pagecheck.mjs ./dist
node plugins/pagecheck/bin/pagecheck.mjs https://example.comCatches 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.
Three false positives had to die before its numbers meant anything:
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- Scroll animations leave every element at its own transform mid-scrub
- 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
📄 ats-resume
node plugins/ats-resume/bin/ats-resume.mjs lint resume.json
node plugins/ats-resume/bin/ats-resume.mjs tailor resume.json posting.txtTwo 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:
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.
Tailoring 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%.
🧭 craft-setup
docs · skill · not on npm, no code to ship
Skill 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.
Distilled from running agents across a résumé generator, an Angular ERP, a NestJS backend and several Flutter apps.
🧪 The filter every rule had to pass
91 tests. Every suite asserts twice — fire on input built to trip it, stay silent on input that is merely factual.
| Suite | Tests | Fires on | Silent on |
|---|---|---|---|
| plainspoken | 33 | fixtures/slop.md | fixtures/clean.md |
| ats-resume | 37 | fixtures/broken.json | fixtures/good.json |
| pagecheck | 21 | fixtures/broken/ | fixtures/clean/ |
npm testThe clean fixtures are the important ones. If a change makes any of them produce a finding, the change is wrong until proven otherwise.
Three 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.
plainspoken also lints this repository's own prose in CI. A prose linter that cannot survive its own README is not usable.
🖥️ Runs everywhere, checked not claimed
Every push runs the real installer on five targets: download the release, verify the published SHA256, unpack it, and execute the binary.
| | Verified by |
|---|---|
| 🪟 Windows x64 and ARM | windows-latest, install and run |
| 🐧 Linux x64 and ARM (glibc) | ubuntu-latest, install and run |
| 🏔️ Alpine and musl | node:22-alpine, musl detection then install and run |
| 🍎 macOS Apple silicon | macos-latest, install and run |
| 🍏 macOS Intel | macos-13, install and run |
That matrix exists because "works on my Mac" was wrong three times in a row. A
real Windows run found the installer reporting success while installing nothing:
the main-module guard compared import.meta.url against 'file://' +
process.argv[1], which never matches on a drive path. Alpine found renameSync
failing with EXDEV, because a container's /tmp and $HOME are different
mounts. Both are now asserted in toolkit/test-platforms.mjs so they cannot come
back quietly.
Alpine gets its own job for a reason: Node reports plain linux-x64 there, so
the glibc build would be picked and would die at load time with an error naming
nothing useful.
🤖 Any agent, not just Claude Code
The CLIs are npm packages that exit non-zero. They need no harness at all, and behave the same from a terminal, from CI, or from inside an agent.
npx @alokraj68/craftkit agents # write AGENTS.md
npx @alokraj68/craftkit agents --cursor # and .cursor/rules/craftkit.mdc
npx @alokraj68/craftkit agents --print # inspect it firstAGENTS.md is the convention Codex, Cursor, opencode, Copilot, Gemini CLI and
others already read, so one file reaches all of them.
| Harness | How it gets the gates | How it gets the judgement |
|---|---|---|
| Claude Code | /plugin marketplace add alokraj68/craftkit | skills, installed as plugins |
| Codex, opencode, Copilot | AGENTS.md | same file |
| Cursor | AGENTS.md | .cursor/rules/craftkit.mdc |
| Anything else | npx @alokraj68/plainspoken | node_modules/@alokraj68/*/skills/*/SKILL.md |
| No agent at all | the CLIs, in CI or a terminal | read the README |
Every package ships its SKILL.md inside the npm tarball, so an agent that only
ran npm i can read the reasoning without ever touching a marketplace. It will
not overwrite an AGENTS.md that craftkit did not write.
🎒 The curated toolkit
toolkit/catalogue.json is the whole set, grouped by what you do rather than by
who wrote it. npx @alokraj68/craftkit reads it.
Nothing third-party is vendored here. Of the 47 skills this grew from, 26 carry no licence file at all, which under copyright means the author kept every right. Public is not the same as redistributable. The installer clones from each upstream instead, so their name stays on the work and their fixes reach you.
Two details a manual copy gets wrong, and the installer does not:
- A skill installs under its declared
name:, not its directory name.leonxlnx/taste-skillships intaste-skilland declaresdesign-taste-frontend impeccablemust run its own installer. ItsSKILL.mdis generated fromSKILL.src.mdand still holds{{scripts_path}}placeholders, so a plain copy installs a broken skill
🧠 How it works
Plain 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.
Two design rules run through all of it:
Fixed patterns gate, heuristics advise. A phrase either appears or it does not. A ratio is a judgement, and judgements make bad gates.
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.
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.
🤖 For AI coding agents
Every plugin ships a SKILL.md that is the agent-facing spec: the judgement a regex cannot encode, written to be read rather than parsed.
Every one also ships inside its npm tarball, so an agent can read it from
node_modules/<pkg>/skills/ without ever touching the marketplace.
| Skill | Covers |
|---|---|
| plain-writing | Why detectors flag abstraction rather than vocabulary, and the plain word to use instead |
| page-audit | Reading the output, and the layout defects worth knowing before you hit them |
| tailor-resume | The five readers, and the three honest outcomes for a missing keyword |
| craft-setup | The working agreement itself |
Point your agent at this repo, or add a line to your own AGENTS.md / CLAUDE.md:
Prose gates come from craftkit/plainspoken. Before claiming work is done,
follow craftkit/craft-setup: run the checks and name what went unverified.🚢 Releasing
One command, all four packages:
npm run release -- --dry-run # what would go out, and why
npm run release # publish whatever is not on npm yet
npm run release -- --bump patch # move all versions in step, then publishIt runs every test suite before publishing anything, skips versions already on npm, and asks for the 2FA code once rather than four times.
Once a trusted publisher is configured on npmjs.com for each package
(alokraj68 / craftkit / publish.yml), releasing is just git push:
.github/workflows/publish.yml does the same work over OIDC, with provenance
and no token anywhere in the repository.
🗺️ Roadmap
Shipped
- [x] All four packages on npm under
@alokraj68, published from CI over OIDC with SLSA provenance - [x]
npx @alokraj68/craftkitonboarding, with upstream skills pinned to commits - [x] Retired the duplicated
check-mobileandcheck-typefrom alokraj68.in: 329 lines deleted, replaced by@alokraj68/pagecheck
Next
- [ ] Retire the seven duplicated rule sets in alokraj68.in's
src/data/ats.ts. Blocked onplainspokenexposing its thresholds as importable config, since that repo applies them at résumé strictness rather than the defaults - [ ]
.docxand PDF export forats-resume, or a documented handoff to an existing JSON Resume theme - [ ] A
--fixmode for the mechanical half ofplainspoken - [ ] More
pagecheckviewports, and a stored baseline so a regression is visible as a diff - [ ] Publish
craft-setupsomewhere installable without the marketplace
🤝 Contributing
Two rules, and they are the ones that matter:
- 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.
- Never weaken a gate to make something pass. A red check means something broke. Fix the input.
Beyond that: run npm test, run npm run lint:prose, and say in the pull request what you ran and what you could not verify.
Every 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.
🙏 Credits
plainspoken's AI-fingerprint rules build on ARPeeketi/claude-resume-kit. Seven prose patterns are distilled from the deslop skill in every-app/open-seo: the seven that survived the false-positive filter above.
Curated third-party work belongs to its authors: pbakaus/impeccable, leonxlnx/taste-skill, emilkowalski/skills, multica-ai/andrej-karpathy-skills, AgriciDaniel/claude-seo, nextlevelbuilder/ui-ux-pro-max-skill, DietrichGebert/ponytail, JuliusBrussee/caveman, yvgude/lean-ctx.
Elsewhere
- 🛡️
eslint-plugin-typeorm-enterprise— the same principle pointed at TypeORM: block raw SQL, require transactions, guard multi-tenant queries. Not part of craftkit; it fails a build the same way. docs - 🌐 alokraj68.in — who writes these, and what they were built for.
