メインコンテンツまでスキップ

v2.0.0 — npm 公開中

置くだけで、
動く。

クラスを置く。フレームワークが見つけ、登録し、つなぐ。
Discord Bot の起動までを、規約と型に任せられます。

bun add @cc-discord-framework/core

auto-discovery — 登録コードを書かずに、配置だけで Bot が組み上がる

01 · 設計思想

書くのは、
Bot の機能だけ。

発見・登録・ルーティング・型付け。Bot を書くたびに 繰り返してきた「いつもの配線」は、規約と型が肩代わりします。

  1. 規約が構造になる

    commands/ に置いたクラスが、そのままスラッシュコマンドになる。 import も登録リストも書きません。名前はクラス名から導出 (UserInfoCommand/user-info)。

  2. サービスは this に収束

    どのコンポーネントからも this.services.audio / this.services.ai / this.services.ui。 宣言マージで型も通ります — 手動のジェネリクス指定はありません。

  3. discord.js のまま

    export * from "discord.js" — 全 API を再エクスポートし、Client は discord.js の Client そのもの。 これまでの知識も、エコシステムも、すべてそのまま使えます。

02 · discord.js との関係

discord.js を、
置き換えない。

全 API を再エクスポートし(export * from "discord.js")、 その上へ規約と型の構造を足します。同じ /ping を 動かすまでのコードが、これだけ変わります。

discord.js のみ1ファイル · 36

index.ts手動配線
import {
Client,
GatewayIntentBits,
REST,
Routes,
SlashCommandBuilder,
} from "discord.js";

// 1) コマンド定義を組み立てて…
const commands = [
new SlashCommandBuilder()
.setName("ping")
.setDescription("Botの応答速度を確認します。"),
// コマンドを足すたびにここへ追記
];

// 2) REST API で自分で登録して…
const rest = new REST().setToken(process.env.DISCORD_TOKEN!);
await rest.put(Routes.applicationCommands(process.env.APP_ID!), {
body: commands.map((c) => c.toJSON()),
});

// 3) ルーティングも自分で書く
const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand()) return;
switch (interaction.commandName) {
case "ping":
await interaction.reply(`Pong! ${client.ws.ping}ms`);
break;
// コマンドを足すたびに分岐も追記
}
});

await client.login(process.env.DISCORD_TOKEN);

cc-discord-framework2ファイル · 20

src/index.ts自動
// src/index.ts — エントリポイントはこれだけ
import {
Client,
GatewayIntentBits,
} from "@cc-discord-framework/core";

const client = new Client({ intents: [GatewayIntentBits.Guilds] });
await client.login(); // トークンは DISCORD_TOKEN 環境変数から自動使用
src/commands/PingCommand.ts自動
// src/commands/PingCommand.ts — 置くだけ。登録・同期は自動
import {
Command,
type ChatInputCommandInteraction,
} from "@cc-discord-framework/core";

@Command.define({ description: "Botの応答速度を確認します。" })
export class PingCommand extends Command {
override async chatInputRun(interaction: ChatInputCommandInteraction) {
await interaction.reply(`Pong! ${this.client.ws.ping}ms`);
}
}

interaction は discord.js の型そのもの。2つ目のコマンドは ファイルをもう1枚置くだけで、左のコードのように登録行や分岐が増えることはありません。

03 · 主要機能

小さなコアと
本物の拡張点

コアが持つのはサービス・コマンド・リスナー・Precondition だけ。それ以外は、同じ仕組みの上にプラグインとして積み上がります。

標準デコレータ(TC39)

@Command.define({...}) は TC39 標準デコレータのみ。 experimentalDecorators も reflect-metadata も不要です。 デコレータは宣言し、ローダーが実行する — 厳密に分離されています。

設定は config/ に分割

createClient()src/config/ を読み、1関心1ファイルの 設定を合成。plugins は priority 順に連結、intents は 合併(union)されます。

プラグインは「種別」を足す

プラグインは機能ではなくコンポーネント種別ごと追加できます。utils は tasks/、music は resolvers/+providers/、 ai は ai/ — すべて Public API だけで実現。

すべて差し替え可能

ユーザーに見える文言・色・上限は、すべてただの既定値。 変更できないハードコードは設計ルールとして存在しません。 Bot の見せ方は Bot が決めます。

Bun ファースト

Bun 1.4+ 専用。TypeScript をそのまま実行するので、開発にビルド工程は ありません。500件を超える自動テストを bun test でまとめて実行できます。

型はマージで効く

リスナーのイベント引数、ストア参照、this.services.*、 Precondition 名 — 宣言マージにより、手動のジェネリクス指定なしで型が通ります。

