cogapp-markdown
Auto-generate and keep markdown documentation in sync with code using cogapp. Use when user says "keep docs in sync", "regenerate readme", "embed --help output", "run cog -r", "documentation is out of date", "sync CLI help into README", or when documentation should be derived from code rather than maintained by hand.
From cogapp-markdownnpx claudepluginhub fblissjr/fb-claude-skills --plugin cogapp-markdownThis skill is limited to using the following tools:
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
uv add --dev 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:
<!-- [[[cog
import cog
cog.outl("This content is generated by cog.")
]]] -->
This content is generated by cog.
<!-- [[[end]]] -->
The pattern is:
<!-- [[[cog— opens the Python code block (hidden in rendered markdown)- Python code that calls
cog.out()orcog.outl()to produce output ]]] -->— closes the Python code block- Generated output appears here (visible in rendered markdown)
<!-- [[[end]]] -->— marks the end of the generated region
Running Cog
Regenerate all cog blocks in-place:
cog -r docs/*.md
Or without installing — use uv run --with to run cog in a temporary environment:
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):
<!-- [[[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:
<!-- [[[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:
- 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:
- 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:
- name: Check if cog needs to be run
run: |
uv run --with cogapp cog --check docs/*.md
Other Patterns
Generating a Markdown Table
<!-- [[[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
<!-- [[[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-placecog --check FILE— check without modifying (for CI)cog --check --diff FILE— show what would changecog -P FILE— useprint()instead ofcog.outl()in code blocks