Skip to content

Getting Started with TomoriBot Development

How to run TomoriBot locally with Bun and PostgreSQL for development.

  • Bun and PostgreSQL.
  • A Discord application with the bot and applications.commands scopes, and the Server Members and Message Content privileged intents enabled in the Developer Portal. Presence is optional and only used outside production.
Terminal window
bun install --frozen-lockfile
cp .env.example .env

Fill in the required values, and create the database and user they name:

DISCORD_TOKEN=...
CRYPTO_SECRET=...
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=...
POSTGRES_PASSWORD=...
POSTGRES_DB=tomodb
RUN_ENV=development
  • The code branches on RUN_ENV, not NODE_ENV.
  • RUN_ENV=production reads secrets from AWS Secrets Manager unless TEST_PRODUCTION=true.
  • Optional settings are in .env.optional.example; copy only the ones you need.
Terminal window
bun run dev

Startup loads secrets, the encryption key manager, the schema and seeds, the tool registry, locales, and caches, then sets up event handlers and logs in to Discord.

Run /setup in your server. It needs Manage Server and opens a private checklist. Nothing is saved until Finish Setup: cancelling or restarting the bot discards the draft (drafts live in memory, up to 200 at a time).

With RUN_ENV=development the checklist has two steps:

  • AI Provider, one select with three modes:
    • AI Provider (Recommended): pick a provider and enter an API key, which is validated and encrypted into the draft.
    • Custom Endpoint (Advanced): Configure Connection, then Configure Text Model, which is enabled once the connection validates.
    • User BYOK (servers only): members bring their own providers and the server keeps no text provider.
  • Starting Settings, one modal: persona, reply style, timezone, and the default system prompt. Built-in Default (Recommended) stores no prompt text, so it follows future changes to the shipped default; a catalog preset stores its text when you finish.

RUN_ENV=production adds a Policies step that accepts the Terms of Service and Privacy Policy. Set TEST_PRODUCTION=true to see it locally. The same setting controls whether /legal terms-of-service and /legal privacy-policy are registered; /legal license always is.

Afterwards, /providers adds and edits saved providers (Add New Custom Endpoint for a custom one, then register a model from its dropdown), and /config > Models > Switch Models changes the active provider or model.

Quick checks: /ping, /status, and mentioning the bot in chat. If commands do not appear, run /refresh.

CommandUse
bun run dev / build / startRun with reload, build, run the build
bun run check, bun run lintTypeScript and Biome
bun run vlEvery gate, one verdict each (see Development Tasks)
bun run check-locales, bun run check-limitsLocale keys and Discord limits
bun run check-runtime-importsRuntime dependencies load, and bun.lock keeps compatible transitive versions. Fatal in vl and CI
bun run check-media-sizeFails on tracked media over 1 MiB in src/db/seed/catalog/personas/** and assets/img/**
bun run compress-mediaFixes those files: lossless re-encode first, then a downscale to 768 px on the long edge if still too big. --dry-run previews; a path substring targets one file
bun run nuke-db, bun run backupReset or back up the local database
bun run purge-commandsRemove registered slash commands

Persona PNGs are already well compressed, so meeting the budget usually needs the downscale; Discord shows avatars at 128 px or less. On a release checkout, compress-media also converts release cards in .github/release/** to WebP (quality 90) and rewrites release-notes.md references. For a release already published, update its body with gh release edit afterwards.