Agent skills
Ten agent skills ship inside the crust binary — skills list to see them, skills install to write them into .agents/skills/ (linked into .claude/skills/ for Claude Code), grammar-lint-tested so they can't rot.
Goal: teach a coding agent to drive crust well — pipelines, test suites, mocks, load runs, process supervision — without pasting docs into every prompt.
Crust ships agent skills: SKILL.md guides in the format coding agents pick
up out of a project directory. They install into .agents/skills/ — the
cross-client location Codex, Cursor and OpenCode read — with a per-skill link at
.claude/skills/<name> for Claude Code, the one mainstream host that hasn’t
adopted the standard path. The guides are embedded in the crust binary itself, so
the skills you install always match the binary you’re running — no version skew
between “what the agent was taught” and “what the shell actually parses”.
See what’s embedded
skills list
crust-api-testing
Test HTTP APIs with crust — .pipes suites (one fixture pipeline per line, request chaining via capture, inline SQL verification), .crust.ts fixtures with setup/matchers, and gen-fixtures which derives negative-case matrices and CRUD flow suites from an OpenAPI spec. Use for API integration tests, contract tests from a spec, auth/authz negative cases, or DB-verified endpoint tests.
crust-builtins
crust has two separate namespaces — tool builtins (`mock-server`, `test-fixture`, `test-pipes`, `gen-fixtures`, `verify-web-links`, `logs`, `dotenv`, `skills`) that need a line of their own, and registered functions (`base64`, `salt`, `jwt`, `bundle`, `sql`, `wait`) that are space-separated stages usable as a source or mid-pipeline. Explains what the upstream item means to each one, why `bundle(5)` is a shell syntax error, and how to reach crypto/FS from a lambda. Use when a crust stage exits 2 with `syntax error near unexpected token`, when a mid-pipeline function eats the wrong argument, or when a lambda says `salt is not defined`.
crust-cli
How to invoke crust and read its answer — the run modes (`-c`, script file, piped stdin, REPL, tool subcommands like `crust skills install`), what each exit code actually means (0/1/2/127/130, and why there is no 124), `--check` as a linter including what it cannot catch, `--env-file` vs `dotenv` vs `export`, the REPL's verified keybindings and Ctrl-C semantics, and where crust's globals (`GET`, `range`, `parallel`, `crust.fn`) do and do not exist. Use when a crust run's exit code is confusing, when a CI step passes on a failing line, when `--check` says ok but the line dies, when `GET is not defined` appears in a `.ts` file, or when driving the REPL from a script.
crust-load-testing
Load-test and soak-test HTTP services with crust — the load rate source, parallel workers, timed verbs, stats windows, CI threshold gates via assert, and baseline comparison with stats --out. Use for smoke-load, latency percentiles, rps checks, performance regression gates in CI, or "is this endpoint fast/degrading" questions.
crust-logs
Search a live log stream with crust's `logs` session — it holds a tail/procs/shell source open, keeps a ring buffer, and re-runs every typed pipeline fragment over the buffered past and then the live stream; `json on` parses NDJSON at query time, `search` counts the buffer instantly, `buffer N` resizes without restarting. Use when tailing dev services or containers, when a grep workflow keeps losing history, or when you want to widen a filter over logs you already saw.
crust-mcp
Drive crust directly from an MCP-capable agent (OpenCode, Claude Code, Codex, Cursor) instead of a shell — `crust mcp` exposes every capability as a first-class tool: run_line, check_line, test_fixture/test_pipes, gen_fixtures, load_run, verify_web_links, plus lifecycle mock servers, supervised procs, and buffered log sessions that stay open across calls. Use when configuring crust as an MCP server, choosing which crust_* tool fits a task, or reasoning about what persists between tool calls and what does not.
crust-mock-server
Mock an API from an OpenAPI spec with crust mock-server — example-first responses, stateful CRUD (in-memory or persisted to sqlite/postgres with --state, seedable with --seed), request validation with 422s, and validation-proxy mode that checks a REAL API's spec conformance. Use for mocking backends, frontend dev without a server, contract/conformance testing, or checking whether an API matches its openapi.json.
crust-pipelines
Compose crust pipelines — sources (range, glob, read, tail, GET, load, procs, sql), transforms (TS lambdas, filter, HTTP verbs, parallel), assertions (expect, assert), and request chaining with capture. Use when writing or debugging crust one-liners, `crust -c` scripts, .crust script files, or .pipes lines that mix HTTP, SQL, and processes.
crust-procs
Run and supervise dev processes with crust — procs() merges multiple long-lived commands into one pipeable stream with per-proc env, restart backoff, readiness probes (ready:), dependency ordering (after:), and process-group teardown; wait blocks until a port/URL is up. Use for dev runners ("start db, api, web in order"), readiness gating in CI, tailing multiple services, or mining merged process logs.
crust-verify-web-links
Crawl a site from its sitemap and verify every link, #anchor, redirect chain, OG image and meta tag against .crust.ts fixtures. `--base-url` auto-discovers the sitemap (robots.txt → /sitemap.xml → /sitemap-index.xml), `--site-map-url` takes a local sitemap so you can check build output, `--fixtures` diffs meta. Use when link or SEO health must gate a deploy, when a built site should be checked before publishing, or when OG/meta regressions need catching.
The ten skills
All ten have a page: usage directions, worked examples, and the reasoning
behind them. skills install --select <name> writes that skill into
./.agents/skills/ (and links it for Claude Code); the pages are for the human
deciding which one that should be.
| Skill | Teaches the agent to… | Leans on |
|---|---|---|
| crust-pipelines | Write and debug pipeline lines: pick the right source, compose lambdas/verbs/parallel, chain requests with capture, know where $VAR expands. The foundation the rest assume. | Quickstart |
| crust-api-testing | Build .pipes suites with capture chaining and SQL cross-checks, write .crust.ts fixtures, and derive negative matrices + CRUD flows from an OpenAPI spec. | API smoke tests, gen-fixtures |
| crust-load-testing | Shape load scenarios and ramps, size parallel pools, read drop reports, and wire stats/assert threshold gates with baselines into CI. | Stress testing, CI load gates |
| crust-mock-server | Boot spec mocks, use stateful CRUD for round-trip flows, interpret --validate 422s, and run conformance audits with --proxy. | Mock server |
| crust-procs | Orchestrate processes with ready:/after:/restart:, tail merged logs, and gate CI on wait. | One dev tail |
| crust-cli | Drive crust from CI and scripts: which run mode takes which argument, what each exit code actually means (0 · 1 · 2 · the stage’s own · 127 · 130, and why there is no 124), what --check validates without executing and what it cannot see, env files vs dotenv, and the REPL’s real keybindings. | CI load gates, Quickstart |
| crust-builtins | Tell the two namespaces apart — tool builtins that need a line of their own vs registered functions used as stages — and get fn(item, ...args) right: what the item means per function, why bundle(5) is a shell syntax error, why a lambda says salt is not defined, and how to reach crypto and FS from one. | Quickstart |
| crust-logs | Run the logs session: one held source behind a ring buffer, every typed fragment run over the buffered past and then live (so side effects fire twice), json on for NDJSON and the silent zero it prevents, search and buffer N, and which item type each source yields. | Log mining, One dev tail |
| crust-verify-web-links | Crawl a sitemap and check links, #anchors, redirect chains and OG images, plus meta against .meta.crust.ts fixtures: sitemap auto-discovery, --site-map-url against local build output, and the three ways a green run means nothing was checked. | Verify web links |
| crust-mcp | Drive crust over the Model Context Protocol: one-shot tools that run a fresh child per call (cwd/env never persist) vs lifecycle tools that hold a mock, a procs runner or a logs session open across calls; validate with check_line before spending a run, and read isError results — verbatim output, explicit zeros — as evidence. | MCP server |
Install
crust skills install # on a terminal: pick which ones, into ./.agents/skills
crust skills install --all # everything, no menu
crust skills install --select crust-cli,crust-logs
crust skills install --global # target ~/.agents/skills instead of ./.agents/
✔ installed 10, up-to-date 0 → /app/.agents/skills
linked 10 into /app/.claude/skills for Claude Code
Each skill is written once. .agents/skills/<name>/ holds the real file and
.claude/skills/<name> is a relative link to it
(../../.agents/skills/<name>). One file means one edit: change it in either
path and every agent reads the same text.
| Who reads what | |
|---|---|
| Codex | .agents/skills/ only |
| Cursor, OpenCode | .agents/skills/ plus their own vendor directory |
| Claude Code | .claude/skills/ — hence the links |
Links are per-skill on purpose: Codex keeps its own built-ins under
.agents/skills/.system, and a directory-level link would hide whatever a host
stores there.
Nothing of yours is removed on the way. A real .claude/skills/<name> directory
crust did not write is left alone and named on stderr — --force is what
consents to replacing it with a link — a link pointing somewhere else is left
alone even then, and a system that cannot symlink falls back to a copy. None of
it can fail the install: the real file under .agents/skills/ is written first.
On crust 0.2.4 and earlier the real files went into .claude/skills/ and
nowhere else, so Codex, Cursor and OpenCode found no skills at all. After
updating, crust skills install writes them to .agents/skills/; the old
crust-* directories under .claude/skills/ are not crust’s, so it reports them
and leaves them be. Delete them and re-run with --force to turn each into a
link.
On a terminal, install is a menu rather than ten files appearing: one row
per skill, its status in the directory you are about to write to — not installed, current, EDITED locally — pre-checked to everything not already
current. Arrows or j/k move, space toggles, a toggles all, g switches
between the project and ~/.agents/skills (recomputing every status, because a
skill current in your project may be missing from your home), f allows
overwriting your own edits, enter installs, q leaves everything alone.
Cancel is exit 0: declining is not a failure. A menu that would write a skill
also says it links into .claude/skills.
Piped or non-interactive output has no menu and installs everything it is
told to — --all for the same result explicitly, --select a,b for a subset,
and an unknown name exits 2 listing the valid ones. crust skills install --help documents the flags.
When crust comes from npm, npm install asks once whether to install the
skills. It never asks on CI, with piped output, for a global install, when crust
is somebody’s dependency, or once crust skills are already in the project —
under either path, so an install from before the layout change is not a second
question — and it can never fail the install. CRUST_NO_SKILLS=1 stops the
question for good.
Project-level install is the default and usually the right call: the skills land
next to your code, get committed, and every agent (and teammate’s agent) working
in the repo picks them up. --global suits a machine where you use crust
everywhere but don’t want to touch each repo.
The install is idempotent — run it again and unchanged files are left alone, links included:
✔ 10 skills already current → /app/.agents/skills
And it’s respectful of your edits. If you’ve customized an installed skill locally, a plain reinstall refuses to clobber it and exits 1:
skills: 1 file(s) differ from the embedded version — pass --force to overwrite:
/app/.agents/skills/crust-pipelines/SKILL.md
skills install --force overwrites with the embedded version. Exit codes: 0 ok
(including “cancelled — nothing written”), 1 refused overwrites, 2 bad args.
Typical upgrade flow — after updating crust, refresh the skills so they describe the binary you now have:
crust skills install --all # picks up new/changed skills; exits 1 if you have local edits
git diff .agents/skills # review what the new crust version taught differently
How the grammar lint keeps them honest
An agent skill is only useful if its examples actually run — a skill that demonstrates syntax the shell rejects is worse than no skill, because the agent will confidently reproduce the broken form. Crust enforces this in its own test suite:
- Every skill’s fenced
```crustexample blocks are extracted at test time. - Every line is tokenized and classified against the live shell grammar — the same lexer the binary uses at the prompt. A line that fails to classify fails the build.
- Lines whose head is a pipeline keyword (
capture,expect,stats,load,read,assert,GET/POST/…,range(…)) additionally assert they classify as that stage kind and not as a fall-through shell command — the exact failure mode of a stale example after a grammar change.
So when the grammar evolves, the test suite turns every outdated skill example into a red test in the same commit. The skills can’t silently rot: what the agent learns is checked against what the shell parses, on every bun test.
Related
- Quickstart — the human-readable version of what the skills teach.
- Recipes — the workflows the skills point agents at.
- Pipe shorthand vs TypeScript — which surface a skill’s examples are written against.