This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Microdocs is a Python tool that transforms Markdown files (README.md and CHANGELOG.md) into a self-contained HTML documentation site. It converts markdown to HTML with syntax highlighting, tables of contents, and other extensions, then injects the content into an HTML template.
# Install dependencies (requires Python 3.11+)
uv sync
# Install with dev dependencies
uv sync --dev# Basic usage - convert markdown files to HTML
microdocs README.md CHANGELOG.md
# Specify output file
microdocs README.md CHANGELOG.md -o docs/index.html
# Use custom template
microdocs README.md -t custom-template.html
# Run as Python module
python -m microdocs README.md CHANGELOG.md# Run linter (Ruff with "ALL" rules enabled)
ruff check .
# Auto-fix linting issues
ruff check --fix .
# Format code
ruff format .Templates are built using Vite, which compiles HTML, CSS (Tailwind), and JavaScript into single-file outputs.
Template Structure:
- Source:
templates_src/{template_name}/(root level, not in microdocs/){template_name}.html- HTML template with Jinja2 markup{template_name}.css- Tailwind CSS source{template_name}.js- JavaScript source
- Output:
microdocs/templates/{template_name}/{template_name}.html(single file with inlined CSS/JS)
Development workflow:
# Start dev server with hot-reloading
npm run dev
# Build all templates for production
npm run build
# Preview built templates
npm run previewIMPORTANT:
- Never edit files in
microdocs/templates/directly - they are auto-generated by Vite! - Always edit source files in
templates_src/(at project root) - Run
npm run buildto compile templates after making changes - The build process automatically discovers all template directories and builds them
templates_src/is excluded from PyPI package builds (only compiled templates are distributed)
Test Organization
- Tests are located in
microdocs/tests/ - Tests are organized by module type:
test_builder.py- Low-level functions (markdown conversion, title extraction, etc.)test_cli.py- CLI interface functionalitytest_templates.py- Template rendering and integration
Test Style
- Use pytest functions, NOT TestCase classes
- Use pytest fixtures for reusable test data
- Focus on testing OUR code, not external libraries (e.g., don't test that markdown conversion works, test that our builder uses it correctly)
Running Tests
# Run all tests
pytest
# Run tests with verbose output
pytest -v
# Run tests with coverage
pytest --cov=microdocs
# Run tests across all Python versions (3.11-3.14)
./runtests.shCI/CD
.github/workflows/test.yml- Runs tests on Python 3.11, 3.12, 3.13, 3.14.github/workflows/lint.yml- Runs ruff check and ruff format --check
When creating a new release, follow these steps in order:
-
Build templates - Ensure templates are up to date
npm run build
-
Run full test suite - Verify everything passes before releasing
pytest && ruff check . && ruff format --check .
-
Update version in
pyproject.toml- Bump version number
- Update development status classifier if needed (Alpha → Beta → Production/Stable)
-
Update CHANGELOG.md
- Move "Unreleased" section to new version heading with date
- Add summary of changes (Added, Changed, Fixed, etc.)
- Include deployment instructions with new version number
-
Commit changes
git add pyproject.toml CHANGELOG.md git commit -m "Release version X.Y.Z" -
Create git tag
git tag -a vX.Y.Z -m "Release vX.Y.Z: brief description" -
Build the package
uv build
-
Publish to PyPI
uv publish
-
Push changes and tags
git push git push --tags
-
Update floating major version tag (for GitHub Action compatibility)
# For v1.x.x releases, update the v1 tag
git tag -f v1 vX.Y.Z
git push origin v1 --forceImportant Notes:
- Always run tests BEFORE building and publishing
- Never build before creating git commit and tag
- Always create git tag BEFORE building
- Update CHANGELOG with actual release date
- Include deployment instructions in CHANGELOG
- Update floating major version tag (v1, v2, etc.) after pushing tags so GitHub Actions can use
@v1for latest v1.x release
-
Entry Points (microdocs/init.py, main.py, cli.py)
- Package exposes
main()function that invokes the Typer CLI app - Registered as
microdocsCLI command in pyproject.toml - CLI accepts multiple markdown files as arguments
- Options:
--output(default: index.html),--template(custom HTML template),--repo-url,--title
- Package exposes
-
Builder (microdocs/builder.py)
- Clean, well-documented module with comprehensive docstrings
- All functions have proper type hints using modern Python syntax
- Passes all ruff linting checks
- No legacy/backward compatibility code
build_documentation(input_files, output_path, template_path, *, repo_url, title): Main build function- Accepts list of markdown files to convert
- Converts markdown to HTML using python-markdown with extensions: extra, codehilite, fenced_code, tables, toc
- Extracts title from first file using parsed TOC tokens (from toc extension) or uses provided title
- Extracts and flattens TOC for each section
- Reads HTML template (default: templates/default.html)
- Uses Jinja2 for template rendering with
title,sections,inlined_css, andrepo_urlvariables - Writes final HTML to specified output path
- Always prints progress messages to stdout
convert_markdown_to_html(md_content): Returns tuple of (html, markdown_instance)- The markdown instance provides access to parsed metadata like toc_tokens
extract_title_from_markdown_instance(md): Extracts first H1 from parsed treeflatten_toc_tokens(tokens): Recursively flattens nested TOC structure- TOC tokens from markdown are nested (children in 'children' key)
- Returns flat list with level/id/name for each heading
convert_plain_text_to_html(text_content): Converts plain text to HTML with line breaks
-
Template System
- Build Process: Templates are built using Vite (see Template Development section)
- Source Location:
microdocs/templates_src/{template_name}/{template_name}.html- Jinja2 template with embedded template tags{template_name}.css- Tailwind CSS source{template_name}.js- JavaScript (Alpine.js initialization)
- Output Location:
microdocs/templates/{template_name}/{template_name}.html- Single-file HTML with all CSS/JS inlined by Vite
- Default Template (
templates/default/default.html):- Single-page HTML template with Tailwind CSS and Alpine.js
- Uses CDN for Alpine.js 3.x and Tocbot
- Two-column layout:
- Main content area (left, flex-1)
- TOC sidebar (right, fixed 16rem width, sticky)
- Page-based navigation: sections act like pages, only one visible at a time
- Alpine.js state:
activeSectiontracks which section is displayed - Smooth transitions between sections
- Dynamic navigation with active state highlighting
- Table of Contents (TOC):
- Shows all headings (H1-H6) for current section
- Automatically indented based on heading level
- Sticky positioning (follows scroll)
- Each section has its own TOC
- Template Variables (Jinja2):
{{ title }}- Extracted from first H1 or provided via CLI{{ sections }}- List of sections withid,name,htmlattributes{{ repo_url }}- Optional repository URL{{ build_timestamp }}- Build timestamp in UTC
- Uses uv for dependency management
- Title extraction:
- Automatically extracted from first H1 heading in first markdown file
- Uses parsed TOC tokens from markdown library (not regex)
- Falls back to "Documentation" if no H1 found
- Section IDs are generated from filenames (lowercase stem) for anchor links
- Target Python 3.11+
- Uses "ALL" rules with specific exclusions for common conflicts (COM812, E501, D203, D212, etc.)
- FBT (boolean trap), FIX (TODO/FIXME), and ERA001 (commented code) rules are ignored
- Test files have relaxed rules (allow assert statements, magic values)