agentleFS
pavelzbornikpavelzbornik/whisperX-FastAPI/CLAUDE.md

whisperX-FastAPI

CLAUDE.md188 starsChanged 7 months agoMITArchived repositoryView on GitHub

whisperX-FastAPI is a REST API built with FastAPI that provides async audio/video transcription, alignment, speaker diarization, and transcript combination using WhisperX. Tasks are processed as background jobs with results tracked in a database. All developer commands are defined in Taskfile.yml (with includes in taskfiles/). Run task --list to see all available tasks. go-task is installed automatically via the devcontainer feature. Layered Architecture with Repository Pattern and Dependency Injection Container (dependency-injector library). Each folder below has its own CLAUDE.md with layer-specific…

  • Reads credentials

We split this CLAUDE.md into the rules it gives an agent

29 rules. About 0 are common, 18 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈18

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    All developer commands are defined in Taskfile.yml (with includes in taskfiles/).

    line 16
  2. Very specific:

    Run task --list to see all available tasks.

    line 17
  3. Very specific:

    Create a .env file in the repo root:

    line 98
  4. Very specific:

    Critical: When DEVICE=cpu, COMPUTE_TYPE is auto-corrected to int8.

    line 123
  5. Distinctive:

    When a request is ambiguous, present the possible interpretations and ask which is intended.

    line 156
  6. Distinctive:

    Stop when confused. Name what's unclear and ask for clarification.

    line 158
  7. Distinctive:

    No features beyond what was asked.

    line 165
  8. Distinctive:

    No abstractions for single-use code.

    line 166
  9. Distinctive:

    No speculative "flexibility" or "configurability" that wasn't requested.

    line 167
  10. Distinctive:

    No error handling for impossible scenarios.

    line 168
  11. Distinctive:

    If the code you're writing could be 50 lines instead of 200, write the 50.

    line 169
  12. Distinctive:

    Don't "improve" adjacent code, comments, or formatting.

    line 174
  13. Distinctive:

    Don't refactor things that aren't broken.

    line 175
  14. Distinctive:

    If you notice unrelated dead code, mention it — don't delete it.

    line 177
  15. Very specific:

    Remove imports/variables/functions that your changes made unused.

    line 178
  16. Distinctive:

    Don't remove pre-existing unused code unless asked.

    line 179
  17. Distinctive:

    Follow Test-Driven Development for all new features and bug fixes:

    line 183
  18. Distinctive:

    All new code must have tests written before implementation

    line 195
  19. Very specific:

    Run task test after every change — ensure coverage ≥80% overall

    line 196
  20. Very specific:

    Check coverage gaps proactively: uv run pytest --cov=app --cov-report=term-missing

    line 198
  21. Distinctive:

    Never commit untested code paths — if you wrote it, test it first

    line 199
  22. Very specific:

    Use factories (tests/factories/) over inline object construction

    line 206
  23. Very specific:

    Use mocks (tests/mocks/) — extend existing mocks rather than adding conditional logic

    line 207
  24. Distinctive:

    Write a test that reproduces the bug (must fail)

    line 211
  25. Very specific:

    Check no regressions: task test

    line 214
  26. Distinctive:

    When modifying file contents (especially Markdown/YAML frontmatter), validate that existing fields are preserved

    line 218
  27. Distinctive:

    Never replace entire file contents when only a section needs updating

    line 220
  28. Very specific:

    Before creating a PR, run: task check (lint + format + typecheck) and task test

    line 226
  29. Distinctive:

    Verify coverage meets threshold before pushing, not after CI fails

    line 229

≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

Project Guide

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

whisperX-FastAPI is a REST API built with FastAPI that provides async audio/video transcription, alignment, speaker diarization, and transcript combination using WhisperX. Tasks are processed as background jobs with results tracked in a database.

  • Package manager: uv — always use uv run for all Python commands
  • Database: SQLAlchemy ORM (default: SQLite, configurable via DB_URL)
  • Container runtime: Docker with NVIDIA CUDA (CPU fallback supported)
  • See pyproject.toml for exact Python and dependency versions.

Commands

All developer commands are defined in Taskfile.yml (with includes in taskfiles/). Run task --list to see all available tasks. go-task is installed automatically via the devcontainer feature.

Install dependencies

task deps              # includes dev tools (linters, tests)
task deps:prod         # production only

Run locally

task run

Run with Docker

task docker:restart    # stop, start, follow logs
task docker:up         # start in background
task docker:down       # stop
task docker:logs       # follow logs

