diff --git a/.claude/skills/write-chapter/SKILL.md b/.claude/skills/write-chapter/SKILL.md index 40b5f97..210657a 100644 --- a/.claude/skills/write-chapter/SKILL.md +++ b/.claude/skills/write-chapter/SKILL.md @@ -98,7 +98,8 @@ Re-read each file with adversarial eyes and fix every instance of: - A violation of the Appendix B conventions. - Anything that would fail under `bun run` (syntax, type, import errors, missing await). - Placeholders, TODOs, or incomplete logic. -- Non-ASCII punctuation. +- Non-ASCII punctuation outside a fenced diagram (prose and code stay ASCII; box-drawing and arrows are fine inside a ``` diagram). +- A diagram whose connectors do not line up under the node they descend from, or a vertical with no arrowhead - render the page and eyeball the diagram, never trust the raw source. - Golfed/compressed code: any line that stacks multiple statements, sequences side effects with the comma operator, or inlines a multi-step expression to save a line. Re-expand to one statement per line (a multi-line `async function` over a dense one-line arrow), even if that grows the file - up to the 100-line hard cap. A correct-but-dense one-liner is a defect here, not a pass. For cutoff-sensitive APIs (extended thinking, citations source schema, fine-tuning), verify the exact shape against current Anthropic docs; if you cannot verify, list the file under Review flags in the PR rather than guess. @@ -114,7 +115,7 @@ For cutoff-sensitive APIs (extended thinking, citations source schema, fine-tuni - Auth and runtime env vars are introduced and explained once, in Chapter 1: `ANTHROPIC_API_KEY` (sent as `x-api-key`, Anthropic direct), `ANTHROPIC_AUTH_TOKEN` (sent as `Authorization: Bearer`, used by some compatible providers), and `ANTHROPIC_BASE_URL` (which endpoint to call). Later chapters assume them; only mention an env var a sample actually uses. - TypeScript style: prefer `type` over `interface`; never use `unknown` or index signatures; reuse SDK-exported types (`Anthropic.MessageParam`, `Anthropic.Tool`, `Anthropic.ToolUseBlock`, etc.). - Loop idioms: for an unbounded produce-then-consume loop (long-polling an API, draining an event stream), prefer an async generator - `async function* poll()` that `yield`s, consumed with `for await (const x of poll())` - which separates transport from handling and matches the `for await...of` style used elsewhere. Where a generator does not fit, use `while (true)`. Never use `for (;;)`. -- ASCII punctuation only: `-`, `->`, `...`. No em dashes, no smart quotes. (This governs punctuation; emoji are allowed in chapter prose per the visual-aids rule, but code and example files stay ASCII-only.) +- ASCII punctuation in prose and code: `-`, `->`, `...`. No em dashes, no smart quotes. (This governs punctuation; emoji are allowed in chapter prose per the visual-aids rule, but code and example files stay ASCII-only.) The one exception: inside a fenced diagram (a ``` block) you MAY use Unicode box-drawing and arrow characters for a cleaner picture - the commit hook permits non-ASCII inside fences, while everything outside a fence stays ASCII. - Each example is standalone and runnable on its own. Begin each file with a short header comment giving the run command (for example: `// bun run examples/05-tools/define-tool.ts`). - Chapters are rendered by VitePress and published to GitHub Pages. In chapter prose, show a sample's full source with a VitePress snippet import (`<<< @/examples/NN-slug/file.ts`) on its own line, NOT by pasting the code into a fenced block - this keeps the rendered docs in lockstep with the runnable file. Inline fenced blocks are only for short illustrative fragments. The runnable file under `examples/` is the single source of truth; prose must not contradict it. After editing chapters, the site builds with `bun x vitepress@2.0.0-alpha.17 build`. - Do NOT add Markdown links to chapters or pages that do not exist yet (for example a "next chapter" pointer like `[Chapter 2](./02-streaming.md)`). VitePress fails the build on dead links - refer to a not-yet-written chapter as plain text, and only turn it into a link once that page exists. @@ -127,7 +128,7 @@ For cutoff-sensitive APIs (extended thinking, citations source schema, fine-tuni - One-home rule: teach each fact once - in the prose OR a code comment, never both (example comments render inline via the snippet import, so a duplicated explanation shows up twice on the same page). - Teach only what this chapter reaches: enum/option lists (for example `stop_reason` values) include only values a sample exercises, plus one short deferral clause for the rest. - Going-deeper asides: secondary material (extra providers, full configs, full taxonomies) goes in a `::: details` block (or a `::: tip`/`::: info` callout), never a main-line H2. The main line must read complete if every aside is collapsed. -- Visual aids, used sparingly (seasoning, not structure): VitePress callout containers (`::: tip`, `::: info`, `::: warning`, `::: details`) for asides; AT MOST one small ASCII diagram per chapter, and only where a picture genuinely beats a sentence; a small Markdown table when comparing a short list of options (for example env vars or model tiers). +- Visual aids, used sparingly (seasoning, not structure): VitePress callout containers (`::: tip`, `::: info`, `::: warning`, `::: details`) for asides; AT MOST one small diagram per chapter, only where a picture genuinely beats a sentence - draw it with Unicode box-drawing inside a ``` fence (cleaner than ASCII `|`/`v`/`->` art, which is also fine), make the connectors line up under the node they descend from, give every descending line an arrowhead, and render the page to eyeball it; a small Markdown table when comparing a short list of options (for example env vars or model tiers). - Config lives in the repo, not the prose: no `package.json`/`tsconfig.json` JSON dumps in a chapter - one sentence plus the run command, and note the repo already ships the scaffold so a follow-along reader can just run the file. - Example code budget: keep each sample focused and single-concept; verbose, explicit code is welcome - favor clarity over brevity. Aim for <=70 lines (HARD CAP 100, `wc -l`) with comment:code ratio <=0.40 (a comment line's first token is `//` or `#`; an end-of-line comment counts as code). The header comment is the run command and nothing else. No numbered `// 1) ... // 2) ...` blocks over `console.log` groups, and no reference tables inside code files. - Readability outranks the line count - never golf a sample to hit the budget. One statement per line: do NOT join multiple statements with `;` on one line, do NOT use the comma operator to sequence side effects (`(last = now), edit(...)`), and do NOT inline a multi-step expression (for example `(await fetch(...)).json()` with method/headers/body options) purely to save a line. A normal multi-line `async function` helper beats a dense one-line arrow. The standalone-file rule means each Telegram/`fetch` sample re-pastes its own helper, and verbose, explicit style is encouraged - that is exactly why the budget is generous (up to 100 lines) for samples that need it. If a sample still cannot fit while staying readable, cut its scope (or, when writing the issue, split it into two samples) - compression is never the answer.