Build the skills AI can't replace.
This repo holds the website, Discord bot, and supporting services that power the Smarter Dev community — a 13,000+ member community focused on critical thinking, architecture, and adversarial reasoning.
- Website: https://smarter.dev
- Discord: https://smarter.dev/discord
- Premium membership: https://smarter.dev/sudo
- Website — Skrift-based async CMS at
smarter.dev. Marketing pages, blog, admin, and Skrift-managed content. - Discord bot — slash commands powering the community: a Bytes economy, Squads system, daily Quests, multi-stage Challenges, AI-assisted help, moderation, forum notifications, scheduled messages, and more.
- Web API — native Litestar controllers mounted at
/api(part of the Skrift app, insmarter_dev/web/api_native/). Bot authenticates with Skrift-nativesk_bearer service keys; sessions and OAuth handled by Skrift. - Bot admin — Litestar controllers inside Skrift's
/admininterface (guild config, Bytes, Squads, Campaigns, scheduled messages, and the rest of the bot's data), plus Skrift's built-in API-key management at/admin/api-keys. - Scan — AI research assistant, served from
scan.smarter.dev.
Everything runs against a single PostgreSQL database (smarter_dev): Skrift core tables (users, roles, pages, API keys, etc.) and all app tables (bot data — Bytes, Squads, Challenges, forum subs, scheduled messages — plus research, scan, quests, moderation, campaign signups) live in the skrift schema.
Two migration sets apply to it, in dependency order:
- Skrift core migrations — bundled with the
skriftpackage. alembic/main/— every project table (in theskriftschema), version tablealembic_version_app.
scripts/migrate.py orchestrates both runs.
- Docker with
docker compose(Docker Desktop, Colima, or equivalent). - uv for the bootstrap script and any out-of-container Python work.
- Python 3.13 (managed by uv).
git clone [email protected]:Smarter-Dev/smarter-dev.git cd smarter-dev cp .env.example .env
The defaults in .env.example are wired for the local compose stack — no edits required to get the stack standing up. scripts/bootstrap.py will append BOT_API_KEY automatically. Real Discord and LLM credentials are only needed for the features that use them (see Optional secrets below).
Note for Colima / non-default Docker setups: Postgres' init scripts (in
scripts/postgres-init/) only run if the project lives somewhere your Docker engine can bind-mount. Colima shares your home directory by default, so cloning under~works; cloning under/tmpor other unshared paths will leave theskriftschema uncreated and bootstrap will fail withschema "skrift" does not exist.
docker compose up -d postgres uv run python scripts/bootstrap.py docker compose up -d redis web bot
What that does:
- Starts Postgres on host port
5434. The init script inscripts/postgres-init/creates theskriftschema in thesmarter_devdatabase. bootstrap.py:- Runs Skrift + main migrations (via
scripts/migrate.py). - Marks Skrift setup complete (otherwise the dispatcher redirects all routes — including
/api/*— to its setup wizard). - Mints a Skrift-native
discord-botservice API key (sk_…) inskrift.api_keys, scopesbot:read,bot:write. - Writes the plaintext key into
.envasBOT_API_KEY=….
- Runs Skrift + main migrations (via
- Starts Redis on
6380, web on8001(host) →8000(container), and the bot.
Visit http://localhost:8001.
uv run python scripts/bootstrap.py --rotate-key # force-rotate the bot key uv run python scripts/bootstrap.py --skip-migrations # skip the migration step
Re-running without flags is idempotent: if the row in the DB and the key in .env agree, nothing changes; if they disagree, a fresh key is generated.
docker compose down -v # nukes volumes, full reset
docker compose up -d postgres
uv run python scripts/bootstrap.py
docker compose up -d redis web botapp.development.yaml configures Skrift's built-in dummy auth provider so you can log into the admin without setting up real OAuth credentials. Production (app.yaml) uses Discord/GitHub/Google; Skrift refuses to start with the dummy provider in production.
These only matter when you exercise the feature:
| Var | Feature |
|---|---|
DISCORD_BOT_TOKEN + DISCORD_APPLICATION_ID |
The bot connecting to Discord. Without these the bot logs an error and exits cleanly. |
ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY |
LLM-backed features (mod agent, help, mention, scan synthesis). GEMINI_API_KEY is also used for Discord voice message TTS. |
BRAVE_SEARCH_API_KEY / JINA_API_KEY / YOUTUBE_API_KEY |
Scan tools (search, page reader, YouTube). |
RESEND_API_KEY |
Outbound email (e.g. signup confirmations). Logs a warning and skips if absent. |
SPACES_ACCESS_KEY / SPACES_SECRET_KEY |
DigitalOcean Spaces / S3-compatible asset storage. |
DISCORD_APPLICATION_SECRET, GITHUB_CLIENT_*, GOOGLE_CLIENT_* |
Real OAuth providers (production only). |
# Quality uv run ruff check . uv run mypy smarter_dev # Tests uv run pytest # Generate a new project migration after editing models uv run alembic -c alembic/main/alembic.ini revision --autogenerate -m "describe change"
alembic/main owns every project model table — add new tables to MAIN_TABLES in alembic/main/env.py (guarded by tests/test_migration_ownership.py).
/api/* redirects to /setup on a fresh DB. Skrift's dispatcher locks routing to its setup wizard until setup_completed_at is recorded. Run uv run python scripts/bootstrap.py (the mark Skrift setup complete step does this), then docker compose up -d --force-recreate web so the dispatcher re-decides at startup.
Bot logs 200 responses but reports Expecting value: line 1 column 1 (char 0). Same root cause as above — the bot's HTTP client follows the /setup redirect and tries to JSON-parse the wizard's HTML. Fix is the same.
scripts/migrate.py reports success but no tables are created. This is an upstream Skrift bug — the skrift db CLI silently no-ops when the project path contains a space. scripts/migrate.py works around it by invoking alembic directly. Don't run skrift db upgrade heads from a path with a space.
Port 5434 / 6380 / 8001 already in use. Change the host-side port in compose.yaml and the matching localhost:<port> references in .env.
MIT.