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 -- use any LLM provider you want.
porchsongs preserves meter, rhyme scheme, chord alignment, and emotional meaning -- it only swaps out the imagery that doesn't fit.
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 full control over your LLM provider, follow the Quick Start below.
- 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
pip install uv
uv sync
cd frontend && npm install && npm run build && cd ..
cd backend
uv run uvicorn app.main:app --reloadOpen http://localhost:8000. Configure your LLM API key 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 devcp .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.
porchsongs supports three auth modes, controlled by environment variables:
No env vars needed. The app is open to anyone who can reach it. A local user is auto-created.
Set APP_SECRET to gate the app behind a password:
APP_SECRET=your-secret-password
JWT_SECRET=a-long-random-string-at-least-32-charsYou 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$...'For Google OAuth and other premium features, see the porchsongs-premium repo.
PREMIUM_PLUGIN=porchsongs_premium.pluginporchsongs uses PostgreSQL in production and SQLite for local development/testing.
# Production (set in .env or environment)
DATABASE_URL=postgresql://porchsongs:porchsongs@localhost:5432/porchsongs
# Local dev with SQLite
DATABASE_URL=sqlite:///dev.db
# Apply migrations
uv run alembic upgrade headDocker Compose includes a PostgreSQL service and runs migrations automatically on startup.
| 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 |
OPENAI_API_KEY |
(none) | OpenAI API key |
ANTHROPIC_API_KEY |
(none) | Anthropic API key |
See .env.example for the full list.
# 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 typecheckporchsongs uses any-llm as its LLM backbone -- a unified interface to 38+ providers including OpenAI, Anthropic, Google, Mistral, Groq, and Ollama. Swap providers by changing a single setting; no code changes needed.
| Website | any-llm.ai |
| GitHub | mozilla-ai/any-llm |
any-llm gives porchsongs:
- Provider flexibility -- use whichever LLM API you already have a key for
- Local/offline support -- run fully offline with llamafile or Ollama
- Consistent interface -- streaming, async, and tool use work the same across all providers
Bring your own API key, configure it in Settings, and start rewriting.