Test

task test              # all tests with coverage (CI requires ≥80%)
task test:unit         # unit tests only
task test:fast         # exclude slow and load markers
task test:ci           # full CI command with XML reports

# Single test file (use uv directly)
uv run pytest tests/unit/domain/entities/test_task.py

Lint and format

task lint              # ruff check --fix
task format            # ruff format
task typecheck         # mypy app/
task check             # all three sequentially
task pre-commit        # run all pre-commit hooks

Dependency changes

task deps:lock         # regenerate uv.lock + sync

Architecture

Layered Architecture with Repository Pattern and Dependency Injection Container (dependency-injector library). Each folder below has its own CLAUDE.md with layer-specific guidance.

app/
├── main.py                    # FastAPI app, lifespan, health endpoints, router registration
├── api/                       # HTTP layer: routers, schemas, mappers, DI wiring
│   ├── audio_api.py           # Speech-to-text (full pipeline) endpoints
│   ├── audio_services_api.py  # Individual service endpoints (transcribe/align/diarize)
│   ├── task_api.py            # Task management endpoints
│   ├── dependencies.py        # Injects services from Container via Depends()
│   ├── schemas/               # Pydantic request/response models
│   ├── mappers/               # API schema ↔ domain entity conversion
│   └── exception_handlers.py  # Maps domain exceptions → HTTP responses
├── core/                      # Config, DI Container, exception hierarchy → see app/core/CLAUDE.md
├── domain/                    # Pure Python entities, repository + ML service interfaces → see app/domain/CLAUDE.md
├── infrastructure/            # SQLAlchemy + WhisperX implementations → see app/infrastructure/CLAUDE.md
└── services/                  # Business logic orchestration → see app/services/CLAUDE.md

tests/                         # Markers, mocks, factories, coverage → see tests/CLAUDE.md
docs/                          # ADRs, stories, config migration guide → see docs/CLAUDE.md

Environment Variables

Create a .env file in the repo root:

HF_TOKEN=<huggingface-token>     # required for diarization model downloads
WHISPER_MODEL=tiny               # tiny/base/small/medium/large/distil-*
DEFAULT_LANG=en
DEVICE=cuda                      # cuda or cpu
COMPUTE_TYPE=float16             # float16/float32/int8 — MUST be int8 when DEVICE=cpu
LOG_LEVEL=INFO
ENVIRONMENT=production
DB_URL=sqlite:///records.db
MAX_CONCURRENT_GPU_TASKS=1          # max simultaneous GPU tasks (prevents OOM)

# API protection (all no-op by default — see app/core/config.py)
MAX_UPLOAD_SIZE_MB=0               # 413 over this many MB; 0 = unlimited
MAX_QUEUED_GPU_REQUESTS=0         # 503 when in-flight GPU requests exceed cap; 0 = unlimited
SYNC_GPU_QUOTA_FRACTION=0.5       # share of MAX_QUEUED_GPU_REQUESTS for the sync (/v1/audio/*) path
RATE_LIMIT__ENABLED=false         # slowapi per-caller limiting → 429 + Retry-After
RATE_LIMIT__REQUESTS_PER_MINUTE=60
RATE_LIMIT__BURST=10
RATE_LIMIT__KEY_STRATEGY=ip       # ip | bearer_token
AUTH__ENABLED=false               # shared bearer-token auth → 401
AUTH__BEARER_TOKEN=               # required when AUTH__ENABLED=true

Critical: When DEVICE=cpu, COMPUTE_TYPE is auto-corrected to int8. Tests set DEVICE=cpu and COMPUTE_TYPE=int8 automatically.

API protection (rate limiting, upload cap, route concurrency caps, bearer auth) lives in app/core/{rate_limit,concurrency}.py, app/api/{middleware,security}.py, and is wired in main.py. Knobs come from get_settings() (loaded from env/.env at startup and lru_cache-backed), so they are fixed for the life of the process and stay no-op until enabled — changing them needs a restart (tests clear the caches to re-read). The upload cap is enforced from Content-Length; the async concurrency gate is admission control (the background GPU pipeline is bounded by MAX_CONCURRENT_GPU_TASKS). Multi-worker deployments give each worker its own in-process budget.

CI Pipeline

.github/workflows/CI.yaml triggers on PRs and pushes to main/dev when app/, tests/, dockerfile, docker-compose.yml, or pyproject.toml change.

Jobs: lint → test (≥80% coverage) → dependency-review + build (Docker + Trivy scan) → release-please (main only).

