A personal song lyric rewriter. Edit and refine your lyrics with AI -- workshop them into something that actually sounds like you.
Powered by any-llm -- routed through a single LLM gateway.
porchsongs preserves meter, rhyme scheme, chord alignment, and emotional meaning -- it only swaps out the imagery that doesn't fit.
Try It Live
porchsongs.ai is the hosted version of porchsongs. Sign in with Google, pick a plan, and start rewriting. No setup, no API keys to manage.
If you prefer to self-host or want to point porchsongs at your own LLM gateway, follow the Quick Start below.
How It Works
- Paste your lyrics -- with or without chords, any format works
- Chat to workshop the lyrics -- tell the AI what to change ("swap the truck for my bike," "make verse 2 about coding") and iterate in a live conversation
- Play and enjoy -- chords are automatically realigned above your new lyrics
Quick Start
pip install uv uv sync cd frontend && npm install && npm run build && cd .. cd backend LLM_API_BASE=https://your-gateway/v1 LLM_API_KEY=your-key \ uv run uvicorn app.main:app --reload
Open http://localhost:8000. porchsongs routes all AI traffic
through a single LLM gateway; set LLM_API_BASE and LLM_API_KEY (see the
environment variables below), then pick a model in Settings.
By default, porchsongs runs in zero-config dev mode -- no login required, a local user is auto-created. See Authentication below for production setups.
For frontend development with hot reload:
# Terminal 1: backend cd backend && uv run uvicorn app.main:app --reload # Terminal 2: frontend (proxies /api to backend) cd frontend && npm run dev
Docker
cp .env.example .env
# Edit .env -- set JWT_SECRET to a long random string
docker compose up --buildThis starts PostgreSQL + runs database migrations + serves the app on port 8000.
Authentication
porchsongs supports three auth modes, controlled by environment variables:
Zero-config dev mode (default)
No env vars needed. The app is open to anyone who can reach it. A local user is auto-created.
Single-user password protection
Set APP_SECRET to gate the app behind a password:
APP_SECRET=your-secret-password JWT_SECRET=a-long-random-string-at-least-32-chars
You can also use a bcrypt hash for APP_SECRET:
# Generate a hash python3 -c "import bcrypt; print(bcrypt.hashpw(b'mypassword', bcrypt.gensalt()).decode())" # Use it in .env APP_SECRET='$2b$12$...'
Premium plugin
For Google OAuth and other premium features, see the porchsongs-premium repo.
PREMIUM_PLUGIN=porchsongs_premium.plugin
Database
porchsongs uses PostgreSQL everywhere (production, development, and testing).
# Production (set in .env or environment) DATABASE_URL=postgresql://porchsongs:porchsongs@localhost:5432/porchsongs # Local dev / testing DATABASE_URL=postgresql://postgres:postgres@localhost:5432/porchsongs_test # Quick PostgreSQL setup via Docker docker run --name porchsongs-pg -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=porchsongs_test -p 5432:5432 -d postgres:16 # Apply migrations uv run alembic upgrade head
Docker Compose includes a PostgreSQL service and runs migrations automatically on startup.
Environment Variables
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
postgresql://...localhost.../porchsongs |
Database connection string |
JWT_SECRET |
change-me-in-production |
Secret for signing JWT tokens (use 32+ chars) |
AUTH_BACKEND |
app_secret |
Auth mode: app_secret (premium plugins can add others) |
APP_SECRET |
(none) | Password gate (app_secret mode). Supports plaintext or bcrypt hash |
CORS_ORIGINS |
* |
Allowed CORS origins (comma-separated) |
JWT_EXPIRY_MINUTES |
15 |
Access token lifetime |
REFRESH_TOKEN_DAYS |
30 |
Refresh token lifetime |
PREMIUM_PLUGIN |
(none) | Module path for premium auth backend |
LLM_API_BASE |
(none) | LLM gateway base URL (OpenAI-compatible, e.g. https://your-gateway/v1). Required for AI features |
LLM_API_KEY |
(none) | LLM gateway API key (read server-side, never sent to the browser) |
LLM_PROVIDER |
otari |
any-llm provider name for the gateway |
See .env.example for the full list.
Testing
# Backend tests (118 tests) uv run pytest uv run pytest -v # verbose uv run pytest tests/test_auth.py # auth tests only # Frontend tests (39 tests) cd frontend && npx vitest run # Lint & type check uv run ruff check backend/ uv run ruff format --check backend/ cd frontend && npx eslint src/ cd frontend && npm run typecheck
LLM gateway -- Powered by any-llm
porchsongs routes all AI traffic through a single LLM gateway using any-llm. Point LLM_API_BASE / LLM_API_KEY at any OpenAI-compatible gateway (an Otari deployment by default) and pick a model in Settings; the model catalog is discovered from the gateway. Keys live only on the server and are never sent from the browser.
| Website | any-llm.ai |
| GitHub | mozilla-ai/any-llm |
Routing everything through one gateway gives porchsongs:
- One place to manage credentials, models, and spend -- no per-provider keys in the app
- Model discovery -- the Settings model picker is populated from the gateway's catalog
- Consistent interface -- streaming, async, and reasoning work the same regardless of the model behind the gateway
Bring your own API key, configure it in Settings, and start rewriting.
