| name | documentation-writing |
| description | Use when writing or editing documentation under docs/ — page layout, docs_src snippet embedding, snippet tests, link conventions, and FastStream example-code rules. |
FastStream Documentation Writing
Layout
- Pages:
docs/docs/en/... (markdown; mkdocs-material with the i18n plugin — English is the source language).
- Runnable code snippets:
docs/docs_src/<topic>/... (fully excluded from ruff — see exclude in ruff.toml).
- Navigation:
docs/docs/SUMMARY.md (literate-nav) — new pages need an entry there.
- API reference pages are generated by
docs/create_api_docs.py — never hand-edit them.
Code snippets
Never inline non-trivial code in markdown. Put a runnable Python file in docs/docs_src/ and embed it with mdx_include:
{!> docs_src/getting_started/publishing/kafka/broker.py !}
New docs_src snippets should get a test under tests/docs/<topic>/test_<feature>.py — one test file covers all broker variants via require marks (e.g. @require_aiokafka), not one file per broker subdir (see the testing-patterns skill). Some examples are intentionally untested; the exemptions are listed in the coverage omit list in pyproject.toml.
A snippet test imports the runnable objects from the module and exercises them in-memory — never a bare import module (it tests nothing and trips ruff F401):
import pytest
from faststream.nats import TestApp, TestNatsBroker
@pytest.mark.nats()
@pytest.mark.asyncio()
async def test_basic() -> None:
from docs.docs_src.nats.js.pull_sub import app, broker, handle
async with TestNatsBroker(broker), TestApp(app):
await broker.publish("Hi!", "test")
handle.mock.assert_called_once_with("Hi!")
The test imports via the docs.docs_src.… package path, while the markdown embeds it via the docs_src/… path (mdx_include base_path is docs/). Either way the snippet MUST live under docs/docs_src/, not repo-root docs_src/ — otherwise the embed silently resolves to nothing and the import fails.
Markdown conventions
-
External links: [text](https://...){.external-link target="_blank"}; internal links: {.internal-link}.
-
Multi-broker pages use pymdownx tabs with one snippet per broker:
=== "AIOKafka"
...embedded kafka snippet...
=== "Confluent"
...embedded confluent snippet...
=== "RabbitMQ"
...embedded rabbit snippet...
-
Admonitions (!!! note, !!! tip, !!! warning) are available and encouraged for caveats.
Example-code rules (FastStream usage)
All example code must follow idiomatic FastStream usage:
- Create the broker outside the app and pass it positionally:
app = FastStream(broker). Don't use app.broker.
- Prefer the
faststream.Logger annotation in broker handlers over print() (some HTTP-integration examples use print() for brevity).
- Register subscribers/publishers only via
@broker.subscriber(...) / @broker.publisher(...) (or the router equivalents).
- Fully annotate handler parameters; handlers return
None unless their return value is published.
- Don't add decorator options the example doesn't need.
- Use
Annotated[str, Path()] for subject path params and Annotated[..., Context()] for context access (built-ins: broker, context, logger, message).
- Import only from public packages — never
faststream._internal.
Build & serve
just docs-serve — live dev server on port 8000.
just docs-build — build the static site.
just docs-build-api — regenerate the API reference.
Related skills
- testing-patterns — how to mark and run the snippet tests in
tests/docs/.
- code-architecture — source conventions example code must follow (public API only, no
_internal imports).
- dev-workflow — environment setup for the docs toolchain.