Skip to content

IOC FRAMEWORK · INFRASTRUCTURE

Circe

An inversion-of-control application framework for Discord bots, built on top of discord.js. The circe CLI owns the application lifecycle, discovers commands and event listeners by directory convention, and routes interactions over Gateway WebSockets, HTTP Webhooks, or a hybrid mode — without touching interaction logic.

DUAL-TRANSPORT

Gateway, HTTP Webhooks, or hybrid

  • Switch transport directly in circe.config.ts without modifying a single line of interaction logic.
  • Gateway: stateful 24/7 WebSocket connection. HTTP: stateless serverless Webhooks. Hybrid: both at once.
  • Sub-millisecond Ed25519 signature verification with native crypto.subtle.verify, zero dependencies, for the HTTP transport.
circe.config.ts

						01
						import { defineCirceConfig, defineConfig } from '@sxnnyside/circe';
					
						02
						 
					
						03
						export default defineCirceConfig({
					
						04
						  config: defineConfig(schema),
					
						05
						  transport: 'gateway', // "gateway" | "http" | "hybrid"
					
						06
						});
					

FILE-SYSTEM CONVENTIONS

Automatic discovery by directory

  • commands/, command-groups/, context-menus/, events/, components/, and modals/ are discovered on their own.
  • Scan-time shape validation with compiler-grade diagnostics — errors surface in development, not in production.
  • Hierarchical subcommand tree assembled automatically up to Discord's two-level limit, with inherited group-level guards.
src/commands/ping.ts

						01
						import { defineCommand } from '@sxnnyside/circe';
					
						02
						import { SlashCommandBuilder } from 'discord.js';
					
						03
						 
					
						04
						export default defineCommand({
					
						05
						  builder: new SlashCommandBuilder()
					
						06
						    .setName('ping')
					
						07
						    .setDescription('Replies with Pong'),
					
						08
						  async execute(ctx) {
					
						09
						    await ctx.interaction.reply('Pong!');
					
						10
						  },
					
						11
						});
					

CROSS-RUNTIME

Bun, Node.js 22+, or Deno

  • Same circe binary, same behavior, on all three runtimes — no compatibility shims.
  • discord.js ^14.16.0 as a peer dependency. Zod for typed configuration validation.
  • Full lifecycle CLI: circe init for scaffolding, circe dev with hot-reload, circe start for production, circe build as a CI contract check.
terminal

						$
						bun add @sxnnyside/circe discord.js zod
					
						$
						npm install @sxnnyside/circe discord.js zod
					
						$
						deno add npm:@sxnnyside/circe npm:discord.js npm:zod
					
						 
						 
					
						$
						bun x circe dev
					
						✦
						hot-reload watching src/**
					

TYPED ROUTING & OBSERVABILITY

Guards, pagination, and tracing

  • Component routes with expressive URL-style patterns — ticket:close:[ticketId]:[action] — with full type inference.
  • Collector-free pagination via createPaginator, with optional dropdown navigation (pageSelect).
  • Composable cooldown() guards in memory or SQLite, correlation IDs via AsyncLocalStorage, and global error reporting with onError.
src/components/ticket-close.ts

						01
						import { defineComponent, cooldown } from '@sxnnyside/circe';
					
						02
						 
					
						03
						export default defineComponent({
					
						04
						  pattern: 'ticket:close:[ticketId]:[action]',
					
						05
						  guards: [cooldown({ seconds: 5 })],
					
						06
						  async execute(ctx) {
					
						07
						    const { ticketId, action } = ctx.params;
					
						08
						  },
					
						09
						});
					

START NOW

Install it and go.

No dashboard, no panel, no server invite — Circe lives in your repository.

bun add @sxnnyside/circe discord.js zod