Skip to main content
flora is a Discord bot framework built on Rust and V8 isolates. The runtime bridges Discord events into JavaScript execution contexts, with each guild running its own isolated environment.

Core Components

The flora runtime consists of several key components:

Discord Client Layer

Built on Serenity, the Discord client handles:
  • Gateway event subscription and processing
  • REST API calls to Discord
  • Bot authentication and connection management
  • Event routing to guild isolates
All events without a guild_id are dropped at the Discord handler level (apps/runtime/src/discord_handler.rs:74-77).

Bot Runtime

The BotRuntime manages a pool of worker threads (apps/runtime/src/runtime/mod.rs:34-65):
  • Worker pool with 1-64 threads (configurable via RUNTIME_MAX_WORKERS, default 4)
  • Guild-to-worker routing using consistent hashing
  • Per-worker isolate lifecycle management
  • Runtime migration support for load balancing
pub struct BotRuntime {
    workers: Vec<Worker>,
    num_workers: usize,
    secrets: Arc<SecretService>,
    guild_routes: Arc<parking_lot::Mutex<HashMap<String, usize>>>,
    migration_queues: Arc<Mutex<HashMap<String, Vec<QueuedGuildEvent>>>>,
}

V8 Isolates

Each guild runs in its own V8 isolate:
  • One isolate per guild for complete isolation
  • Backed by Deno Core for ops and module loading
  • Initialized once per worker thread
  • SDK bundle loaded into default runtime, shared across guild isolates
V8 is initialized once per process (apps/runtime/src/main.rs:121). Workers are initialized sequentially to avoid V8 race conditions (apps/runtime/src/runtime/mod.rs:68-75).

Deno Core Ops

Ops expose Discord functionality to JavaScript:
  • Discord actions: op_send_message, op_edit_message, op_delete_message
  • Command registration: op_register_slash_commands
  • KV storage: op_kv_get, op_kv_set, op_kv_list, op_kv_delete
  • Secrets: op_secrets_get (runtime-scoped or guild-scoped)
  • Logging: Custom log sink for script output
  • Cron: op_cron_register for scheduled tasks
Ops use the #[op2] macro from Deno Core and extract state via Rc<RefCell<OpState>>.

HTTP API

Axum-based REST API for CLI and tooling (apps/runtime/src/handlers/mod.rs):
  • /deployments/* - Deploy, list, and read guild scripts
  • /logs/* - Query and stream logs (including SSE)
  • /kv/* - KV store management
  • /secrets/* - Secret management
  • /auth/* - Discord OAuth flow
  • /tokens/* - API token management
Authentication via Bearer tokens or OAuth sessions.

Storage Layer

Multiple storage backends:
StorageTechnologyPurpose
PostgresSQLxDeployments, tokens, KV metadata
Redis/ValkeyFredSession cache, deployment cache
SledEmbedded KVPer-guild key-value storage
Sled stores are scoped per guild and per store name, backed by local disk under data/kv (apps/runtime/src/main.rs:103).

Data Flow

Deployment Flow

  1. CLI sends bundled TypeScript to /deployments
  2. Runtime stores deployment in Postgres + Redis cache
  3. Runtime routes deployment to appropriate worker by guild ID
  4. Worker creates/updates guild isolate with new script
  5. Guild’s cron jobs are cleared and re-registered

Event Dispatch Flow

  1. Discord gateway event arrives at Serenity handler
  2. Event payload serialized to JSON
  3. Guild ID extracted; events without guild ID are dropped
  4. Event routed to worker via consistent hashing
  5. Worker dispatches to guild isolate’s event handlers
  6. Script handlers registered via on() execute
  7. Ops like ctx.reply() map back to Discord REST calls
// In guild script
on('messageCreate', async (msg) => {
  // Executes in guild isolate
  await msg.reply('Hello!') // Maps to op_send_message
})

Cron Execution Flow

  1. Per-worker interval ticks every second (apps/runtime/src/runtime/worker.rs:102-116)
  2. Cron registry checks for due jobs
  3. Due jobs dispatched as synthetic events (__cron:<name>)
  4. Handlers execute with their own timeout (default 5s)
  5. skipIfRunning flag prevents concurrent execution

Configuration

Runtime behavior is controlled via environment variables or config.toml (crates/flora_config/src/lib.rs):
[runtime]
max_workers = 4              # Worker pool size (1-64)
boot_timeout_secs = 5        # Isolate initialization timeout
dispatch_timeout_secs = 3    # Per-event handler timeout
max_script_bytes = 8388608   # 8MB script size limit
max_cron_jobs = 32           # Cron jobs per guild
cron_timeout_secs = 5        # Cron handler timeout

Runtime Lifecycle

Startup Sequence

  1. Load configuration from environment + config.toml (apps/runtime/src/main.rs:41-46)
  2. Initialize tracing subscriber (apps/runtime/src/main.rs:48-63)
  3. Connect to Postgres, run migrations (apps/runtime/src/main.rs:76-82)
  4. Connect to Redis/Valkey with reconnect policy (apps/runtime/src/main.rs:84-98)
  5. Initialize services: deployments, tokens, KV, secrets, auth (apps/runtime/src/main.rs:100-119)
  6. Initialize V8 once per process (apps/runtime/src/main.rs:121)
  7. Initialize worker pool sequentially (apps/runtime/src/main.rs:134-140)
  8. Load SDK bundle into all workers (apps/runtime/src/main.rs:142-148)
  9. Restore cached deployments from database (apps/runtime/src/main.rs:149-157)
  10. Start Discord client and HTTP server concurrently (apps/runtime/src/main.rs:159-207)

Guild Bootstrap

When the bot joins a new guild without a deployment:
  1. GuildCreate event fires (apps/runtime/src/discord_handler.rs:360-367)
  2. Runtime checks for existing deployment
  3. If none exists, deploys a minimal starter script
  4. Starter script includes basic prefix command example
The default guild script is embedded at compile time from runtime-dist/default_guild_bundle.js (apps/runtime/src/discord_handler.rs:839).

Thread Model

  • Main thread: Serenity event loop + Axum HTTP server
  • Worker threads: One per configured worker (1-64)
  • Tokio runtime: Current-thread runtime per worker (apps/runtime/src/runtime/worker.rs:94-97)
Workers use unbounded channels for command dispatch and track backlog with atomic counters (apps/runtime/src/runtime/worker.rs:52-53).

Build docs developers (and LLMs) love