# README-generation templates This directory holds `@suaveplan/templates` engine templates for auto-generating `README.md` files at three levels of the `packages/` tree. | Template | Target path | Purpose | |----------|-------------|---------| | `package-readme.template.md` | `packages////README.md` | Stand-alone npm-package readme | | `plugin-readme.template.md` | `packages///README.md` | Index of packages inside one plugin | | `category-readme.template.md` | `packages//README.md` | Index of all packages in a category | ## How to render Load the template file as a string, build a context object, and pass both to `TemplateEngine` with the **loop-aware preset**: ```ts import { TemplateEngine, fullPresetWithLoops, } from "@suaveplan/templates"; import type { ParseState } from "@suaveplan/templates"; const engine = new TemplateEngine(); engine.usePreset( fullPresetWithLoops( (tpl, ctx, state) => (engine as unknown as { parseInternal: Function }).parseInternal( tpl, ctx, state ) ) ); const template = await Bun.file( ".claude/templates/package-readme.template.md" ).text(); const context = { packageName: "@suaveplan/api-plugin-vault", shortDescription: "Per-user vault HTTP plugin for `@suaveplan/api`.", summary: "Per-user vault HTTP plugin...", installCommand: "bun add @suaveplan/api-plugin-vault", quickStartCode: `import { createVaultPlugin } from "@suaveplan/api-plugin-vault";`, quickStartDescription: "After `registry.start()`, the vault plugin...", features: [ "Persists `site` records under SurrealDB...", "Enforces per-organization and per-site caps...", ], modules: [ { name: "error-codes/error-codes", path: "./src/error-codes/error-codes.md", description: "9 stable `VAULT_PLUGIN_*` codes." }, { name: "plugin/plugin", path: "./src/plugin/plugin.md", description: "`createVaultPlugin` factory." }, ], otelInstruments: [ { type: "Counter", name: "webhook_plugin.deliveries_total", labels: "{event,status,endpoint_id}" }, ], otelStatusValues: "`delivered`, `exhausted`, `not_found`", license: "MIT", }; const readme = engine.parse(template, context); ``` ## Context shapes ### `package-readme.template.md` | Key | Type | Required | Notes | |-----|------|----------|-------| | `packageName` | `string` | ✅ | Full scoped name, e.g. `@suaveplan/templates` | | `shortDescription` | `string` | ✅ | ≤120 characters; appended to H1 | | `summary` | `string` | ✅ | Multi-line paragraph(s) | | `installCommand` | `string` | ✅ | Shell command, e.g. `bun add @suaveplan/templates` | | `quickStartCode` | `string` | ✅ | Code inside the `ts` fence (no backticks) | | `quickStartDescription` | `string` | ❌ | Paragraph after the quick-start block | | `features` | `string[]` | ❌ | Renders the "What it does" section | | `modules` | `{name,path,description}[]` | ✅ | Module index bullets | | `otelInstruments` | `{type,name,labels?}[]` | ❌ | Renders the "OpenTelemetry" section | | `otelStatusValues` | `string` | ❌ | Sentence fragment after the instrument list | | `license` | `string` | ✅ | e.g. `MIT` | ### `plugin-readme.template.md` | Key | Type | Required | |-----|------|----------| | `pluginName` | `string` | ✅ | | `pluginDescription` | `string` | ✅ | | `packages` | `{name,path,description}[]` | ✅ | ### `category-readme.template.md` | Key | Type | Required | |-----|------|----------| | `categoryName` | `string` | ✅ | | `categoryDescription` | `string` | ✅ | | `packages` | `{name,path,description}[]` | ✅ | ## Brace-escaping caveat The `@suaveplan/templates` engine scans the **entire** template (including text inside code blocks) for `{identifier}` tokens. If a context string contains a literal brace pair that looks like a variable — e.g. `GET /sites/{id}/public` — the engine will try to resolve it and, when the identifier is absent from context, replace it with an empty string. When building context objects, avoid bare `{foo}` patterns. Safe work-arounds: 1. **Add a space** — `{ id }` does not match any plugin regex. 2. **Back-tick wrapping** — `` `{id}` `` is still scanned, but if the value is not in context the engine replaces it with `""`. Only use this when the loss of the braces is acceptable. 3. **Post-process** — after rendering, run a regex replace that restores any sentinels you placed in the context strings (e.g. `«LBRACE»` → `{`). Because the package-level readme is aimed at npm consumers with no knowledge of the monorepo, the generated text should already avoid monorepo-specific tags (`genesis`, migration phases, universal tiers, etc.). The AI generating the context object is responsible for stripping that content before rendering. ## Conditional nesting The `@suaveplan/templates` conditional plugin (`{if:…}…{/if}`) does not support nesting. The package template keeps all conditionals at the top level so they never wrap each other. Loop bodies may contain inner conditionals safely because the loop plugin resolves them recursively before the outer conditional runs.