Agent skill

cogapp-markdown

Use cogapp to auto-generate sections of markdown documentation by embedding Python code that produces content. Use when a project needs to keep documentation in sync with code, such as embedding CLI --help output in README files, generating tables, or any content that should be derived from the code itself rather than manually maintained.

Stars 40
Forks 5

Install this agent skill to your Project

npx add-skill https://github.com/simonw/skills/tree/main/cogapp-markdown

SKILL.md

cogapp for Markdown Documentation

Use cogapp to auto-generate sections of markdown files. Cog lets you embed Python code in markdown that produces output inline — the generated content lives in the file alongside the code that created it. Running cog -r regenerates the output, keeping docs in sync with code.

Install

bash
pip install cogapp

Or add "cogapp" to your [dependency-groups] dev dependencies in pyproject.toml.

Markdown Syntax

Use HTML comments as cog markers so the Python code is invisible when the markdown is rendered:

markdown
<!-- [[[cog
import cog
cog.outl("This content is generated by cog.")
]]] -->
This content is generated by cog.
<!-- [[[end]]] -->

The pattern is:

  1. <!-- [[[cog — opens the Python code block (hidden in rendered markdown)
  2. Python code that calls cog.out() or cog.outl() to produce output
  3. ]]] --> — closes the Python code block
  4. Generated output appears here (visible in rendered markdown)
  5. <!-- [[[end]]] --> — marks the end of the generated region

Running Cog

Regenerate all cog blocks in-place:

bash
cog -r docs/*.md

Or without installing — use uv run --with to run cog in a temporary environment:

bash
uv run --with cogapp cog -r docs/*.md

The -r flag replaces file contents in-place. Without it, cog writes to stdout.

Key Pattern: Embedding CLI --help Output

The most common use is keeping CLI documentation in sync with actual --help output.

For Click-based CLIs, use CliRunner to capture help output directly (no subprocess needed):

markdown
<!-- [[[cog
import cog
from mypackage import cli
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli.cli, ["mycommand", "--help"])
help = result.output.replace("Usage: cli", "Usage: mypackage")
cog.out(
    "```\n{}\n```\n".format(help.strip())
)
]]] -->
<!-- [[[end]]] -->

The replace("Usage: cli", "Usage: mypackage") is needed because CliRunner reports the command name as cli instead of the real entry point name.

For argparse or other CLIs, use subprocess:

markdown
<!-- [[[cog
import cog
import subprocess
result = subprocess.run(["mycommand", "--help"], capture_output=True, text=True)
cog.out(
    "```\n{}\n```\n".format(result.stdout.strip())
)
]]] -->
<!-- [[[end]]] -->

GitHub Actions: Fail CI if Cog Hasn't Been Run

Add a step to your test workflow that checks all cog blocks are up to date. This fails CI if someone changes CLI behavior but forgets to regenerate the docs:

yaml
- name: Check if cog needs to be run
  run: |
    cog --check docs/*.md

cog --check exits with code 1 if any file would change. It does not modify files.

Use --check-fail-msg to tell developers how to fix it:

yaml
- name: Check if cog needs to be run
  run: |
    cog --check --check-fail-msg='Run "cog -r docs/*.md" to update' docs/*.md

If the project uses uv and cogapp is not a declared dependency, use uv run --with:

yaml
- name: Check if cog needs to be run
  run: |
    uv run --with cogapp cog --check docs/*.md

Other Patterns

Generating a Markdown Table

markdown
<!-- [[[cog
import cog
headers = ["Name", "Type", "Description"]
rows = [
    ["id", "int", "Primary key"],
    ["name", "str", "User name"],
]
cog.outl("| " + " | ".join(headers) + " |")
cog.outl("| " + " | ".join(["---"] * len(headers)) + " |")
for row in rows:
    cog.outl("| " + " | ".join(row) + " |")
]]] -->
<!-- [[[end]]] -->

Generating a Code Block

markdown
<!-- [[[cog
import cog
import json
data = {"key": "value", "count": 42}
cog.out("```json\n")
cog.outl(json.dumps(data, indent=2))
cog.out("```\n")
]]] -->
<!-- [[[end]]] -->

Multiple Blocks in One File

Each cog block is independent. You can have many blocks in one file — each gets its own <!-- [[[cog ... ]]] --> and <!-- [[[end]]] --> pair. Imports are shared across blocks within the same file.

Useful Flags

  • cog -r FILE — regenerate in-place
  • cog --check FILE — check without modifying (for CI)
  • cog --check --diff FILE — show what would change
  • cog -P FILE — use print() instead of cog.outl() in code blocks

Expand your agent's capabilities with these related and highly-rated skills.

simonw/skills

setup-to-pyproject

Migrate Python projects from setup.py/setup.cfg to pyproject.toml for use with uv. Use when upgrading legacy Python packaging, converting setup.py to modern pyproject.toml format, setting up dependency groups for development/testing, and ensuring `uv run pytest` works correctly.

40 5
Explore
simonw/skills

uv-tdd

A development process for Python applications that uses TDD to iterate on a new project based around uv. Use when Claude needs to create a new Python project, write Python code with tests, or work on Python development using test-driven development practices with the uv package manager.

40 5
Explore
simonw/skills

upgrade-actions

Upgrade GitHub Actions workflows

40 5
Explore
simonw/research

datasette-plugin-writer

Guide for writing Datasette plugins. This skill should be used when users want to create or develop plugins for Datasette, including information about plugin hooks, the cookiecutter template, database APIs, request/response handling, and plugin configuration.

479 38
Explore
simonw/research

starlette

Build async web applications and APIs with Starlette 1.0, the lightweight ASGI framework for Python. Use this skill whenever a user wants to create an async Python web app, REST API, WebSocket server, or ASGI application using Starlette. Triggers include mentions of 'Starlette', 'ASGI', async Python web frameworks, or requests to build lightweight async APIs, WebSocket services, streaming responses, or middleware pipelines. Also use when the user is working with FastAPI internals (which is built on Starlette), needs ASGI middleware patterns, or wants a minimal async web server without a full framework. Covers routing, requests/responses, WebSockets, middleware, templates, static files, authentication, lifespan, background tasks, config, testing, schemas, and more.

479 38
Explore
simonw/research

greeter

Generate a cheerful greeting in any language.

479 38
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results