Own your creativity.
プログラミングツールの多くは「速く作ること」を目指す。DucerはAIが全部やるのではなく、人間がクリエイティブであり続けることを中心に設計されている。
Ducerは、自分でコーディングするスタイルと、バイブコーディングの間に位置する。
- 勉強と制作は別々じゃない。作りながら理解する(Learning by doing)
- AIはコーチ。主役は常にユーザー
- 共に進むから、先が見える
ユーザーがソフトウェアを理解しながら作るための、AIコーチングMCPサーバー。 Claude Codeに接続し、AIが実装を進めながら音声で逐一解説する。ユーザーが事前に指定した箇所だけをユーザーに渡す(ハンドオフ)。
名前の由来:ラテン語 "educere"(内側から引き出す)から。AIが教え込むのではなく、ユーザーの能力を引き出す。
- ユーザーがClaude Codeに「作りたいもの」を伝える。
- Claude Codeが
start_sessionでDucerセッションを開始し、使用IDEを確認する - Claude Codeが**理解の順序(cognitive ordering)**でプランを設計し、
set_planで登録する。Ducerが音声でプランを読み上げ、ユーザーに確認を取る - ユーザーが「次」と言うたびに、Claude Codeが
write_stepを呼ぶ。DucerがIDEのファイルにコードをブロック単位で書きながら、VoiceManagerが内容をリアルタイムで解説する - ユーザー担当箇所に来たら
execute_handoffで停止し、音声で「ここからはあなたです」と渡す - ユーザーが実装したら、Claude Codeが
check_user_codeで評価し、次へ進む - ビルドエラー等が起きた場合、アドホックステップを
write_stepで挿入して修正する - 間違えたら
goto_stepでロールバックし、やり直せる - 最終的にソフトウェアが完成し、ユーザーは内部構造を理解している
- プログラミングを自分の興味のあることで学習したい人
- システムの全体概要を捉えた上で表現の検討をしたいアーティスト、プログラマー
- 技術書を読み終え、自分の作りたいものをどう作るか知りたい人
- 業務の中で効率よく仕様を学びながら経験を積みたいエンジニア
モードは明示的に選ぶものではなく、user_owned の内容によって自動的に決まる。
| モード | 条件 | 動作 |
|---|---|---|
| Watch | user_owned が空 |
AIが全部書く。ユーザーは見て理解するだけ |
| Pair | user_owned に何か入っている |
AIが担当部分を書き、handoff でユーザーに渡す |
仕組みは同じ。ユーザーの担当箇所があるかどうかだけが違い。
DucerはMCPサーバーとしてClaude Codeに接続する。Claude Code自体がオーケストレーターおよびプランナーの役割を担い、Ducerはコード書き込み・音声ナレーション・セッション管理を提供する。
┌──────────────────────────────────────────────┐
│ Claude Code (AI) │
│ プランニング・オーケストレーション・対話 │
└──────────┬───────────────────────────────────┘
│ MCP Protocol
↓
┌──────────────────────────────────────────────┐
│ Ducer MCP Server │
│ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ Session │ │ Coder │ │ VoiceManager │ │
│ └─────────┘ └─────────┘ └──────────────┘ │
└──────────────────────────────────────────────┘
| 担当 | 役割 |
|---|---|
| Claude Code | ユーザーとの対話、プラン設計、ステップの実行判断、コード生成 |
| Ducer | ファイル書き込み、音声ナレーション、セッション状態管理、IDE連携 |
- セッション全体の状態管理(プラン、完了ステップ、書き込みファイル)
.ducer/session.jsonに永続化。MCPサーバー再起動やClaude Codeセッション変更を跨いで復元可能- ステップごとに書き込んだファイルを追跡(
written_files)。ロールバック時のファイル削除に使用 - セッション状態:
idle→active→handoff→complete
- プランに従ってIDEのファイルに直接コードを書く
- ブロック単位書き込み: ソースコードを空行で区切ったブロックに分割し、1ブロックずつファイルに追記する。各ブロックの間にナレーションを挟むことで、ユーザーがリアルタイムでコードの成長を見られる
- ファイル作成時にIDEで自動オープン(Xcode / VS Code / Cursor対応)
- スケルトンコードの書き込み(ハンドオフ用)
- TTS: macOS
sayコマンドによる日本語音声ナレーション- デフォルト音声: Kyoko、速度: 200 WPM
- コードブロックの間に挟まる形でリアルタイム解説
enabled=Falseでサイレントモード(テスト/CI用)
- 割り込み:
interrupt()で発話を即座に停止可能
VoiceManagerに渡すナレーションは以下の原則に基づく:
-
Why優先:何を書くかより、なぜそう書くかを先に説明する
- ❌「ifブロックを書きます」
- ✅「隣のセルが生きているか死んでいるかを確認します。条件によって処理を分けたいので、ifを使います」
-
具体的な例えを使う:抽象的な概念を日常的なものに置き換える
- 例:「配列はエクセルの表のようなものです」
-
難しい言葉を使わない:専門用語を使う場合は必ず一言で説明を添える
-
ユーザーレベルに合わせる:
granularityの値に応じて説明の深さを変える- 1(粗い):大きな流れだけ説明、詳細は省く
- 3(標準):概念とコードの対応を説明
- 5(細かい):1行ごとに丁寧に、背景知識も含めて説明
-
テンポを保つ:説明が長くなりすぎない。1ブロックあたり2〜3文を目安にする
| ツール | 説明 |
|---|---|
start_session |
セッション開始/再開。プロジェクトルート、名前、granularity、音声設定、IDE名を指定 |
get_session_status |
現在のセッション状態とプラン進捗を取得 |
| ツール | 説明 |
|---|---|
set_plan |
実装プランを設定(構造のみ、コードなし)。音声でプランを読み上げて確認を取る |
revise_plan |
指定ステップ以降のプランを差し替え |
| ツール | 説明 |
|---|---|
write_step |
blocks配列でコード・ナレーション・コメントを一体で書き込む。各blockが1つの書き込み単位。プランにないステップIDの場合、アドホックステップとして自動挿入される |
execute_handoff |
ユーザーにバトンを渡す。スケルトンコードを書き込み、音声で案内する |
check_user_code |
ユーザーが書いたファイルの内容を読み取って返す |
| ツール | 説明 |
|---|---|
goto_step |
ステップNにロールバック。N以降のステップで書いたファイルを削除し、進捗をリセットする。goto_step(0) で全リセット |
speak |
任意のテキストを音声で読み上げる |
| URI | 説明 |
|---|---|
ducer://guide |
コーチングガイド。Claude Codeが従うべき原則(cognitive ordering、ナレーションスタイル、ツール使用順序) |
ducer://plan/current |
現在のプランと進捗状況(JSON) |
コーチングガイド全文は ducer://guide リソースとして提供される。主要原則のみここに記載する。
- セッション開始時にIDEを確認する
- AIがプロジェクト足場(Package.swift、xcodeproj等)を作成する
- 1ステップずつ進める。複数ステップを連続実行しない
- ステップ実行前に意図を説明し、ユーザーの確認を得る
- 各ステップは前のステップの土台になっている
- 画面に何かが出ることを最優先(単色の四角形でもいい)
- 1ステップ = 1ファイル。ナレーションとコードブロックの整合性を保つため
- ユーザー担当箇所は、前後の文脈が理解できた状態で渡す
- コア先行確認(後述)に従い、プロジェクトのコアを最優先で体験可能にする
- 観測可能状態ルール: ステップのタイトル・descriptionは完了時にユーザーが観測できる状態を記述する。未接続のコードは「定義する」「準備する」と書き、「描画する」「表示する」を使わない
- ビルドエラー修正等、プランにない作業も
write_stepで対応 - プランに存在しない
step_idを指定すると、最後に完了したステップの直後に自動挿入される
goto_step(0): 全リセット。全ファイル削除、プランクリアgoto_step(N): ステップN以降をロールバック。該当ファイルを削除し、進捗をリセット- ロールバック後、削除されたファイルが過去ステップでも書かれていた場合、そのステップを先に再実行する
@dataclass
class PlanStep:
id: int # ステップ番号
title: str # タイトル
description: str # 説明
rationale: str # なぜこの順番か
owner: Literal["ai", "handoff"] # 実行者
files: list[str] # 対象ファイル(相対パス)
completion_criteria: str # 完了条件(任意)
message: str # ハンドオフメッセージ(任意){
"project": "Game of Life",
"user_owned": [
{
"file": "Sources/Logic/GameLogic.swift",
"description": "Game of Lifeのアルゴリズム。nextGeneration関数を実装してください",
"skeleton": "func nextGeneration(grid: [[Bool]]) -> [[Bool]] {\n // ここを実装してください\n}"
}
],
"steps": [
{
"id": 1,
"title": "エントリーポイント作成",
"description": "アプリの起動地点を作ります",
"rationale": "まずアプリが起動することを確認します",
"owner": "ai",
"files": ["GameOfLife/GameOfLifeApp.swift"],
"completion_criteria": "アプリが起動する"
},
{
"id": 2,
"title": "Metalシェーダー",
"description": "画面に色を表示するシェーダーを作ります",
"rationale": "早期に画面出力を実現します",
"owner": "ai",
"files": ["GameOfLife/Shaders/GridShaders.metal"],
"completion_criteria": "シェーダーがコンパイルできる"
}
]
}セッション状態は {project_root}/.ducer/session.json に自動保存される。
{
"project_name": "Game of Life",
"granularity": 3,
"plan_steps": [...],
"completed_steps": [1, 2],
"written_files": {
"1": ["GameOfLife/GameOfLifeApp.swift"],
"2": ["GameOfLife/Shaders/GridShaders.metal"]
},
"state": "active"
}MCPサーバーが再起動しても、start_session 時に既存セッションを検出して自動復元する。
Claude Codeのスラッシュコマンドとして提供。
| コマンド | 動作 |
|---|---|
/ducer-step |
次の未完了ステップを実行 |
/ducer-step N |
ステップNに移動(ロールバック含む) |
/ducer-step 0 |
セッション全体をリセット |
| コンポーネント | 技術 |
|---|---|
| 全体 | Python 3.11+ |
| サーバー | MCP (Model Context Protocol) / fastmcp |
| TTS | macOS say コマンド(日本語 Kyoko) |
| AI | Claude Code(MCPクライアントとして接続) |
| セッション保存 | JSON (.ducer/session.json) |
| IDEファイル操作 | 直接ファイル書き込み + IDE自動オープン |
{
"mcpServers": {
"ducer": {
"command": "python",
"args": ["-m", "ducer.server"],
"cwd": "/path/to/ducer"
}
}
}注意:
pythonコマンドは仮想環境有効化後に使えるようになる。source .venv/bin/activateが必要。
Claude Code → start_session(project_root, project_name, granularity, ide)
Claude Code → set_plan(steps)
Claude Code → write_step(step_id, blocks, mode) を繰り返す
- 理解優先:速く作ることより、ユーザーが理解することを優先する
- 動くものを見せる:毎ステップ、何かが動く状態にする。画面出力を最優先
- ユーザーの主体性:AIはあくまでコーチ。ユーザーが書きたい部分は必ず渡す
- 説明のスタイル:丁寧で体系的に説明しながら、ユーザーの状況を読んで柔軟に導く
- 1ステップ = 1ファイル:ナレーションとコードの整合性を保つための基本単位
- ロールバック可能:いつでも過去のステップに戻れる。失敗を恐れずに進められる
- 永続性:セッション状態は自動保存。中断しても続きから再開できる
- コア先行確認:プロジェクトのコア(最も重要なアルゴリズムや概念)を実装した直後に、その動作を体験できなければならない
Ducerの存在意義は「理解しながら作る」ことにある。ユーザーの理解がピークに達するのは、プロジェクトのコア — 最も重要なアルゴリズムや概念 — を実装した瞬間である。この理解のピークと動作確認が離れていると、理解は保留され、薄れ、Ducerの価値が損なわれる。
コアを実装した直後の1ステップ以内に、その動作を視覚的・機能的に確認できなければならない。
確認できない場合、ステップの順序を再構成するか、確認用の中間ステップを挿入する。
ステップの順序は「依存関係の順」ではなく「理解と体験の順」で設計する。
Phase 1: 最小足場(scaffold)
コアを「見せる」ために必要な最低限のインフラを構築する。
ここでは表示系・描画系・通信系など、コアの出力先を先に整える。
Phase 2: コア実装 + 即時確認(core → verify)
プロジェクトの核心を実装し、直後のステップでそれが動くのを見る。
この2ステップの間に無関係なステップを挟んではならない。
Phase 3: 段階的拡張(extend)
追加機能を一つずつ実装する。各ステップで即確認できる状態を維持する。
| アプリ | コア | 最小足場 | 即時確認 |
|---|---|---|---|
| Game of Life | セルオートマトン | 描画パイプライン + セル色分け | タイマーで自動進化 |
| 画像フィルタ | フィルタアルゴリズム | カメラ/画像入力 + 表示 | フィルタ適用結果 |
| チャットアプリ | リアルタイム同期 | 最小UI + 接続 | メッセージが流れる |
| 物理シミュレーション | 物理方程式 | レンダリング + オブジェクト | 物体が落下・衝突 |
プロジェクト定義に core_concept を記述し、各ステップに purpose を指定する。
project:
core_concept: >
Conway's cellular automaton — 隣接セルを数えて誕生・生存・死亡を判定する
単純なルールから複雑なパターンが創発する。
steps:
- id: 1
purpose: scaffold # コアのための土台
- id: 8
purpose: core # コアの実装
- id: 9
purpose: verify # コアの動作確認(core直後であること)
- id: 10
purpose: extend # 追加機能purpose の4種類:
- scaffold — コアを動かすために必要な土台
- core — プロジェクトの核心
- verify — コアが動くことを確認できるステップ(core直後に配置)
- extend — 追加機能・UI改善
- より自然なTTS(OpenAI TTS API)
- STT(Whisper APIによるマイク入力・音声割り込み)
- FileWatcher(
watchdogによるユーザーコード変更の自動検知) - セッション履歴のエクスポート・共有
- Web/クラウドIDE対応
- 複数プロジェクト同時セッション