Dependency updates (uv packages, GitHub Actions, Docker images, pre-commit hooks) are managed by Renovate (renovate.json), batched monthly. ML-critical packages (PyTorch, huggingface-hub, whisperx) require manual review; minor/patch updates for all other groups auto-merge after CI passes.

PyTorch wheels: uv.lock is platform-specific (CUDA on Linux x86_64, CPU on macOS/Windows). Never manually edit uv.lock.

Coding Discipline

Think Before Coding

  • State assumptions explicitly before writing code. If uncertain, ask rather than guess.
  • When a request is ambiguous, present the possible interpretations and ask which is intended.
  • Push back when a simpler approach exists — suggest it before building the complex one.
  • Stop when confused. Name what's unclear and ask for clarification.
  • Frame tasks as goals with verification checkpoints — "add validation" becomes "write tests for invalid inputs, then make them pass"; "refactor X" becomes "ensure tests pass before and after". For multi-step tasks, state a plan before starting.

Simplicity First

  • No features beyond what was asked.
  • No abstractions for single-use code.
  • No speculative "flexibility" or "configurability" that wasn't requested.
  • No error handling for impossible scenarios.
  • If the code you're writing could be 50 lines instead of 200, write the 50. (Applies to new code — see Surgical Changes for existing code.)

Surgical Changes

  • Don't "improve" adjacent code, comments, or formatting.
  • Don't refactor things that aren't broken.
  • Match existing style, even if you'd do it differently.
  • If you notice unrelated dead code, mention it — don't delete it.
  • Remove imports/variables/functions that your changes made unused.
  • Don't remove pre-existing unused code unless asked.

Testing — TDD Process

Follow Test-Driven Development for all new features and bug fixes:

TDD Workflow

  1. Write failing tests first — before writing any implementation code, write tests that define the expected behavior. Run them to confirm they fail.
  2. Implement the minimum code to make the tests pass — no more, no less.
  3. Refactor — clean up the implementation while keeping tests green.
  4. Repeat for each new behavior or code path.

Coverage Rules

  • All new code must have tests written before implementation
  • Run task test after every change — ensure coverage ≥80% overall
  • Target >80% coverage on new code specifically (SonarCloud new code gate)
  • Check coverage gaps proactively: uv run pytest --cov=app --cov-report=term-missing
  • Never commit untested code paths — if you wrote it, test it first

Test Organization

  • Unit tests (tests/unit/) for isolated logic — mock all external deps
  • E2e tests (tests/e2e/) for API endpoints — test full request/response cycle
  • Integration tests (tests/integration/) for real DB or service interaction
  • Use factories (tests/factories/) over inline object construction
  • Use mocks (tests/mocks/) — extend existing mocks rather than adding conditional logic

When Fixing Bugs

  1. Write a test that reproduces the bug (must fail)
  2. Fix the bug
  3. Confirm the test passes
  4. Check no regressions: task test

Data Integrity

  • When modifying file contents (especially Markdown/YAML frontmatter), validate that existing fields are preserved
  • Never replace entire file contents when only a section needs updating
  • For batch operations, process in small batches with validation between each
  • See also Surgical Changes above for scope discipline when modifying code.

PR Workflow

  • Before creating a PR, run: task check (lint + format + typecheck) and task test
  • Address style violations proactively — check for unused imports, consistent naming (str | None not Optional[str]), and docstrings on public methods
  • Verify coverage meets threshold before pushing, not after CI fails

PR titles must be Conventional Commits

The .github/workflows/pr-title-lint.yml workflow (added in #539) enforces Conventional Commits for every PR title via amannn/action-semantic-pull-request. The PR will fail CI if the title doesn't match.

Why it matters: PRs are squash-merged, so the PR title becomes the merge commit subject on the target branch. release-please parses those subjects on main to decide the version bump and to build the changelog — a non-conventional title (e.g. Dev) flattens everything behind a single unrecognized commit and the release detection breaks.

Allowed types: feat:, fix:, chore:, docs:, refactor:, test:, ci:, build:, perf:, style:, revert: (the action-semantic-pull-request defaults). Use a scope when useful — e.g. feat(security): ..., fix(api): ..., chore(deps): .... Mark breaking changes with ! (e.g. feat(api)!: ...).

The dev → main release PR is also subject to this rule: title it with a conventional prefix (e.g. feat: … or chore(main): release X.Y.Z) so release-please can detect it after the squash. Do not title it Dev.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.