{"id":26946182,"url":"https://github.com/jhd3197/cacaodocs","last_synced_at":"2026-03-07T12:01:15.483Z","repository":{"id":270678573,"uuid":"910047423","full_name":"jhd3197/CacaoDocs","owner":"jhd3197","description":"CacaoDocs is a lightweight Python package that effortlessly extracts API documentation directly from your code's docstrings","archived":false,"fork":false,"pushed_at":"2026-03-05T07:12:17.000Z","size":12100,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-05T11:42:38.556Z","etag":null,"topics":["api","api-documentation","docs","docstring","docstrings","documentation","documentation-generator","documentation-tool","er-diagram","flexsearch","python"],"latest_commit_sha":null,"homepage":"https://jhd3197.github.io/CacaoDocs/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhd3197.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["jhd3197"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"jhd3197","thanks_dev":null,"custom":null}},"created_at":"2024-12-30T11:11:44.000Z","updated_at":"2026-03-05T07:12:20.000Z","dependencies_parsed_at":"2025-09-16T09:58:50.239Z","dependency_job_id":"f7ba2ecc-a000-40eb-b404-9676fef6bf21","html_url":"https://github.com/jhd3197/CacaoDocs","commit_stats":null,"previous_names":["jhd3197/cacaodocs"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/jhd3197/CacaoDocs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhd3197%2FCacaoDocs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhd3197%2FCacaoDocs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhd3197%2FCacaoDocs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhd3197%2FCacaoDocs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhd3197","download_url":"https://codeload.github.com/jhd3197/CacaoDocs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhd3197%2FCacaoDocs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30212485,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T09:02:10.694Z","status":"ssl_error","status_checked_at":"2026-03-07T09:02:08.429Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-documentation","docs","docstring","docstrings","documentation","documentation-generator","documentation-tool","er-diagram","flexsearch","python"],"created_at":"2025-04-02T19:17:51.479Z","updated_at":"2026-03-07T12:01:15.469Z","avatar_url":"https://github.com/jhd3197.png","language":"Python","funding_links":["https://github.com/sponsors/jhd3197","https://buymeacoffee.com/jhd3197"],"categories":[],"sub_categories":[],"readme":"# CacaoDocs\n\nA documentation generator for Python projects, powered by [Cacao](https://github.com/cacao-research/Cacao).\n\nCacaoDocs 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.\n\n## Links\n\n- **PyPI:** [cacaodocs](https://pypi.org/project/cacaodocs/)\n- **GitHub:** [CacaoDocs](https://github.com/jhd3197/CacaoDocs)\n\n## Installation\n\n```bash\npip install cacaodocs\n```\n\n## Quick Start\n\n```bash\n# Initialize config (optional)\ncacaodocs init\n\n# Build docs from your source directory\ncacaodocs build ./src -o ./docs\n\n# Serve the generated docs\ncacaodocs serve ./docs\n```\n\n## How Docstrings Work\n\nCacaoDocs 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`.\n\nHere's the idea — you write normal docstrings, and CacaoDocs figures out what sections to parse based on the type:\n\n| Type | What it's for | How it's detected |\n|------|--------------|-------------------|\n| `function` | Regular functions and methods | Default — no directive needed |\n| `api` | REST API endpoints | Auto-detected from decorators like `@app.get`, `@router.post`, `@app.route` |\n| `class` | Python classes | Detected from class definitions |\n| `page` | Markdown documentation pages | `.md` files in your source directory |\n| `config` | App settings and env vars | Set with `Type: config` |\n| `event` | Webhooks, signals, pub/sub | Set with `Type: event` |\n| Custom | Anything you define | Set with `Type: your_type_name` |\n\n### Function (default)\n\nThe most common type. Just write standard Google-style docstrings — no `Type:` directive needed:\n\n```python\ndef hash_password(password: str, salt: str = None) -\u003e str:\n    \"\"\"Hash a password using bcrypt.\n\n    Args:\n        password (str): The plaintext password.\n        salt (str): Optional salt. Generated if not provided.\n\n    Returns:\n        str: The hashed password string.\n\n    Raises:\n        ValueError: If password is empty or too short.\n\n    Examples:\n        \u003e\u003e\u003e hash_password(\"mysecretpass\")\n        '$2b$12$...'\n    \"\"\"\n```\n\n**Available sections:** `Args`, `Returns`, `Raises`, `Examples`, `Notes`\n\n### API Endpoints\n\nAPI 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.\n\n```python\n@app.get(\"/users/{user_id}\")\ndef get_user(user_id: int):\n    \"\"\"Get a user by ID.\n\n    Path Params:\n        user_id (int): The user's unique identifier.\n\n    Query Params:\n        include (str): Comma-separated fields to include.\n\n    Response (200):\n        id (int): The user ID.\n        name (str): Full name.\n        email (str): Email address.\n\n    Response (404):\n        detail (str): User not found.\n    \"\"\"\n```\n\n**Auto-detected decorators:**\n- **FastAPI**: `@app.get`, `@app.post`, `@router.put`, `@router.delete`, `@router.patch`\n- **Flask**: `@app.route`, `@blueprint.route`\n- **Django REST**: `@api_view`\n\n**Available sections:** `Path Params`, `Query Params`, `Request Body`, `Headers`, `Response (NNN)`\n\n### Config\n\nFor documenting application settings and environment variables. Use `Type: config` to enable config-specific parsing:\n\n```python\ndef load_settings():\n    \"\"\"Application settings.\n\n    Type: config\n\n    Fields:\n        DEBUG (bool, default=False): Enable debug mode.\n        SECRET_KEY (str, required, env=APP_SECRET): Secret key for signing.\n        DATABASE_URL (str, required, env=DATABASE_URL): PostgreSQL connection string.\n        PORT (int, default=8000): Server port.\n    \"\"\"\n```\n\nEach field supports modifiers inside the parentheses:\n- **type** — `str`, `int`, `bool`, etc.\n- **`default=value`** — Default value\n- **`required`** — Marks the field as required\n- **`env=VAR_NAME`** — Maps to an environment variable\n\n### Event\n\nFor documenting webhooks, signals, and event-driven patterns. Use `Type: event`:\n\n```python\ndef on_user_signup(data: dict):\n    \"\"\"User signup event.\n\n    Type: event\n\n    Trigger: When a new user completes registration.\n\n    Payload:\n        user_id (int): The new user ID.\n        email (str): The user's email.\n        plan (str): Selected subscription plan.\n    \"\"\"\n```\n\n**Available sections:** `Trigger` (inline directive), `Payload`\n\n### Custom Types\n\nYou can define your own doc types in `cacao.yaml`. Each custom type gets its own sections and display settings:\n\n```yaml\ndoc_types:\n  cli_command:\n    label: \"CLI Command\"\n    icon: \"terminal\"\n    sections:\n      - name: \"Usage\"\n        format: code\n      - name: \"Options\"\n        format: args\n      - name: \"Flags\"\n        format: args\n\n  database_model:\n    label: \"Model\"\n    icon: \"database\"\n    sections:\n      - name: \"Fields\"\n        format: args\n      - name: \"Indexes\"\n      - name: \"Relations\"\n```\n\nThen use them with the `Type:` directive:\n\n```python\ndef deploy():\n    \"\"\"Deploy the application.\n\n    Type: cli_command\n\n    Usage:\n        deploy --env production --tag v1.2.3\n\n    Options:\n        env (str): Target environment.\n        tag (str): Version tag to deploy.\n    \"\"\"\n```\n\n## Configuration\n\nCreate a `cacao.yaml` in your project root:\n\n```yaml\ntitle: \"My Project\"\ndescription: \"API Documentation\"\nversion: \"1.0.0\"\ntheme: \"dark\"\ngithub_url: \"https://github.com/username/repo\"\n\nexclude_patterns:\n  - \"__pycache__\"\n  - \".venv\"\n  - \"node_modules\"\n```\n\n## Deploy to GitHub Pages\n\nCacaoDocs can export a static version of your docs and deploy them to GitHub Pages. Add this workflow to `.github/workflows/docs.yml`:\n\n```yaml\nname: Deploy Docs to GitHub Pages\n\non:\n  push:\n    branches: [main]\n  workflow_dispatch:\n\npermissions:\n  contents: read\n  pages: write\n  id-token: write\n\nconcurrency:\n  group: pages\n  cancel-in-progress: true\n\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: actions/setup-python@v5\n        with:\n          python-version: \"3.12\"\n\n      - name: Install dependencies\n        run: |\n          pip install cacaodocs\n          pip install \"cacao\u003e=2.1.0\"\n\n      - name: Build docs\n        run: cacaodocs build ./src -o ./_build\n\n      - name: Export static site\n        run: cacaodocs export ./_build -o ./dist --base-path /${{ github.event.repository.name }}\n\n      - name: Upload Pages artifact\n        uses: actions/upload-pages-artifact@v3\n        with:\n          path: dist\n\n      - name: Deploy to GitHub Pages\n        uses: actions/deploy-pages@v4\n```\n\n**Setup steps:**\n1. Go to your repo's **Settings \u003e Pages**\n2. Set **Source** to **GitHub Actions**\n3. Push the workflow file to `main` — it will build and deploy automatically\n\n\u003e **Note:** Change `./src` in the build step to wherever your Python source code lives. The `--base-path` flag is needed so links work correctly under `https://username.github.io/repo-name/`.\n\n## The `@doc()` Decorator\n\nInstead 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.\n\n```python\nfrom cacaodocs import doc\n\n@doc(\n    description=\"Fetch a user by ID.\",\n    args={\"user_id\": {\"type\": \"int\", \"description\": \"The user's unique identifier\"}},\n    returns={\"type\": \"User\", \"description\": \"The matching user\"},\n    raises={\"NotFoundError\": \"If user doesn't exist\"},\n    deprecated=\"2.0\",\n    category=\"Users\",\n    version=\"1.0\",\n)\ndef get_user(user_id: int) -\u003e User:\n    ...\n```\n\nThe 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.\n\n### Decorator vs Docstring\n\nYou can use either approach, or both. When both exist, **decorator values win**.\n\n```python\n# Decorator only — no docstring needed\n@doc(description=\"Add two numbers.\", args={\"a\": \"First\", \"b\": \"Second\"}, returns=\"The sum\")\ndef add(a, b):\n    return a + b\n\n# Supplement mode — docstring provides the basics, decorator adds metadata\n@doc(category=\"Utils\", version=\"3.0\", deprecated=True)\ndef helper():\n    \"\"\"Reticulate the splines.\n\n    Args:\n        count (int): Number of splines.\n    \"\"\"\n    ...\n```\n\n### Supported kwargs\n\n**General:**\n\n| Kwarg | Type | Description |\n|-------|------|-------------|\n| `description` | `str` | Summary text |\n| `doc_type` | `str` | Override type: `\"api\"`, `\"config\"`, `\"event\"`, etc. |\n| `deprecated` | `bool \\| str` | `True` or a since-version string like `\"2.0\"` |\n| `category` | `str` | Sidebar group name |\n| `version` | `str` | Version when added |\n| `hidden` | `bool` | Exclude from generated docs |\n\n**Function sections:**\n\n| Kwarg | Simple syntax | Full syntax |\n|-------|--------------|-------------|\n| `args` | `{\"name\": \"desc\"}` | `{\"name\": {\"type\": \"str\", \"description\": \"...\", \"default\": \"x\"}}` |\n| `returns` | `\"description\"` | `{\"type\": \"User\", \"description\": \"...\"}` |\n| `raises` | `{\"ValueError\": \"when bad\"}` | — |\n| `examples` | `[\"example()\"]` | — |\n| `notes` | `[\"Note text\"]` | — |\n| `attributes` | Same as `args` | Same as `args` |\n\n**API sections:**\n\n| Kwarg | Type | Description |\n|-------|------|-------------|\n| `method` | `str` | HTTP method (`\"GET\"`, `\"POST\"`, etc.) |\n| `path` | `str` | Route path (`\"/users/{id}\"`) |\n| `path_params` | `dict` | Same format as `args` |\n| `query_params` | `dict` | Same format as `args` |\n| `request_body` | `dict` | Same format as `args` |\n| `responses` | `dict` | `{200: \"OK\"}` or `{200: {\"description\": \"...\", \"fields\": {...}}}` |\n| `headers` | `dict` | `{\"Auth\": \"desc\"}` or `{\"Auth\": {\"description\": \"...\", \"required\": True}}` |\n\n**Event sections:**\n\n| Kwarg | Type | Description |\n|-------|------|-------------|\n| `trigger` | `str` | Event trigger name |\n| `payload` | `dict` | `{\"field\": {\"type\": \"int\", \"description\": \"...\"}}` |\n\n**Config sections:**\n\n| Kwarg | Type | Description |\n|-------|------|-------------|\n| `config_fields` | `dict` | `{\"KEY\": {\"type\": \"bool\", \"default\": \"false\", \"env\": \"APP_KEY\"}}` |\n\n## Features\n\n- **`@doc()` Decorator** — Structured metadata as an alternative to docstrings\n- **Doc Types** — Function, API, Class, Page, Config, Event, and Custom types\n- **Auto-Detection** — Flask/FastAPI/Django endpoints detected from decorators\n- **Deprecation Tracking** — From decorators, docstrings, or `@doc(deprecated=\"2.0\")`\n- **Call Map** — Visualize function call relationships across your codebase\n- **Dashboard** — Coverage scores, complexity hotspots, TODOs, dead code detection\n- **Interactive App** — Generated docs are a live Cacao app, not static HTML\n- **Google-style Docstrings** — Extended with API, config, and event sections\n- **Custom Types** — Define your own doc types via `cacao.yaml`\n- **Static Export** — Deploy to GitHub Pages or any static host\n\n## Contributing\n\nContributions are welcome — issues, feature requests, and pull requests.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhd3197%2Fcacaodocs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhd3197%2Fcacaodocs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhd3197%2Fcacaodocs/lists"}