04 · コード

実際の Bot から、
そのまま。

以下はすべて、リポジトリ同梱の公式リファレンス Bot(client/)で実際に動いているコードです。

コマンド本体は、1呼び出し。

オプションはデコレータで宣言し、本体は this.services.ai.reply() の1行。defer・ストリーミング表示・ 長文の分割・失敗時の表示は、すべてサービス側の責務です。

  • コマンド名はクラス名から自動導出(AskCommand/ask)
  • Discord への登録・同期も ready 時に自動
src/commands/ai/AskCommand.ts
import {
ApplicationCommandOptionType,
Command,
type ChatInputCommandInteraction,
} from "@cc-discord-framework/core";

@Command.define({
description: "AIに質問します(会話履歴は使いません)。",
options: [
{
type: ApplicationCommandOptionType.String,
name: "prompt",
description: "聞きたいこと",
required: true,
},
],
})
export class AskCommand extends Command {
override async chatInputRun(interaction: ChatInputCommandInteraction) {
// defer・ストリーミング表示・長文の分割・失敗時の表示は reply() の担当。
await this.services.ai.reply(interaction, {
prompt: interaction.options.getString("prompt", true),
});
}
}

05 · プラグイン

機能ではなく、
「種別」を足す。

プラグインが提供するのは、コンポーネント種別の自動ロード・サービス・ イベントの3つだけ。コマンドは登録しません /play/ask も Bot の機能なので、src/commands/ に自分で書きます。文言も見せ方も、Bot が決める。

そして種別は横断して合成できます。src/ai/ のツールの中で this.services.audio が普通に動く — 「いま流れている曲」を AI が答えられるのは、この合成のおかげです。

独自のデコレータ・ディレクトリ・ライフサイクルを持つ新しい種別を、 Public API だけで丸ごと追加できます。公式プラグインも、 この同じ拡張点の上に立っています。

  • src/
  • index.tsエントリポイント(自動探索のルート)
  • config/設定 — 1関心1ファイル
  • commands/Commandコア
  • listeners/Listenerコア
  • preconditions/Preconditionコア
  • services/Serviceコア
  • tasks/Task — 定期実行utils
  • resolvers/ providers/音源の解決と再生music
  • ai/AiTool — LLM から呼べる関数ai

置く場所が、そのまま役割。プラグインを入れると、読めるディレクトリが増える。

06 · 公式プラグイン

重い依存を
コアの外へ

公式プラグインはそれぞれ独立したパッケージ。すべて npm の @cc-discord-framework スコープで公開されていて、使う分だけ bun add で足せます。

07 · Roadmap — WebAssembly

次の「1枚」は、
どの言語でも。

プラグインの次の形として、WebAssembly コンポーネントの ネイティブ対応を構想しています。境界を WIT で定義すれば、 TypeScript 以外の言語で書いたプラグインも、いまと同じ 「置くだけ」で動く — 言語の違いを、フレームワークの 境界にしないための計画です。

設計構想の段階です。API と WIT 定義は未確定で、 仕様は RFC として公開する予定です。

08 · Project Status — Updated 2026-08-25

プロジェクトの現在地

詳しい状況とサポート方針はステータスページにまとめています。

現行 — v2 系

@cc-discord-framework/core 2.0.0。このサイトと main の コードが説明する現行版で、公式プラグインも同じスコープで npm 公開中。

旧 — v1 系

スコープなしの旧パッケージ cc-discord-framework(1.0.5)は 旧世代です。v2 と API 互換ではないため、新規導入では選ばないでください。

保守

CHACCHAN が設計・実装・ドキュメントを保守する個人メンテナンスの OSS(MIT License)。熊の耳にした2つの C は CHACCHAN から。

09 · はじめる

まず、1枚置いてみる。

最小の Bot まで3ステップ。ボイラープレートの生成も、ビルドの設定もありません。

  1. 01

    インストール

    discord.js は同梱・再エクスポートされるので、個別にインストールする 必要はありません。ランタイムは Bun 1.4+ だけ。

  2. 02

    エントリポイントを書く

    src/index.tsClient を作って login()。トークンは DISCORD_TOKEN 環境変数から自動で使われます。

  3. 03

    クラスを置く

    src/commands/ にコマンドのクラスを1枚。ビルド工程なしで bun run src/index.ts — もう /ping が動いています。

terminal
bun add @cc-discord-framework/core
bun run src/index.ts

Built in Japan

日本語で、最初から。

cc-discord-framework は日本発のオープンソースです。 ドキュメントもコードコメントもエラーメッセージも、翻訳ではなく 最初から日本語で書かれています。MIT License。