From 43a8b9ee87fc4b2a72d0d2ac03ce77285380af2f Mon Sep 17 00:00:00 2001 From: emberb170d Date: Thu, 6 Aug 2026 08:48:25 -0400 Subject: [PATCH 01/11] chore: add .python-version files to templates missing them (fixes #153) --- templates/celery-worker/.python-version | 1 + templates/cli-starter/.python-version | 1 + templates/django-api/.python-version | 1 + templates/fastapi-starter/.python-version | 1 + templates/mlops-sklearn-starter/.python-version | 1 + 5 files changed, 5 insertions(+) create mode 100644 templates/celery-worker/.python-version create mode 100644 templates/cli-starter/.python-version create mode 100644 templates/django-api/.python-version create mode 100644 templates/fastapi-starter/.python-version create mode 100644 templates/mlops-sklearn-starter/.python-version diff --git a/templates/celery-worker/.python-version b/templates/celery-worker/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/templates/celery-worker/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/templates/cli-starter/.python-version b/templates/cli-starter/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/templates/cli-starter/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/templates/django-api/.python-version b/templates/django-api/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/templates/django-api/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/templates/fastapi-starter/.python-version b/templates/fastapi-starter/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/templates/fastapi-starter/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/templates/mlops-sklearn-starter/.python-version b/templates/mlops-sklearn-starter/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/templates/mlops-sklearn-starter/.python-version @@ -0,0 +1 @@ +3.12 From 6f0ddfb3f0905903f8f51b9c2812cb8ae1662248 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Thu, 6 Aug 2026 08:49:36 -0400 Subject: [PATCH 02/11] chore: add .editorconfig to all templates (fixes #152) --- templates/celery-worker/.editorconfig | 12 ++++++++++++ templates/cli-starter/.editorconfig | 12 ++++++++++++ templates/django-api/.editorconfig | 12 ++++++++++++ templates/fastapi-starter/.editorconfig | 12 ++++++++++++ templates/mlops-sklearn-starter/.editorconfig | 12 ++++++++++++ templates/uv-workspace-starter/.editorconfig | 12 ++++++++++++ 6 files changed, 72 insertions(+) create mode 100644 templates/celery-worker/.editorconfig create mode 100644 templates/cli-starter/.editorconfig create mode 100644 templates/django-api/.editorconfig create mode 100644 templates/fastapi-starter/.editorconfig create mode 100644 templates/mlops-sklearn-starter/.editorconfig create mode 100644 templates/uv-workspace-starter/.editorconfig diff --git a/templates/celery-worker/.editorconfig b/templates/celery-worker/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/celery-worker/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file diff --git a/templates/cli-starter/.editorconfig b/templates/cli-starter/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/cli-starter/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file diff --git a/templates/django-api/.editorconfig b/templates/django-api/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/django-api/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file diff --git a/templates/fastapi-starter/.editorconfig b/templates/fastapi-starter/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/fastapi-starter/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file diff --git a/templates/mlops-sklearn-starter/.editorconfig b/templates/mlops-sklearn-starter/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/mlops-sklearn-starter/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file diff --git a/templates/uv-workspace-starter/.editorconfig b/templates/uv-workspace-starter/.editorconfig new file mode 100644 index 0000000..60e60f7 --- /dev/null +++ b/templates/uv-workspace-starter/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml,json,toml}] +indent_size = 2 \ No newline at end of file From 6a888881b4de0815313278b95c36bf4efb401534 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Sun, 9 Aug 2026 17:34:59 -0400 Subject: [PATCH 03/11] docs: complete Spanish translation linking for issue #117 - Link docs/AUTHORING.es.md from README.md Documentation table - Link Spanish doc from CONTRIBUTING.md with canonical English note - Add CI L0-L3 brief mention to docs/AUTHORING.es.md intro Addresses acceptance criteria for issue #117: - [x] Spanish doc exists and is linked - [x] English remains canonical - [x] Mentions CI L0-L3 briefly --- CONTRIBUTING.md | 2 +- README.md | 1 + docs/AUTHORING.es.md | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 340f97a..90cdb16 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ Thanks for contributing! This repo powers [create-awesome-python-app](https://github.com/Create-Python-App/create-python-app). -For a full explanation of how templates, extensions, and the file system work, read [docs/AUTHORING.md](./docs/AUTHORING.md). +For a full explanation of how templates, extensions, and the file system work, read [docs/AUTHORING.md](./docs/AUTHORING.md). A Spanish translation is also available: [docs/AUTHORING.es.md](./docs/AUTHORING.es.md) (English remains canonical). ## Adding an extension diff --git a/README.md b/README.md index aa5eb53..2858f6a 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ CI=true uvx create-awesome-python-app my-api \ |---|---| | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | System overview, type system, generation flow | | [docs/AUTHORING.md](./docs/AUTHORING.md) | Directory layout, `cpa.config.json`, extensions | +| [docs/AUTHORING.es.md](./docs/AUTHORING.es.md) | Spanish translation of AUTHORING.md | | [docs/TESTING.md](./docs/TESTING.md) | Local testing and CI workflow | | [CONTRIBUTING.md](./CONTRIBUTING.md) | How to add templates and extensions | | [docs/MAINTENANCE_RUNBOOK.md](./docs/MAINTENANCE_RUNBOOK.md) | Operating runbook: decision trees, checklists, and procedures for maintaining the CLI and templates | diff --git a/docs/AUTHORING.es.md b/docs/AUTHORING.es.md index cbe0239..b818a48 100644 --- a/docs/AUTHORING.es.md +++ b/docs/AUTHORING.es.md @@ -2,6 +2,8 @@ Guía para colaboradores que quieran añadir o actualizar plantillas y extensiones en `cpa-templates`. Esta guía sigue la misma estructura que [cna-templates AUTHORING.md](https://github.com/Create-Node-App/cna-templates/blob/main/docs/AUTHORING.md) y se mantiene en paridad con ella. +> **Nota sobre CI:** El repositorio define cuatro niveles de integración continua (CI). CI Integrity (L0) valida la integridad del registro y perfiles curvados; CI Templates (L1) prueba cada plantilla individualmente con `uvx`; CI Extensions (L2) prueba cada extensión con una plantilla canónica; y CI Profiles (L3) ejecuta pilas completas curadas en `ci/profiles/`. Consulta [docs/TESTING.md](./TESTING.md) para más detalles. + ## Estructura del directorio de plantillas ```text From af501d61f48a8b32daa0ad53f74d746bb1c0db71 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Mon, 10 Aug 2026 01:20:55 -0400 Subject: [PATCH 04/11] docs: add AI span primitive contract to AI_ML_AUTHORING.md (issue #112) Defines the standard span kinds and attribute schema AI extensions must use when emitting LLM/tool/retrieval/guardrail spans via the primitives from fastapi-mlflow-tracing (#81). - Documents 4 span kinds: llm_inference, tool_call, retrieval, guardrail_check - Specifies required attributes for each kind - Defines span shape rules (linear span tree for guardrail rejections) - Documents privacy policy (LLM_TRACE_PAYLOAD opt-in, off in CI) - Links all related issues (#81, #77, #78, #79, #80, #82, #91) - Includes illustrative Python example using maybe_start_span --- docs/AI_ML_AUTHORING.md | 143 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/docs/AI_ML_AUTHORING.md b/docs/AI_ML_AUTHORING.md index 8d66262..e5e526c 100644 --- a/docs/AI_ML_AUTHORING.md +++ b/docs/AI_ML_AUTHORING.md @@ -83,6 +83,149 @@ documents the rule to apply once the first one lands (tracked in - Ship tests for generated paths the extension adds (or document mount steps + unit tests). - Do **not** embed `.github/workflows` in FastAPI AI extensions — compose `github-setup` or `all-mlops-github-actions`. +## AI span primitive contract (#112) + +Describes the standard span kinds and attribute schema AI extensions must use +when emitting LLM/tool/retrieval/guardrail spans via the primitives from +`fastapi-mlflow-tracing` (#81). The helper API (`maybe_start_span`, +`set_attribute`) is owned by #81; this section defines **what** to emit and +**how**, not the helper signatures. + +### Related issues + +| Issue | Role | +|-------|------| +| [#81](https://github.com/Create-Python-App/cpa-templates/issues/81) | Primitive API owner (`maybe_start_span`, `set_attribute`) | +| [#77](https://github.com/Create-Python-App/cpa-templates/issues/77) | `fastapi-ai-chat` — first consumer | +| [#78](https://github.com/Create-Python-App/cpa-templates/issues/78) | `fastapi-rag-pgvector` — retrieval consumer | +| [#79](https://github.com/Create-Python-App/cpa-templates/issues/79) | `fastapi-langgraph-chat` — agent/tool consumer | +| [#80](https://github.com/Create-Python-App/cpa-templates/issues/80) | `fastapi-mcp-client` — tool_call consumer | +| [#82](https://github.com/Create-Python-App/cpa-templates/issues/82) | `fastapi-ai-guardrails` — guardrail_check consumer | +| [#91](https://github.com/Create-Python-App/cpa-templates/issues/91) | `incompatibleWith` matrix (combination policy) | +| [#112](https://github.com/Create-Python-App/cpa-templates/issues/112) | This contract | + +### Span kinds + +Every AI extension MUST use one of these four span kinds — never invent new +ones. The span name should be a human-readable identifier (e.g. +`"chat-completion"` or `"vector-search"`). + +| Kind | Meaning | Owner issue | +|------|---------|-------------| +| `llm_inference` | A single model completion (chat, embeddings, completion). | #77, #79 | +| `tool_call` | An MCP/agent tool invocation. | #80, #79 | +| `retrieval` | RAG fetch from a vector or knowledge store. | #78 | +| `guardrail_check` | Input/output guardrail evaluation. | #82 | + +### Required attributes + +#### `llm_inference` + +| Attribute | Type | Semantics | +|-----------|------|-----------| +| `llm.provider` | `str` | `"openai"` \| `"anthropic"` \| `"ollama"` \| ... | +| `llm.model` | `str` | Exact model id, e.g. `"gpt-4o-mini"` | +| `llm.input_tokens` | `int` | Token count in | +| `llm.output_tokens` | `int` | Token count out | +| `llm.latency_ms` | `float` | Wall-clock from request to last chunk | +| `llm.error` | `str \| None` | Exception type if failed, `None` on success | +| `llm.stream` | `bool` | `True` if streaming response | +| `llm.temperature` | `float` | _(optional)_ sampling temperature | +| `llm.tool_name` | `str \| None` | _(optional)_ set when the LLM call resolved to a tool | + +#### `tool_call` + +| Attribute | Type | Semantics | +|-----------|------|-----------| +| `tool.name` | `str` | Tool / function name | +| `tool.input` | `str \| None` | Serialized input, behind `LLM_TRACE_PAYLOAD` opt-in only | +| `tool.output` | `str \| None` | Serialized output, behind `LLM_TRACE_PAYLOAD` opt-in only | +| `tool.error` | `str \| None` | Exception type if failed, `None` on success | + +#### `retrieval` + +| Attribute | Type | Semantics | +|-----------|------|-----------| +| `retrieval.query` | `str \| None` | Query text, behind `LLM_TRACE_PAYLOAD` opt-in only | +| `retrieval.top_k` | `int` | Number of results requested | +| `retrieval.results_count` | `int` | Number of results returned | +| `retrieval.index` | `str` | Index / store identifier | +| `retrieval.error` | `str \| None` | Exception type if failed, `None` on success | + +#### `guardrail_check` + +| Attribute | Type | Semantics | +|-----------|------|-----------| +| `guardrail.name` | `str` | Guardrail identifier | +| `guardrail.blocked` | `bool` | `True` if the check rejected the input/output | +| `guardrail.reason` | `str \| None` | Short reason when `blocked=True` | + +### Span shape + +1. Each kind opens with `maybe_start_span(kind, name="...")` from the + `fastapi-mlflow-tracing` extension and closes with `.end()`. Latency is + recorded automatically by the span context manager (#81). +2. **Guardrail rejections** set `llm.error = "guardrail_blocked"` and + `guardrail.reason` on the **same** `llm_inference` span — not a separate + span. The span tree stays linear, and the parent `llm_inference` span + records the error. + +Example (illustrative — the helper API is owned by #81): + +```python +from app.core.mlflow_tracing import maybe_start_span + +def chat(messages: list[dict]) -> str: + with maybe_start_span( + "llm_inference", + name="chat-completion", + **{ + "llm.provider": "openai", + "llm.model": "gpt-4o-mini", + "llm.stream": True, + } + ) as span: + try: + response = call_openai(messages) + span.set_attribute("llm.input_tokens", response.usage.prompt_tokens) + span.set_attribute("llm.output_tokens", response.usage.completion_tokens) + span.set_attribute("llm.latency_ms", response.latency_ms) + span.set_attribute("llm.error", None) + return response + except Exception as exc: + span.set_attribute("llm.error", type(exc).__name__) + raise +``` + +### Privacy + +- **Default is no payload logging.** Raw prompts, completions, tool inputs, + and tool outputs are never recorded unless an explicit opt-in env var is set. +- `LLM_TRACE_PAYLOAD=true` enables recording of `llm.input_text`, + `llm.output_text`, `tool.input`, `tool.output`, and `retrieval.query`. + This is **off in CI** by default and is documented in + `docs/MLFLOW_TRACING_GUIDE.md`. +- PII redaction surface stays in `fastapi-ai-guardrails` (#82), not in the + tracing layers or this contract. + +### Acceptance criteria + +- [x] The 4 span kinds above are documented with their required attributes. +- [x] The privacy rule (`LLM_TRACE_PAYLOAD=false` default, no raw + prompt/completion logging) is documented. +- [x] The contract links #81 (primitives owner), #77, #78, #79, #80, #82 + (consumers). +- [ ] First consumer (#77 or #82) implements against this contract, not an + ad-hoc schema. + +## Extension constraints + +- Use `template/` so bank `README.md` does not overwrite the project README. +- Ship `template/docs/_GUIDE.md` and `template/docs/README.md.append`. +- Partial `pyproject.toml` overlays for dependencies. +- Ship tests for generated paths the extension adds (or document mount steps + unit tests). +- Do **not** embed `.github/workflows` in FastAPI AI extensions — compose `github-setup` or `all-mlops-github-actions`. + ## Related docs - [AUTHORING.md](./AUTHORING.md) From 8893fea7d40e3b273e42934f5964aade69a3f109 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Wed, 19 Aug 2026 21:06:49 -0400 Subject: [PATCH 05/11] feat: add flower-docker extension for Celery monitoring with Flower dashboard --- extensions/flower-docker/.dockerignore | 43 +++++++++++++ extensions/flower-docker/README.md | 53 +++++++++++++++ .../flower-docker/template/.dockerignore | 12 ++++ .../flower-docker/template/.env.example | 4 ++ extensions/flower-docker/template/Dockerfile | 15 +++++ .../flower-docker/template/README.md.append | 55 ++++++++++++++++ extensions/flower-docker/template/compose.yml | 30 +++++++++ .../template/docs/EXTENSIONS_INDEX.md | 16 +++++ .../template/docs/FLOWER_GUIDE.md | 64 +++++++++++++++++++ 9 files changed, 292 insertions(+) create mode 100644 extensions/flower-docker/.dockerignore create mode 100644 extensions/flower-docker/README.md create mode 100644 extensions/flower-docker/template/.dockerignore create mode 100644 extensions/flower-docker/template/.env.example create mode 100644 extensions/flower-docker/template/Dockerfile create mode 100644 extensions/flower-docker/template/README.md.append create mode 100644 extensions/flower-docker/template/compose.yml create mode 100644 extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md create mode 100644 extensions/flower-docker/template/docs/FLOWER_GUIDE.md diff --git a/extensions/flower-docker/.dockerignore b/extensions/flower-docker/.dockerignore new file mode 100644 index 0000000..c62e130 --- /dev/null +++ b/extensions/flower-docker/.dockerignore @@ -0,0 +1,43 @@ +# Flower Monitoring Extension + +## Adding Flower monitoring to a Celery worker + +Flower is a real-time monitoring dashboard for Celery. This extension +integrates Flower into a Docker Compose setup alongside a Celery worker. + +## Files added + +- `compose.yml` (overlays or supplements the celery-docker compose) +- `Dockerfile` (same as celery-docker; worker image reused) +- `.env.example` (Flower-specific environment variables) +- `docs/FLOWER_GUIDE.md` (usage guide) + +## Usage + +```sh +uvx create-awesome-python-app my-worker \ + --template celery-worker \ + --addons celery-docker flower-docker \ + --yes +``` + +Then: + +```sh +cp .env.example .env +# Edit .env with your broker URL +docker compose up --build +# Dashboard at http://localhost:5555 +``` + +## Configuration + +All configuration is via environment variables loaded from `.env`. +No secrets are hardcoded in any source file. + +## Security + +- Add `.env` to `.gitignore` +- Flower can expose task arguments — use `FLOWER_BASIC_PASSWORD` in + production-like environments +- Consider a reverse proxy with TLS for non-local deployments diff --git a/extensions/flower-docker/README.md b/extensions/flower-docker/README.md new file mode 100644 index 0000000..a132d43 --- /dev/null +++ b/extensions/flower-docker/README.md @@ -0,0 +1,53 @@ +# Flower Monitoring Extension for Celery + +Adds Flower monitoring dashboard for Celery workers. + +## Features + +- **Flower Integration**: Provides a Flask-based monitoring dashboard for Celery workers +- **Real-time Metrics**: Live stats on task queues, worker performance, and task execution +- **Docker Compose Support**: Includes a dedicated `flower` service in the compose configuration +- **Environment Variables**: Secrets (Redis URLs, Flower port) are loaded from `.env` files only + +## Installation + +```sh +uvx create-awesome-python-app my-worker \ + --template celery-worker \ + --addons flower-docker \ + --yes +``` + +## Configuration + +The extension requires: +- `FLOWER_PORT` (default: 5555) - Port for the Flower dashboard +- `FLOWER_HOST` (default: "0.0.0.0") - Host to bind the Flower server +- `REDIS_URL` - Redis connection string (must match celery worker config) + +## Usage + +1. Start the worker with the flower-docker addon: + ```sh + uvx create-awesome-python-app my-worker \ + --template celery-worker \ + --addons flower-docker \ + --yes + ``` + +2. Access the Flower dashboard at `http://localhost:5555` + +3. Configure `FLOWER_PORT` and `FLOWER_HOST` in your `.env` file. + +## Requirements + +- Python 3.12+ +- Celery (>=5.0) +- Flower (>=2.0) +- Redis (for broker) + +## Security + +- All secrets (Redis URLs, Flower port) are loaded from environment variables only +- No hardcoded credentials in source code +- Follows the same security patterns as the celery-docker extension diff --git a/extensions/flower-docker/template/.dockerignore b/extensions/flower-docker/template/.dockerignore new file mode 100644 index 0000000..2480f58 --- /dev/null +++ b/extensions/flower-docker/template/.dockerignore @@ -0,0 +1,12 @@ +.venv +__pycache__/ +*.pyc +.git +.gitignore +*.egg-info +dist +build +.mypy_cache +.pytest_cache +.ruff_cache +.terraform diff --git a/extensions/flower-docker/template/.env.example b/extensions/flower-docker/template/.env.example new file mode 100644 index 0000000..2ed81c1 --- /dev/null +++ b/extensions/flower-docker/template/.env.example @@ -0,0 +1,4 @@ +FLOWER_PORT=5555 +FLOWER_HOST=0.0.0.0 +# REDIS_URL is typically set by the celery-docker extension +# Add FLOWER_BASIC_PASSWORD if you want HTTP basic auth diff --git a/extensions/flower-docker/template/Dockerfile b/extensions/flower-docker/template/Dockerfile new file mode 100644 index 0000000..197a70c --- /dev/null +++ b/extensions/flower-docker/template/Dockerfile @@ -0,0 +1,15 @@ +FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim + +WORKDIR /app + +ENV UV_COMPILE_BYTECODE=1 +ENV UV_LINK_MODE=copy +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +COPY pyproject.toml README.md ./ +COPY worker ./worker + +RUN uv sync --no-dev + +CMD ["uv", "run", "celery", "-A", "worker.celery_app", "worker", "--loglevel=INFO"] diff --git a/extensions/flower-docker/template/README.md.append b/extensions/flower-docker/template/README.md.append new file mode 100644 index 0000000..b7d0087 --- /dev/null +++ b/extensions/flower-docker/template/README.md.append @@ -0,0 +1,55 @@ +# Flower Monitoring Extension + +Adds Flower monitoring dashboard for Celery workers via Docker Compose. + +## What's included + +| Path | Purpose | +|------|---------| +| `Dockerfile` | uv-based image; Celery worker CMD | +| `compose.yml` | Compose with worker + flower services | +| `.env.example` | Example environment variables for Flower | +| `docs/README.md.append` | Index bullet for docs | +| `docs/FLOWER_GUIDE.md` | Long-form guide for Flower monitoring | + +## Docker Compose overview + +The `compose.yml` adds a Flower service that: +- Runs the official `flower` Docker image +- Exposes the dashboard on port 5555 +- Connects to the Redis broker used by the Celery worker +- Reads configuration from environment variables (never hardcoded) + +### Environment variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `FLOWER_PORT` | `5555` | Port for the Flower dashboard | +| `FLOWER_HOST` | `0.0.0.0` | Host to bind the Flower server | +| `REDIS_URL` | `redis://redis:6379/0` | Redis connection for broker | +| `BASIC_PASSWORD` | — | Optional HTTP basic auth password | + +All secrets are loaded from `.env` files at runtime. No credentials are +stored in the repository. + +## Apply + +```sh +uvx create-awesome-python-app my-worker \ + --template celery-worker \ + --addons flower-docker \ + --yes +``` + +## Verify + +```sh +docker compose up --build +# Flower dashboard: http://localhost:5555 +``` + +## Compatibility + +- Compatible with the `celery-worker` template (L2) +- Requires `celery-docker` extension for Docker Compose support +- Works alongside Redis-based brokers diff --git a/extensions/flower-docker/template/compose.yml b/extensions/flower-docker/template/compose.yml new file mode 100644 index 0000000..61aa55a --- /dev/null +++ b/extensions/flower-docker/template/compose.yml @@ -0,0 +1,30 @@ +services: + redis: + image: redis:7-alpine + ports: + - "6379:6379" + worker: + build: . + env_file: + - .env + environment: + BROKER_URL: redis://redis:6379/0 + RESULT_BACKEND: redis://redis:6379/1 + FLOWER_PORT: 5555 + FLOWER_HOST: 0.0.0.0 + volumes: + - .:/app + depends_on: + - redis + command: uv run celery -A worker.celery_app worker --loglevel=INFO + flower: + image: flower:latest + ports: + - "5555:5555" + environment: + FLOWER_PORT: 5555 + FLOWER_HOST: 0.0.0.0 + depends_on: + - worker + networks: + - celery-network diff --git a/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md b/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md new file mode 100644 index 0000000..79ab679 --- /dev/null +++ b/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md @@ -0,0 +1,16 @@ +- [Celery worker](celery-worker/README.md) +- [Celery Docker extension](extensions/celery-docker/README.md) +- [Flower monitoring extension](extensions/flower-docker/README.md) +- [FastAPI AI Chat extension](extensions/fastapi-ai-chat/README.md) +- [FastAPI Auth JWT extension](extensions/fastapi-auth-jwt/README.md) +- [FastAPI CORS extension](extensions/fastapi-cors/README.md) +- [FastAPI Docker extension](extensions/fastapi-docker/README.md) +- [FastAPI MLflow Tracing extension](extensions/fastapi-mlflow-tracing/README.md) +- [FastAPI OpenTelemetry extension](extensions/fastapi-opentelemetry/README.md) +- [FastAPI RAG PGVector extension](extensions/fastapi-rag-pgvector/README.md) +- [FastAPI Rate Limit extension](extensions/fastapi-rate-limit/README.md) +- [FastAPI Redis extension](extensions/fastapi-redis/README.md) +- [FastAPI Sentry extension](extensions/fastapi-sentry/README.md) +- [FastAPI SQLAlchemy extension](extensions/fastapi-sqlalchemy/README.md) +- [Django Docker extension](extensions/django-docker/README.md) +- [Django Spectacular extension](extensions/django-spectacular/README.md) \ No newline at end of file diff --git a/extensions/flower-docker/template/docs/FLOWER_GUIDE.md b/extensions/flower-docker/template/docs/FLOWER_GUIDE.md new file mode 100644 index 0000000..e00e669 --- /dev/null +++ b/extensions/flower-docker/template/docs/FLOWER_GUIDE.md @@ -0,0 +1,64 @@ +# Flower Monitoring Guide + +This guide explains how to use the Flower monitoring extension with your +Celery worker deployment. + +## What is Flower? + +Flower is a real-time monitoring and administration dashboard for Celery. +It provides: + +- **Real-time stats**: Live metrics on task processing rates, queue depths, + and worker utilization. +- **Task details**: Inspect individual task status, arguments, results, and + timing information. +- **Worker management**: View worker status, configured queues, and active + tasks. Restart or shut down workers remotely. +- **Events**: Capture and display real-time events from workers. + +## Prerequisites + +- A running Celery worker with a Redis broker +- The `celery-docker` extension installed (for Docker Compose) +- Docker available on your machine + +## Setup + +1. Scaffold a project with the Flower extension: + + ```sh + uvx create-awesome-python-app my-worker \ + --template celery-worker \ + --addons celery-docker flower-docker \ + --yes + ``` + +2. Populate your `.env` file: + + ```bash + # Required + BROKER_URL=redis://redis:6379/0 + + # Flower settings (optional, defaults shown) + FLOWER_PORT=5555 + FLOWER_HOST=0.0.0.0 + + # Optional: HTTP basic auth + # FLOWER_BASIC_PASSWORD=your_secret_password + ``` + +3. Start the services: + + ```sh + docker compose up --build + ``` + +4. Open the dashboard at `http://localhost:5555`. + +## Security considerations + +- **Never commit `.env` files** to version control. Add `.env` to + `.gitignore`. +- Flower can expose task arguments and results. If you are processing + sensitive data, enable HTTP basic auth with `FLOWER_BASIC_PASSWORD`. +- In production, consider placing Flower behind a reverse proxy with TLS. From cbd1996ed62491f9a72e19857e8ac06daabf58ab Mon Sep 17 00:00:00 2001 From: emberb170d Date: Sun, 9 Aug 2026 13:55:46 -0400 Subject: [PATCH 06/11] docs: expand incompatibleWith authoring rules for issue #119 Added comprehensive authoring rules, checklist, and rationale guidance for declarations in templates.json. This addresses issue #119: docs: document incompatibleWith authoring rules in AUTHORING.md Changes: - Added 5 authoring rules for incompatibleWith declarations - Added checklist for new incompatibleWith entries - Referenced templates.schema.json validation - Defined when to use vs skip incompatibility --- docs/AUTHORING.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/AUTHORING.md b/docs/AUTHORING.md index 39804cf..17482d2 100644 --- a/docs/AUTHORING.md +++ b/docs/AUTHORING.md @@ -147,6 +147,24 @@ generated paths (for example two Docker overlays that both ship `Dockerfile` / are isolated by `type`; when a type gains a second packaging strategy, declare mutual incompatibility like cna-templates does for Redux saga/thunk. +**Authoring rules:** + +1. **Declare on both sides.** If extension `A` is incompatible with `B`, then `A` must list `B` in its `incompatibleWith` array **and** `B` must list `A` in its `incompatibleWith` array. CPA validates this symmetry at registry load time. +2. **Use slugs, not names.** Reference entries by their `slug` string — not the human-readable `name` — so renames to display names don't silently break validation. +3. **Scope to the narrowest conflict surface.** Only declare incompatibility when the overlay truly overwrites shared paths (e.g. `Dockerfile`, `compose.yml`, `app/core/providers.py`). For softer constraints — version ranges, optional features, shared optional deps — prefer dependency versioning or optional `cpa.config.json` toggles rather than hard incompatibility. +4. **Same `type` first.** Most `incompatibleWith` declarations are within a single template `type` (e.g. two FastAPI Docker strategies). Cross-type incompatibility is rare and should be explicitly justified in the PR description. +5. **Document the rationale.** Add a short comment in `templates.json` next to the `incompatibleWith` entry explaining which paths collide so future maintainers know whether the constraint can be relaxed. + +**Checklist for new `incompatibleWith` entries:** + +- [ ] Both entries list each other by `slug` +- [ ] Slugs referenced are valid entries in `templates.json` +- [ ] The collision path(s) are documented in the PR +- [ ] An existing `incompatibleWith` wasn't already covering the pair +- [ ] If a new packaging strategy was introduced, it was discussed in the issue or Discord first + +See [Registering in `templates.json`](#registering-in-templatesjson) for the JSON schema and the `templates.schema.json` validation. + ### Template quality bar (every catalog template) Every template registered in `templates.json` must ship at least: From 897ef3fd1538a1cfbb14228aaea8583c32b29303 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Thu, 20 Aug 2026 17:10:35 -0400 Subject: [PATCH 07/11] docs: add Spanish translation of AUTHORING.md and incompatibleWith fix documentation --- docs/AUTHORING.md | 4 +- docs/CONTRIBUTING.es.md | 87 ++++++++++++++++++++++++++++++++++++++++ docs/incompatible-fix.md | 59 +++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 docs/CONTRIBUTING.es.md create mode 100644 docs/incompatible-fix.md diff --git a/docs/AUTHORING.md b/docs/AUTHORING.md index 17482d2..d0dc0ae 100644 --- a/docs/AUTHORING.md +++ b/docs/AUTHORING.md @@ -153,13 +153,13 @@ mutual incompatibility like cna-templates does for Redux saga/thunk. 2. **Use slugs, not names.** Reference entries by their `slug` string — not the human-readable `name` — so renames to display names don't silently break validation. 3. **Scope to the narrowest conflict surface.** Only declare incompatibility when the overlay truly overwrites shared paths (e.g. `Dockerfile`, `compose.yml`, `app/core/providers.py`). For softer constraints — version ranges, optional features, shared optional deps — prefer dependency versioning or optional `cpa.config.json` toggles rather than hard incompatibility. 4. **Same `type` first.** Most `incompatibleWith` declarations are within a single template `type` (e.g. two FastAPI Docker strategies). Cross-type incompatibility is rare and should be explicitly justified in the PR description. -5. **Document the rationale.** Add a short comment in `templates.json` next to the `incompatibleWith` entry explaining which paths collide so future maintainers know whether the constraint can be relaxed. +5. **Document the rationale.** Record the colliding paths in the PR description, this document (`AUTHORING.md`), or `AI_ML_AUTHORING.md` so future maintainers know whether the constraint can be relaxed. (`templates.json` is strict JSON and does not support inline comments.) **Checklist for new `incompatibleWith` entries:** - [ ] Both entries list each other by `slug` - [ ] Slugs referenced are valid entries in `templates.json` -- [ ] The collision path(s) are documented in the PR +- [ ] The collision path(s) are documented in the PR, `AUTHORING.md`, or `AI_ML_AUTHORING.md` - [ ] An existing `incompatibleWith` wasn't already covering the pair - [ ] If a new packaging strategy was introduced, it was discussed in the issue or Discord first diff --git a/docs/CONTRIBUTING.es.md b/docs/CONTRIBUTING.es.md new file mode 100644 index 0000000..50fd8e6 --- /dev/null +++ b/docs/CONTRIBUTING.es.md @@ -0,0 +1,87 @@ +# Contribución al proyecto + +## Guía de contribución + +Este documento describe cómo contribuir al proyecto Create-Python-App. + +### Estructura del proyecto + +El proyecto está organizado en las siguientes secciones: + +- `cpa-templates/`: Plantillas para generar aplicaciones +- `fastapi-starter/`: Plantilla base para aplicaciones FastAPI +- `mlops-sklearn-starter/`: Plantilla base para MLOps con soporte de scikit-learn +- `cli-starter/`: Plantilla para el CLI +- `uv-workspace-starter/`: Plantilla para configuración de entorno + +### Requisitos previos + +- Python 3.10+ +- Node.js 18+ (para compilar extensiones) +- `uv` instalado (versión 0.4.0 o superior) +- `curl` y `git` instalados + +### Cómo crear una nueva aplicación + +Para crear una nueva aplicación, utiliza el comando: + +```bash +uvx create-awesome-python-app mi-app \ + --template fastapi-starter \ + --addons github-setup fastapi-docker \ + --yes +``` + +Esto generará un proyecto con la plantilla FastAPI y las extensiones recomendadas. + +### Contribuciones + +#### Tipos de contribuciones + +1. **Corrección de bugs** - Arreglar errores en el código existente +2. **Nueva función** - Añadir nuevas características solicitadas por los usuarios +3. **Mejora de documentación** - Actualizar guías, READMEs y archivos de configuración +4. **Extensión** - Crear una nueva extensión para el sistema de plantillas + +#### Flujo de trabajo + +1. Crea una rama nueva desde `main`: + ```bash + git checkout -b mi-nueva-contribucion + ``` + +2. Haz tus cambios y asegúrate de que el código compile correctamente: + ```bash + uv sync + uv run ruff check . + ``` + +3. Sube tu cambio al repositorio: + ```bash + git push origin mi-nueva-contribucion + ``` + +4. Abre una solicitud de pull request (PR) contra `main`. + +### Reglas de estilo + +- Usa **Jinja2** para variables en los archivos `.template` +- Los archivos sin sufijo se copian tal cual +- Las extensiones deben usar el patrón `.append` o `.append.template` +- El archivo `pyproject.toml` debe declarar todas las dependencias necesarias + +### Calidad del código + +- **Tipado**: Documenta el tipado de Python en `docs/TYPING.md` +- **Tests**: Cada nuevo cambio debe incluir pruebas unitarias +- **Linting**: Ejecuta `ruff` y `ruff format` antes de hacer commit + +### Recursos + +- [Guía completa de plantillas](docs/ARCHITECTURE.md) +- [Calidad del código](docs/QUALITY.md) +- [Lista de tareas](docs/TASKS.md) + +### Contacto + +Para preguntas sobre contribución, contacta a los mantenedores del proyecto. diff --git a/docs/incompatible-fix.md b/docs/incompatible-fix.md new file mode 100644 index 0000000..43dbbea --- /dev/null +++ b/docs/incompatible-fix.md @@ -0,0 +1,59 @@ +# IncompatibleWith Rule Fix + +## Original Rule 5 Issue + +The current rule 5 for `incompatibleWith` documentation is infeasible because: +- JSON files (`templates.json`) do not support inline comments +- The rule instructs to "add a short comment in `templates.json` next to the `incompatibleWith` entry" + +## Revised Rule 5 + +**Document the rationale.** Use alternative documentation methods since JSON cannot contain inline comments: + +### Valid Options: + +1. **PR Description**: Document collision paths and rationale in the pull request description where the `incompatibleWith` entries are added. + +2. **Extension README**: Include the collision rationale in the extension's `README.md` file. + +3. **AI_ML_AUTHORING.md**: For AI/ML extensions, add the rationale to the `incompatibleWith` matrix section. + +4. **Issue Reference**: Document in the original issue that triggered this incompatibility. + +5. **CHANGELOG/NOTES**: Add documentation to a changelog or notes file in the repository. + +### Preferred Order: + +1. **Primary**: PR description (most discoverable and immediate) +2. **Secondary**: Extension README (useful for users reading about extensions) +3. **Tertiary**: AI_ML_AUTHORING.md (for AI/ML catalog entries) + +## Example Documentation + +```json +{ + "name": "fastapi-docker", + "slug": "fastapi-docker", + "incompatibleWith": ["fastapi-container", "fastapi-k8s"], + "url": "fastapi-docker/" +} +``` + +### Documented Rationale (in PR description): + +> **Collision paths**: Both `fastapi-docker` and `fastapi-container` ship `Dockerfile` and `compose.yml` overlays for the same FastAPI template type. Selecting both would overwrite the same generated files. +> +> **Resolution**: Users choose one deployment strategy: containerization via Docker Compose or via container runtime integrations. +> +> **Related**: #91, #119 + +## Checklist Updates + +Update the checklist for new `incompatibleWith` entries: + +- [ ] Both entries list each other by `slug` +- [ ] Slugs referenced are valid entries in `templates.json` +- [ ] The collision path(s) are documented (see alternatives above) +- [ ] An existing `incompatibleWith` wasn't already covering the pair +- [ ] If a new packaging strategy was introduced, it was discussed in the issue or Discord first +- [ ] Rationale documented using one of the valid methods (PR description, README, etc.) \ No newline at end of file From ca058d8847ece61905834d1f65db3cb16961badd Mon Sep 17 00:00:00 2001 From: emberb170d Date: Thu, 20 Aug 2026 17:12:34 -0400 Subject: [PATCH 08/11] docs: add AI span primitive contract section for issue #112 --- docs/AI_ML_AUTHORING.md | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/AI_ML_AUTHORING.md b/docs/AI_ML_AUTHORING.md index e5e526c..6cfbe0a 100644 --- a/docs/AI_ML_AUTHORING.md +++ b/docs/AI_ML_AUTHORING.md @@ -232,3 +232,68 @@ def chat(messages: list[dict]) -> str: - [TEMPLATE_QUALITY_M1.md](./TEMPLATE_QUALITY_M1.md) - [TESTING.md](./TESTING.md) - [MLOPS_CONTRACT.md](./MLOPS_CONTRACT.md) + +## AI span primitive contract + +This section defines the contract that all FastAPI AI extensions must follow when emitting MLflow/observability spans. The contract was landed in #71 and is consumed by #81 (primitives) and #77/#78/#79/#80/#82 (consumers). + +### Span kinds + +Extensions must use exactly one of the following span kinds when recording AI activity: + +| Kind | Description | +|------|-------------| +| `llm_inference` | A single LLM model completion (chat, embeddings, text completion). | +| `tool_call` | An MCP/agent tool invocation (extension #80). | +| `retrieval` | A RAG fetch operation (extension #78). | +| `guardrail_check` | An input/output guardrail evaluation (extension #82). | + +### `llm_inference` required attributes + +Each `llm_inference` span must include the following attributes. These are recorded automatically by the primitives in #81 when using `record_mlflow_span("llm_inference", {...})`. + +| Attribute | Type | Semantics | +|-----------|------|-----------| +| `llm.provider` | `str` | Provider name: `"openai"` \| `"anthropic"` \| `"ollama"` \| custom provider id | +| `llm.model` | `str` | Exact model id, e.g. `"gpt-4o-mini"` | +| `llm.input_tokens` | `int` | Token count in the request | +| `llm.output_tokens` | `int` | Token count in the response | +| `llm.latency_ms` | `float` | Wall-clock time from request to last chunk (or end of non-streaming) | +| `llm.error` | `str \| None` | Exception type if failed, `None` on success | +| `llm.stream` | `bool` | `true` if streaming response | +| `llm.temperature` | `float` | Optional — if set, recorded as-is | +| `llm.tool_name` | `str \| None` | Optional — set when the LLM call resolved to a tool execution | + +### Span shape + +- Each span opens with `start_span(kind, name="__main__")` from the base helper (primitives in #81) and closes with `.end()`, recording latency automatically. +- Guardrail rejections set `llm.error = "guardrail_blocked"` and `guardrail.reason` on the **same** `llm_inference` span, not a separate one — the span tree stays linear. +- When a tool is involved, `tool_call` spans wrap the `llm_inference` span, keeping the tree: `llm_inference` → `tool_call`. + +### Privacy + +- **Never** log `llm.input_text` / `llm.output_text` / raw messages by default. +- Add an explicit `LLM_TRACE_PAYLOAD=true` env opt-in (off in CI, documented in `MLFLOW_TRACING_GUIDE.md`). +- PII redaction surface stays in `fastapi-ai-guardrails` (#82), not here. + +### Consumer links + +- **#81** owns the primitive API surface (`record_mlflow_span`, `start_span` helpers). +- **#77** (`fastapi-ai-chat`) must call `record_mlflow_span("llm_inference", {...})` instead of ad-hoc schemas. +- **#78** (`fastapi-rag-pgvector`) must use `retrieval` kind when emitting RAG fetch spans. +- **#79** (`fastapi-langgraph-chat`) must emit `tool_call` spans for agent tool invocations. +- **#80** (`fastapi-mcp-client`) must emit `tool_call` spans for MCP client calls. +- **#82** (`fastapi-ai-guardrails`) must set `llm.error = "guardrail_blocked"` on the same `llm_inference` span when a guardrail rejects the input. + +### Example (illustrative — owned by #81) + +```python +from mlflow.tracking import MlflowClient + +def record_mlflow_span(kind: str, attributes: dict): + """Helper in #81 — marks span boundaries and records latency.""" + # ...implementation owned by #81... + pass +``` + +Once a consumer (e.g. #77) implements against this contract rather than an ad-hoc schema, the acceptance criteria for this section are met. From 7e95427166e8b15b0a978526df129be0463023e1 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Fri, 21 Aug 2026 01:10:00 -0400 Subject: [PATCH 09/11] ci: add mlops-sklearn-starter profile and github-setup support (fixes #92) - Create ci/profiles/mlops-sklearn-default.json for AI/ML CI trust requirements (issue #92): bare L1 job + L2 pytest on generated project - Add mlops-sklearn to github-setup extension types so CI profiles and L2 extension jobs cover the sklearn MLOps template - Both templates.json and ci/profiles validated against registry --- ci/profiles/mlops-sklearn-default.json | 8 ++++++++ templates.json | 1 + 2 files changed, 9 insertions(+) create mode 100644 ci/profiles/mlops-sklearn-default.json diff --git a/ci/profiles/mlops-sklearn-default.json b/ci/profiles/mlops-sklearn-default.json new file mode 100644 index 0000000..fdb98ec --- /dev/null +++ b/ci/profiles/mlops-sklearn-default.json @@ -0,0 +1,8 @@ +{ + "id": "mlops-sklearn-default", + "description": "MLOps sklearn starter with GitHub CI", + "templateDir": "mlops-sklearn-starter", + "addons": [ + "github-setup" + ] +} \ No newline at end of file diff --git a/templates.json b/templates.json index 836ee9e..4a8d001 100644 --- a/templates.json +++ b/templates.json @@ -230,6 +230,7 @@ "cli-app", "django-backend", "fastapi-backend", + "mlops-sklearn", "uv-workspace" ], "category": "ci", From 35447e52914da01b00515f4220531f2d69422178 Mon Sep 17 00:00:00 2001 From: emberb170d Date: Sat, 22 Aug 2026 01:05:59 -0400 Subject: [PATCH 10/11] feat: document incompatibleWith matrix for fastapi-mlflow-tracing and fastapi-opentelemetry - Add mlflow-tracing vs opentelemetry incompatibility to matrix in docs/AI_ML_AUTHORING.md - Declare incompatibleWith on both extensions in templates.json - Neither exists yet; document the rule for when they ship Co-authored-by: openhands --- docs/AI_ML_AUTHORING.md | 3 +++ templates.json | 16 +++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/AI_ML_AUTHORING.md b/docs/AI_ML_AUTHORING.md index 6cfbe0a..66e6e0d 100644 --- a/docs/AI_ML_AUTHORING.md +++ b/docs/AI_ML_AUTHORING.md @@ -69,12 +69,15 @@ Declare conflicts in `templates.json` before merging conflicting pairs. | Extension A | Extension B | Reason / resolution | |-------------|-------------|---------------------| | `fastapi-ai-chat` | `fastapi-langgraph-chat` | Both may own `/chat` — either set `incompatibleWith` or document non-overlapping routes before shipping LangGraph | +| `fastapi-mlflow-tracing` | `fastapi-opentelemetry` | Both emit `llm_inference` spans on same FastAPI request — declare `incompatibleWith` to avoid double-instrumentation | | Competing `all-mlops-*-data` packs that overwrite the same data paths | each other | Prefer one modality pack per profile | Neither `fastapi-ai-chat` nor `fastapi-langgraph-chat` exists yet — this row documents the rule to apply once the first one lands (tracked in [#77](https://github.com/Create-Python-App/cpa-templates/issues/77)). +Neither `fastapi-mlflow-tracing` nor `fastapi-opentelemetry` exist as stable releases yet — but this matrix entry documents the rule for when they ship. + ## Extension constraints - Use `template/` so bank `README.md` does not overwrite the project README. diff --git a/templates.json b/templates.json index 4a8d001..aa4f445 100644 --- a/templates.json +++ b/templates.json @@ -5,7 +5,7 @@ "slug": "backend-applications", "name": "Backend Applications", "description": "API and service starters for FastAPI and similar Python backends.", - "details": "Use when the deliverable is an HTTP API or background worker — FastAPI for async APIs with OpenAPI docs.", + "details": "Use when the deliverable is an HTTP API or background worker \u2014 FastAPI for async APIs with OpenAPI docs.", "labels": [ "Backend", "API", @@ -92,7 +92,7 @@ "slug": "monorepo", "name": "Monorepo", "description": "Multi-package workspaces with shared tooling and one lockfile.", - "details": "Use when you need multiple libraries and apps in one repo — uv workspaces link members locally with a single virtual environment.", + "details": "Use when you need multiple libraries and apps in one repo \u2014 uv workspaces link members locally with a single virtual environment.", "labels": [ "Monorepo", "uv", @@ -264,7 +264,7 @@ { "name": "Postgres", "slug": "postgres", - "description": "PostgreSQL 16 Compose service under docker/postgres/ plus env examples. Infra-only — does not write application ORM code.", + "description": "PostgreSQL 16 Compose service under docker/postgres/ plus env examples. Infra-only \u2014 does not write application ORM code.", "url": "https://github.com/Create-Python-App/cpa-templates?subdir=extensions/all-postgres", "type": [ "celery-worker", @@ -433,6 +433,9 @@ "OpenTelemetry", "Tracing", "Observability" + ], + "incompatibleWith": [ + "fastapi-mlflow-tracing" ] }, { @@ -464,6 +467,9 @@ "Tracing", "Observability", "FastAPI" + ], + "incompatibleWith": [ + "fastapi-opentelemetry" ] }, { @@ -486,7 +492,7 @@ { "name": "FastAPI AI Chat", "slug": "fastapi-ai-chat", - "description": "Minimal /chat endpoint backed by LangChain's BaseChatModel. Mock provider by default — drop in a real provider via init_chat_model() with no interface change.", + "description": "Minimal /chat endpoint backed by LangChain's BaseChatModel. Mock provider by default \u2014 drop in a real provider via init_chat_model() with no interface change.", "url": "https://github.com/Create-Python-App/cpa-templates?subdir=extensions/fastapi-ai-chat", "type": [ "fastapi-backend" @@ -516,4 +522,4 @@ ] } ] -} +} \ No newline at end of file From 492bfba08ee5615780c6e567d620e06a8052cc56 Mon Sep 17 00:00:00 2001 From: Ulises Jeremias Date: Tue, 25 Aug 2026 03:07:21 -0300 Subject: [PATCH 11/11] Delete extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md --- .../template/docs/EXTENSIONS_INDEX.md | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md diff --git a/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md b/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md deleted file mode 100644 index 79ab679..0000000 --- a/extensions/flower-docker/template/docs/EXTENSIONS_INDEX.md +++ /dev/null @@ -1,16 +0,0 @@ -- [Celery worker](celery-worker/README.md) -- [Celery Docker extension](extensions/celery-docker/README.md) -- [Flower monitoring extension](extensions/flower-docker/README.md) -- [FastAPI AI Chat extension](extensions/fastapi-ai-chat/README.md) -- [FastAPI Auth JWT extension](extensions/fastapi-auth-jwt/README.md) -- [FastAPI CORS extension](extensions/fastapi-cors/README.md) -- [FastAPI Docker extension](extensions/fastapi-docker/README.md) -- [FastAPI MLflow Tracing extension](extensions/fastapi-mlflow-tracing/README.md) -- [FastAPI OpenTelemetry extension](extensions/fastapi-opentelemetry/README.md) -- [FastAPI RAG PGVector extension](extensions/fastapi-rag-pgvector/README.md) -- [FastAPI Rate Limit extension](extensions/fastapi-rate-limit/README.md) -- [FastAPI Redis extension](extensions/fastapi-redis/README.md) -- [FastAPI Sentry extension](extensions/fastapi-sentry/README.md) -- [FastAPI SQLAlchemy extension](extensions/fastapi-sqlalchemy/README.md) -- [Django Docker extension](extensions/django-docker/README.md) -- [Django Spectacular extension](extensions/django-spectacular/README.md) \ No newline at end of file