| name | accelint-api-docs |
| description | Generate and maintain TypeScript/React API reference documentation in markdown. TRIGGER when user mentions documenting code, API docs, "add docs for X", updating/validating docs, or working with fumadocs/Storybook. Handles all API reference documentation for functions, components, hooks, classes, and constants. If TypeScript/React code needs documentation, use this skill. |
| compatibility | {"required_permissions":[{"Read":"**/.claude/skills/accelint-api-docs/references/*.md"},{"Write":"apps/docs/content/ (or custom outputDir)"},{"Bash":"git hash-object (for SHA tracking, optional)"}],"graceful_degradation":["Without Bash: skips source_sha/doc_sha fields, uses file mtimes","Without Read: cannot load reference examples, structure may vary"],"parameters":[{"outputDir":"Output directory (default: apps/docs/content)"}]} |
API Documentation Generation
Generate and maintain comprehensive markdown API documentation for TypeScript/React code. You are a drafting assistant helping engineers create consistent, maintainable API reference documentation.
Contents
Core Workflows:
Guidance:
Advanced Topics:
Philosophy & Role
Engineers maintain the documentation. You assist.
Your role:
- Draft initial content from source code, JSDoc, and tests
- Suggest updates when code changes
- Validate quality (links, structure, freshness)
All generated content is editable markdown. Engineers can freely customize—you adapt to their patterns rather than enforcing rigid templates.
When to Ask for Confirmation
Always prompt:
- Multi-export files: "Document: [All] [EntityName only] [Custom selection]"
- Existing docs found: "[U]se as reference [I]gnore"
- Update will affect manual edits: Show diff, "[A]pply [S]kip [E]dit"
Proceed directly:
- Single export, no existing docs: Generate and write
- Validation without --fix: Report findings only
- Entity detection with high confidence: Generate after brief confirmation
How Reference Examples Work
Reference examples over templates. This skill uses 6 gold-standard examples showing both structure AND writing style:
references/example-function.md - Curried functions with generics
references/example-component.md - React components with multi-part patterns
references/example-hook.md - Type-safe hooks with generics
references/example-class.md - Classes with singleton patterns
references/example-constant.md - Frozen object patterns (SafeEnum)
references/example-barrel-export.md - Barrel export landing pages (lightweight navigation)
How to Use Reference Examples
Match these aspects:
- Section structure: ## Usage → ## Reference → ## Examples → ## Related
- Voice and tone: direct, imperative, no preamble
- Code-first approach: show usage before explaining
- Body starts with ## (H2), never # (H1) - frontmatter title/description provide the H1
Adapt these aspects:
- Depth based on API complexity
- Number of examples based on use cases
- Level of detail in reference section
CRITICAL: Reference examples have been updated to remove duplicate H1/description from the body. All reference files now start directly with ## Usage (or ## Installation for barrel exports). The frontmatter title and description fields are the single source of truth - they are rendered by the docs framework as the page H1 and intro text. Never add an H1 or duplicate description in the body.
Pattern match from these examples—they demonstrate the target quality level.
Generate Documentation
When the user asks to document a file, follow this workflow.
Parameters
outputDir (optional): Directory to write generated docs. Default: apps/docs/content
- If provided as argument or from context, use it; otherwise use default
Step-by-Step Process
1. Read and analyze the source
- Read the source file completely
- Read any colocated test files (
*.test.ts, *.test.tsx) for usage examples
- Exclude test files and directories from documentation output:
- Skip
*.test.ts, *.test.tsx files
- Skip
__tests__/, __mocks__/ directories
- Read existing documentation if present (
.md, .docs.mdx, README.md)
2. Detect package section
- Extract package name from source path (e.g.,
packages/logger/ → logger)
- Map to section using these rules:
design-toolkit, map-toolkit → toolkits/
postcss-tailwind-css-modules, biome-config, eslint-config, prettier-config, smeegl, typescript-config, vitest-config → tooling/
- All other packages (including
design-foundation) → packages/
- Strip
@accelint/ scope if present (e.g., @accelint/logger → logger)
3. Check for existing documentation locations (CRITICAL)
- BEFORE computing output paths, check if documentation already exists in a different location
- Read
apps/docs/.index.json and search for entries matching the source file
- If found, use the EXISTING doc path from the index, do NOT create a new path
- Common scenario: Documentation may exist in
apps/docs/content/docs/{section}/ rather than apps/docs/content/{section}/
- Why this matters: Fumadocs may have a
docs/ subdirectory convention that you must respect
- Steps:
- Read
apps/docs/.index.json
- Find entry where
source matches your target source file
- If found: Use the
doc path from that entry (this is the correct location)
- If not found: Check filesystem for existing docs:
- Try
apps/docs/content/docs/{section}/{package-name}/ first
- Then try
apps/docs/content/{section}/{package-name}/
- Use whichever exists, or default to what
.index.json uses for other files in same section
- List existing files in the chosen directory to understand the structure
- Never create a parallel documentation tree in a different location if docs already exist
- Example mistake to avoid:
- ❌ Creating
apps/docs/content/tooling/vitest-config/ when docs exist at apps/docs/content/docs/tooling/vitest-config/
- ✅ Check
.index.json, see existing entries use apps/docs/content/docs/tooling/, use that path
4. Detect barrel export vs composed API
- Barrel export: File only contains re-export statements (
export { X } from './path')
- Composed API: File contains actual implementation (classes, functions, orchestration)
- For root
index.ts files:
- If barrel export → generate lightweight landing page (see Barrel Export Detection)
- If composed API → generate comprehensive documentation (see Common Patterns)
- Examples:
- Barrel:
packages/constants/src/index.ts (just re-exports from sub-modules)
- Composed:
packages/bus/src/index.ts (exports Broadcast class with orchestration)
5. Classify exports
- Identify all exported entities
- Classify each: Function, Component, Hook, Class, Constant
- Skip internal exports (prefixed with
_, marked @internal, in /internal/ directories)
- For multi-export files, ask: "Document: [All] [EntityName only] [Custom selection]"
6. Load matching reference example
- Function → read
references/example-function.md
- Component → read
references/example-component.md
- Hook → read
references/example-hook.md
- Class → read
references/example-class.md
- Constant → read
references/example-constant.md
- Barrel export → read
references/example-barrel-export.md
7. Generate markdown content
- Follow the reference example structure exactly
- Extract information from source (don't infer or hallucinate)
- Use direct imperative voice ("Returns the filtered array")
- Name examples by use case ("Example: Filtering null values")
- Keep prose concise—show code first, explain after
8. Compute source_sha before generating content
- Run
git hash-object <source-file> to get the current source file hash
- Store this value to use in frontmatter
9. Generate markdown content with frontmatter
- Follow the reference example structure exactly
- Extract information from source (don't infer or hallucinate)
- Use direct imperative voice ("Returns the filtered array")
- Name examples by use case ("Example: Filtering null values")
- Keep prose concise—show code first, explain after
- Add frontmatter at the top:
---
title: "<entity-name or descriptive-title>"
description: One sentence describing what it does
source: relative/path/to/source.ts
source_sha: <value from step 7>
doc_sha: pending
deprecated: false
updated: YYYY-MM-DD
---
- Title Convention: The title field MUST use export names, NOT deep import paths:
- For package index.mdx files (
packages/X/src/index.ts): Use full package name
- Example:
"@accelint/predicates", "@accelint/temporal", "@accelint/core"
- For sub-page files (any other file): Use the primary export name(s) from the source file
- Single export: Use the export name exactly as it appears in code
export const isIn = ... → "isIn"
export function Button() { ... } → "Button"
export class Broadcast { ... } → "Broadcast"
- Multiple related exports: Use EITHER a descriptive group name OR list primary exports
- Multiple utility functions → Descriptive category:
"Array Utilities", "Timers", "Color Constants"
- Complementary pair → List both:
"isIn & isNotIn", "Radio & RadioGroup"
- Multiple hooks → Group name:
"React Hooks", "Worker Utilities"
- Never include slashes (/) in sub-page titles — titles should match what developers type in code, not import paths
- Examples (CORRECT ✅):
packages/predicates/src/index.ts → "@accelint/predicates" (package index)
packages/predicates/src/is-in/index.ts → "isIn" (single export)
packages/bus/src/react/index.ts → "React Hooks" (multiple hooks: useBus, useEmit, useOn)
packages/temporal/src/timers/index.ts → "Timers" (multiple related: setClockInterval, setClockTimeout)
toolkits/design-toolkit/src/button/index.tsx → "Button" (single component)
toolkits/design-toolkit/src/radio/index.tsx → "Radio & RadioGroup" (complementary components)
- Examples (INCORRECT ❌ — DO NOT USE):
- ❌
"@accelint/predicates/is-in" — Never use deep paths for sub-pages
- ❌
"@accelint/temporal/timers" — Never use deep paths for sub-pages
- ❌
"@accelint/core/array/map" — Never use deep paths for sub-pages
- Why this matters: Users import by export name (
import { isIn } from '@accelint/predicates'), not by path. Titles should match what developers type in code. Deep paths suggest incorrect import patterns and create confusing documentation structure.
- Set
deprecated: true if source has @deprecated JSDoc tag
- Set
doc_sha: pending as a placeholder (will be computed after writing)
10. Validate markdown quality
- Body should start with H2 (##), NOT H1 (#) - frontmatter title becomes the page H1
- Do not include duplicate description paragraph after frontmatter - frontmatter description is rendered in page header
- Add language tags to code fences
- Convert bare URLs to markdown links
- Check that examples have descriptive names
11. Write file and compute doc_sha
12. Update or create meta.json for parent directory
- CRITICAL: Fumadocs requires explicit
meta.json files to include flat .mdx files in navigation
- After writing the documentation file, check the parent directory for a
meta.json file
- Get parent directory:
dirname <output-file>
- List all items (folders and flat .mdx files) in parent directory:
find <parent-dir> -maxdepth 1 -type d ! -name '.' ! -name '..' -exec basename {} \;
find <parent-dir> -maxdepth 1 -name '*.mdx' -type f -exec basename {} .mdx \;
- Sort items alphabetically
- Check if
meta.json exists in parent directory:
- If exists: Read it, verify all items are in
pages array, add missing items alphabetically
- If not exists: Create new
meta.json with all items in alphabetical order
- Format:
{
"title": "<Section Title>",
"pages": [
"item1",
"item2",
"flat-file",
"item3"
]
}
- Title mapping:
packages/ → "Packages"
toolkits/ → "Toolkits"
tooling/ → "Tooling"
- Nested folders: Use capitalized folder name
- Important: Without this step, flat
.mdx files won't appear in sidebar navigation
13. Update tracking index
13. Update tracking index