# Vibetuner
> Vibetuner is a production-ready FastAPI project scaffolding tool that generates full-stack web applications with authentication, flexible database support (MongoDB or SQL), frontend, Docker deployment, and CLI tools pre-configured in seconds. Built by All Tuner Labs for rapid iteration and modern development.
Important notes:
- Vibetuner consists of four packages: a Python framework (`vibetuner`), a JavaScript build-deps package (`@alltuner/vibetuner`) which bundles tailwind, daisyui, htmx and an npm-shipped mirror of the framework's jinja templates (`@alltuner/vibetuner-jinja`, pulled in as a transitive — consumers don't install it directly), and a Copier scaffolding template
- The framework separates immutable framework code (`vibetuner` package) from your application code (`src/app/`) for clean updates
- In all examples, `app` refers to your project's Python package (the directory under `src/`). The actual name depends on your project slug (e.g., `src/myproject/` for a project named "myproject")
- HTMX is used instead of React/Vue for simplicity - server-rendered HTML with sprinkles of interactivity
- All tools are chosen for speed: uv (Python), bun (JavaScript), Granian (ASGI server), Ruff (linting)
- The project is designed to work excellently with AI coding assistants like Claude, Cursor, and ChatGPT
## Quick Start
- [Quick Start Guide](https://vibetuner.alltuner.com/quick-start/): Get started with Vibetuner in 5 minutes
- [Installation](https://vibetuner.alltuner.com/installation/): Prerequisites and installation options
- [Your First Project](https://vibetuner.alltuner.com/quick-start/#create-your-first-project): Interactive project setup with `uvx vibetuner scaffold new`
## Core Documentation
- [Development Guide](https://vibetuner.alltuner.com/development-guide/): Daily development workflow, adding routes, models, templates, and background jobs
- [Architecture](https://vibetuner.alltuner.com/architecture/): System design, four-package architecture, request flow, and core components
- [Tech Stack](https://vibetuner.alltuner.com/tech-stack/): Detailed information about all technologies used and why they were chosen
- [Authentication](https://vibetuner.alltuner.com/authentication/): OAuth and magic link authentication setup and configuration
- [Background Tasks](https://vibetuner.alltuner.com/background-tasks/): Background task system powered by Streaq and Redis with retries, cron scheduling, and SSE integration
- [Runtime Configuration](https://vibetuner.alltuner.com/runtime-config/): Layered configuration system with MongoDB persistence, debug UI, and feature flags
- [HTMX v2 to v4 Migration](https://vibetuner.alltuner.com/htmx-migration/): Breaking changes and migration guide for upgrading from HTMX v2 to v4
- [Theming](https://vibetuner.alltuner.com/theming/): Build-time brand palette via cascade override of DaisyUI's `[data-theme="…"]` selectors in `config.css` (no consumer-side `daisyui` dep needed), plus runtime per-tenant overrides via the embedded `TenantTheme` model + opt-in `register_tenant_theme_provider()` helper + shipped `base/theme.html.jinja` partial that injects DaisyUI role-color overrides at request time
## Features
- **HTMX Request Detection**: `request.state.htmx` available on every request
(via `starlette-htmx` middleware). Properties: `.boosted`, `.target`, `.trigger`,
`.trigger_name`, `.current_url`, `.prompt`. Use `require_htmx` dependency from
`vibetuner.frontend.deps` to reject non-HTMX requests with 400
- **CRUD Factory**: `create_crud_routes()` generates list/create/read/update/delete
endpoints for Beanie models with pagination, filtering, sorting, and search
- **SSE Helpers**: `@sse_endpoint()` and `broadcast()` for real-time streaming with
HTMX. Import from `vibetuner.sse`. Redis pub/sub for multi-worker support
- **`@render` Decorator**: `@render("template.html.jinja")` eliminates
`render_template()` boilerplate — route returns a dict, decorator handles rendering.
Returns `Response` objects unchanged (escape hatch). Import from `vibetuner`
- **Streaming HTML**: `render_template_stream()` returns a `StreamingResponse` using
Jinja2's `generate()`, improving TTFB for large pages. Same context merging as
`render_template()`. Import from `vibetuner`
- **Block Rendering**: `render_template_block(template, block_name, request, ctx)`
renders a single `{% block %}` for HTMX partials. `render_template_blocks()` renders
multiple blocks for OOB swaps. No extra dependencies. Import from `vibetuner`
- **Context kwarg**: `render_template*` accepts the user context positionally, as
`ctx=`, or as `context=` (alias for `ctx=`). Passing both, or any unknown kwarg,
raises `TypeError` — typos cannot silently render with an empty context
- **`@cache` Decorator**: `@cache(expire=60)` caches route responses in Redis.
Key derived from path + query params. Use `vary_on=lambda r: str(r.state.user.id)`
for request-dependent keys (per-user, per-tenant). Disabled in debug mode
(override with `force_caching=True`). No-op if Redis unavailable.
`invalidate(path)` and `invalidate_pattern(path)` for cache busting.
Import from `vibetuner.cache`
- **`@cache_control` Decorator**: `@cache_control(max_age=300, public=True)` sets
`Cache-Control` headers declaratively. Supports `public`, `private`, `no_cache`,
`no_store`, `max_age`, `s_maxage`, `must_revalidate`, `stale_while_revalidate`,
`immutable`. Import from `vibetuner.decorators`
- **HTMX Response Helpers**: `hx_redirect()`, `hx_location()`, `hx_trigger()`,
`hx_push_url()`, `hx_reswap()`, `hx_retarget()`, `hx_refresh()`,
`hx_replace_url()`, `hx_trigger_after_settle()`, `hx_trigger_after_swap()`.
Handles JSON serialization internally. Import from `vibetuner.htmx`
- **Built-in Template Globals**: `request`, `language`, `DEBUG`, `now`
(UTC datetime), `today` (ISO date string), `project` (`settings.project`),
`brand` (`settings.brand`), `csp_nonce`, and `hotreload` are available
in all templates automatically
- **Skeleton Extension Points**: `base/skeleton.html.jinja` exposes blocks
(`extra_head_links`, `extra_scripts`, `before_main`, `after_main`) and
context variables (`color_scheme`, `canonical_url`, `font_preloads`) so
projects can extend instead of wholesale-overriding the skeleton —
upstream changes (CSP nonce, theming, etc.) flow through automatically
- **Brand Configuration**: `BRAND_PRIMARY_COLOR`, `BRAND_BROWSER_THEME_COLOR`,
`BRAND_EMAIL_BUTTON_COLOR` env vars drive favicon meta tags, the PWA
manifest's `theme_color`/`background_color`, and the magic-link email button
— surfaces where DaisyUI/CSS-variable theming can't reach (favicon meta
is read before CSS runs; email clients ignore CSS variables). Accepts
pydantic-Color inputs (named, `rgb()`, hex). For per-tenant in-page
colors use `TenantTheme`; `BrandSettings` is deliberately app-level
- **Encrypted Fields**: `EncryptedFieldsMixin` and `EncryptedStr` type for
transparent Fernet encrypt-on-save / decrypt-on-load on any Beanie model field.
Import from `vibetuner.models.mixins`. Requires `FIELD_ENCRYPTION_KEY` env var
- **Template Context Providers**: `register_globals()` and `@register_context_provider`
inject variables into every template render
- **Per-Tenant Theming**: `TenantTheme` embedded model (`vibetuner.models.TenantTheme`)
with eight optional `#rrggbb` fields for DaisyUI role / role-content colors plus
`.overrides()` for the `{css_var: hex}` map. Wire it up with
`register_tenant_theme_provider(getter)` from `vibetuner` — opt-in, runs on every
render, fail-soft. Vibetuner's `base/skeleton.html.jinja` already includes
`base/theme.html.jinja`, which emits a CSP-noncified ``
block after `bundle.css`. `bundle.css` stays tenant-agnostic and cached
- **i18n Primitives**: `vibetuner.i18n` ships
`register_locale_resolver(getter, *, priority=0)` to inject custom selectors
at the front of `LocaleMiddleware`'s chain (per-tenant locale becomes a
one-liner), `set_request_language(request, code)` to update both the Babel
context and `request.state.language` in one call, and `language_picker(display_locale=None)`
returning `[{code, name}]` with names rendered in the current request's locale
(browsing in Spanish gives "inglés / español / catalán"; never English-only).
`language_picker` is also registered as a Jinja global so templates can call
it directly without overriding any existing template variable
- **Framework Translation Catalogs**: vibetuner ships compiled
`.mo` files under `vibetuner/locales//LC_MESSAGES/messages.mo`
(currently `en`, `ca`). `frontend/middleware.py` loads them before the
project's own `locales/` so framework templates (`login.html.jinja`,
`user/profile.html.jinja`, etc.) render in the active locale with no
per-app extraction. App catalogs loaded after the framework override
framework strings on collision via gettext domain merging. Add a new
framework locale with `just new-framework-locale ` then
`just compile-framework-locales`
- **Service DI**: `get_email_service()`, `get_blob_service()`, `get_runtime_config()`
FastAPI dependency wrappers
- **Email Providers**: Pluggable transactional email via Resend
(`MAIL_RESEND_API_KEY`), Mailjet (`MAIL_MAILJET_API_KEY` +
`MAIL_MAILJET_API_SECRET`), or Cloudflare Email Service
(`MAIL_CLOUDFLARE_API_TOKEN` + `MAIL_CLOUDFLARE_ACCOUNT_ID`). Auto-detected
from available credentials; `MAIL_PROVIDER=resend|mailjet|cloudflare` to
pick explicitly. Auto-detection priority: resend > mailjet > cloudflare
- **CSP Nonce Auto-Injection**: `SecurityHeadersMiddleware` generates a unique CSP nonce
per request and auto-injects it into all `