CacaoDocs
CacaoDocs is a lightweight Python package that effortlessly extracts API documentation directly from your code's docstrings
Install / Use
/learn @jhd3197/CacaoDocsREADME
CacaoDocs
A documentation generator for Python projects, powered by Cacao.
CacaoDocs scans your Python source code, parses docstrings, and generates an interactive documentation app with WebSocket-driven reactivity. No static HTML — your docs are a live app.
Links
Installation
pip install cacaodocs
Quick Start
# Initialize config (optional)
cacaodocs init
# Build docs from your source directory
cacaodocs build ./src -o ./docs
# Serve the generated docs
cacaodocs serve ./docs
How Docstrings Work
CacaoDocs uses Google-style docstrings with one addition: a Type: directive that tells the parser what kind of thing you're documenting. If you don't specify a type, it defaults to function.
Here's the idea — you write normal docstrings, and CacaoDocs figures out what sections to parse based on the type:
| Type | What it's for | How it's detected |
|------|--------------|-------------------|
| function | Regular functions and methods | Default — no directive needed |
| api | REST API endpoints | Auto-detected from decorators like @app.get, @router.post, @app.route |
| class | Python classes | Detected from class definitions |
| page | Markdown documentation pages | .md files in your source directory |
| config | App settings and env vars | Set with Type: config |
| event | Webhooks, signals, pub/sub | Set with Type: event |
| Custom | Anything you define | Set with Type: your_type_name |
Function (default)
The most common type. Just write standard Google-style docstrings — no Type: directive needed:
def hash_password(password: str, salt: str = None) -> str:
"""Hash a password using bcrypt.
Args:
password (str): The plaintext password.
salt (str): Optional salt. Generated if not provided.
Returns:
str: The hashed password string.
Raises:
ValueError: If password is empty or too short.
Examples:
>>> hash_password("mysecretpass")
'$2b$12$...'
"""
Available sections: Args, Returns, Raises, Examples, Notes
API Endpoints
API endpoints are auto-detected from Flask, FastAPI, and Django REST decorators — you don't need to add Type: api. CacaoDocs sees @app.get(...) and knows it's an API endpoint, extracting the HTTP method and route path for you.
@app.get("/users/{user_id}")
def get_user(user_id: int):
"""Get a user by ID.
Path Params:
user_id (int): The user's unique identifier.
Query Params:
include (str): Comma-separated fields to include.
Response (200):
id (int): The user ID.
name (str): Full name.
email (str): Email address.
Response (404):
detail (str): User not found.
"""
Auto-detected decorators:
- FastAPI:
@app.get,@app.post,@router.put,@router.delete,@router.patch - Flask:
@app.route,@blueprint.route - Django REST:
@api_view
Available sections: Path Params, Query Params, Request Body, Headers, Response (NNN)
Config
For documenting application settings and environment variables. Use Type: config to enable config-specific parsing:
def load_settings():
"""Application settings.
Type: config
Fields:
DEBUG (bool, default=False): Enable debug mode.
SECRET_KEY (str, required, env=APP_SECRET): Secret key for signing.
DATABASE_URL (str, required, env=DATABASE_URL): PostgreSQL connection string.
PORT (int, default=8000): Server port.
"""
Each field supports modifiers inside the parentheses:
- type —
str,int,bool, etc. default=value— Default valuerequired— Marks the field as requiredenv=VAR_NAME— Maps to an environment variable
Event
For documenting webhooks, signals, and event-driven patterns. Use Type: event:
def on_user_signup(data: dict):
"""User signup event.
Type: event
Trigger: When a new user completes registration.
Payload:
user_id (int): The new user ID.
email (str): The user's email.
plan (str): Selected subscription plan.
"""
Available sections: Trigger (inline directive), Payload
Custom Types
You can define your own doc types in cacao.yaml. Each custom type gets its own sections and display settings:
doc_types:
cli_command:
label: "CLI Command"
icon: "terminal"
sections:
- name: "Usage"
format: code
- name: "Options"
format: args
- name: "Flags"
format: args
database_model:
label: "Model"
icon: "database"
sections:
- name: "Fields"
format: args
- name: "Indexes"
- name: "Relations"
Then use them with the Type: directive:
def deploy():
"""Deploy the application.
Type: cli_command
Usage:
deploy --env production --tag v1.2.3
Options:
env (str): Target environment.
tag (str): Version tag to deploy.
"""
Configuration
Create a cacao.yaml in your project root:
title: "My Project"
description: "API Documentation"
version: "1.0.0"
theme: "dark"
github_url: "https://github.com/username/repo"
exclude_patterns:
- "__pycache__"
- ".venv"
- "node_modules"
Deploy to GitHub Pages
CacaoDocs can export a static version of your docs and deploy them to GitHub Pages. Add this workflow to .github/workflows/docs.yml:
name: Deploy Docs to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: true
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install cacaodocs
pip install "cacao>=2.1.0"
- name: Build docs
run: cacaodocs build ./src -o ./_build
- name: Export static site
run: cacaodocs export ./_build -o ./dist --base-path /${{ github.event.repository.name }}
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: dist
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4
Setup steps:
- Go to your repo's Settings > Pages
- Set Source to GitHub Actions
- Push the workflow file to
main— it will build and deploy automatically
Note: Change
./srcin the build step to wherever your Python source code lives. The--base-pathflag is needed so links work correctly underhttps://username.github.io/repo-name/.
The @doc() Decorator
Instead of (or in addition to) docstrings, you can use the @doc() decorator to define documentation as structured data. This avoids fragile docstring parsing entirely — CacaoDocs reads the keyword arguments directly from the AST.
from cacaodocs import doc
@doc(
description="Fetch a user by ID.",
args={"user_id": {"type": "int", "description": "The user's unique identifier"}},
returns={"type": "User", "description": "The matching user"},
raises={"NotFoundError": "If user doesn't exist"},
deprecated="2.0",
category="Users",
version="1.0",
)
def get_user(user_id: int) -> User:
...
The decorator is a runtime no-op — it just returns your function unchanged. Zero overhead. CacaoDocs reads the keyword arguments at scan time via AST, so there's nothing to parse or misparse.
Decorator vs Docstring
You can use either approach, or both. When both exist, decorator values win.
# Decorator only — no docstring needed
@doc(description="Add two numbers.", args={"a": "First", "b": "Second"}, returns="The sum")
def add(a, b):
return a + b
# Supplement mode — docstring provides the basics, decorator adds metadata
@doc(category="Utils", version="3.0", deprecated=True)
def helper():
"""Reticulate the splines.
Args:
count (int): Number of splines.
"""
...
Supported kwargs
General:
| Kwarg | Type | Description |
|-------|------|-------------|
| description | str | Summary text |
| doc_type | str | Override type: "api", "config", "event", etc. |
| deprecated | bool \| str | True or a since-version string like "2.0" |
| category | str | Sidebar group name |
| version | str | Version when added |
| hidden | bool | Exclude from generated docs |
Function sections:
| Kwarg | Simple syntax | Full syntax |
|-------|--------------|-------------|
| args | {"name": "desc"} | {"name": {"type": "str", "description": "...", "default": "x"}} |
| returns | "description" | {"type": "User", "description": "..."} |
| raises | {"ValueError": "when bad"} | — |
| examples | ["example()"] | — |
| notes | ["Note text"] | — |
| attributes | Same as args | Same as args |
API sections:
| Kwarg | Type | Description |
|-------|------|-------------|
| method | str | HTTP method ("GET", "POST", etc.) |
| path | str | Route path ("/users/{id}") |
| path_params | dict | Same format as args |
| query_params | dict | Same format as args |
| request_body | dict | Same format as args |
| responses | dict | {200: "OK"} or {200: {"description": "...", "fields": {...}}} |
| headers | dict | {"Auth": "desc"} or {"Auth": {"description": "...", "required": True}} |
Event sections:
| Kwarg | Type | Description | |-------|------|--------
Related Skills
gh-issues
326.5kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
node-connect
326.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
openai-image-gen
326.5kBatch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
oracle
326.5kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
