EdgeVox — Claude Code ルール
ロボット向けオフラインボイスエージェントフレームワーク。Pure-Pythonパッケージ、クラウド依存なし、CPU/CUDA/Metal上で動作。
プロジェクト構成
edgevox/
├── edgevox/ # ソースパッケージ
│ ├── audio/ # VAD、マイクキャプチャ、再生
│ ├── stt/ # STTバックエンド(faster-whisper、sherpa-onnx)
│ ├── llm/ # llama.cpp / Gemma 統合
│ ├── tts/ # TTSバックエンド(Kokoro、Piper、Supertonic、PyThaiTTS)
│ ├── core/ # パイプラインオーケストレーション
│ ├── cli/ # CLIエントリーポイント
│ ├── ui/ # TUIウィジェット
│ ├── integrations/ # ROS2ブリッジなど
│ ├── tui.py # メインTUIアプリ
│ └── setup_models.py # モデルダウンローダー
│ ├── server/ # FastAPI Web UI + WebSocketサーバー
├── webui/ # Reactフロントエンド(Vite + Tailwind)
├── scripts/ # ユーティリティスクリプト(モデルアップロードなど)
├── voices/ # 音声設定ファイル
├── docs/ # プロジェクトドキュメント
├── website/ # VitePressサイト
└── pyproject.toml
エントリーポイント(pyproject.toml 参照):
edgevox→edgevox.tui:main(デフォルトTUI、--web-uiでWeb、--simple-uiでCLI)edgevox-cli→edgevox.cli.main:mainedgevox-setup→edgevox.setup_models:main
対応言語とバックエンド
| 言語 | STT | TTS |
|---|---|---|
| 英語、フランス語、スペイン語など | faster-whisper | Kokoro |
| ベトナム語 | sherpa-onnx (zipformer) | Piper |
| ドイツ語、ロシア語、アラビア語、インドネシア語 | faster-whisper | Piper |
| 韓国語 | faster-whisper | Supertonic |
| タイ語 | faster-whisper | PyThaiTTS |
モデルは nrl-ai/edgevox-models(HuggingFace)でホストされ、フォールバックとして上流リポジトリを使用します。
アーキテクチャの原則
- プラグアンドプレイ、デフォルトでカスタマイズ可能。 すべてのコンポーネント(STTバックエンド、TTSバックエンド、LLM、VAD、エージェントループ動作、パイプラインステージ、ツール、スキル、フック)は、コアコードを編集せずに交換可能でなければなりません。ハードコードされたパスよりも、プロトコル、レジストリ、デコレータを優先します。新しい動作は、既存のモジュールへのパッチではなく、新しいプラグイン/フック/バックエンドとして導入されます。特定のユースケースのためにコアに条件分岐を追加していることに気付いたら、一歩下がって代わりに注入ポイントに抽出してください。
エージェントハーネスアーキテクチャ
エージェントハーネス(edgevox/agents/ + edgevox/llm/hooks_slm.py + edgevox/llm/tool_parsers/)は docs/documentation/ 以下に完全に文書化されています:
agent-loop.md— 6つのファイアポイントループ、並列ディスパッチ、ハンドオフのショートサーキットhooks.md— フック作成契約、ビルトインフック、順序ルールmemory.md—MemoryStore/SessionStore/NotesFile/Compactorinterrupt.md— バージイン信号 + キャンセルトークンの配管multiagent.md— Blackboard、BackgroundAgent、AgentPooltool-calling.md— パーサーチェーン + 文法制約付きデコードのロードマップ
ハーネスルール
- 型付けされた
AgentContextフィールド(ctx.tool_registry、ctx.llm、ctx.interrupt、ctx.memory、ctx.artifacts、ctx.blackboard)は公開配管インターフェースです。ctx.stateはユーザー専用のスクラッチ領域であり、フレームワークコードはここにマジックキーを書き込んではいけません。 - フックが所有する状態は、
ctx.hook_state[id(self)]の下に置かれます。id(self)でキーを指定することで、同じフッククラスの2つのインスタンスが状態を共有しないことが保証されます。 - バージインは強制可能であり、推奨ではありません。 すべての
LLM.complete呼び出しは、stop_event=…を介してctx.interrupt.cancel_tokenをスレッド化するため、llama-cpp のstopping_criteriaが実際に 1 デコードステップ内で生成を停止します。 - トークナイザー正確なトークンカウント。
estimate_tokens(messages, llm)とLLM.count_tokensは、LLMが利用可能な場合にchars // 4ヒューリスティックを置き換えます。CJK / ベトナム語 / タイ語の正しいコンテキストウィンドウの決定に必要です。 - ツール呼び出し解析は、生の状態で最初に実行されます。
parse_tool_calls_from_contentは、思考ブロックを削除する前に、生のコンテンツに対して検出器を試みます — Qwen3は推論ブロック内でツール呼び出しを出力します(llama.cpp#20837 参照)。 - プリセットパーサーはロード時に検証されます。
resolve_preset(slug)は、tool_call_parsers=(...)内のすべての名前が登録された検出器であることをアサートします。タイポは、静かに検出を無効にするのではなく、大声で失敗します。 - モデルが発行したツール呼び出しIDはラウンドトリップします。 Mistral の
[TOOL_CALLS]形式は、フォローアップのrole="tool"メッセージが再利用する必要がある 9 文字の ID を運びます。ToolCallItem.idは、これをパーサーチェーンとエージェントループを通じて配管します。
推奨インポートサーフェス
- エージェントフレームワーク:
from edgevox.agents import LLMAgent, AgentContext, Session, Handoff, ... - ビルトインフック:
from edgevox.agents.hooks_builtin import MemoryInjectionHook, TokenBudgetHook, ... - SLM 強化:
from edgevox.llm.hooks_slm import default_slm_hooks - メモリ:
from edgevox.agents.memory import JSONMemoryStore, NotesFile, Compactor, estimate_tokens - マルチエージェント:
from edgevox.agents.multiagent import Blackboard, BackgroundAgent, AgentPool - 割り込み:
from edgevox.agents.interrupt import InterruptController, InterruptPolicy, EnergyBargeInWatcher
プライベートモジュールや _agent_harness.py に直接アクセスしないでください。
コーディングルール
- Python ≥ 3.10。 現代的な構文(
X | Yユニオン、match、dict[str, int])を使用。 - ruff でフォーマットとリント。 行長 120。
ruff formatを実行後、ruff check --fixを実行。 - コードコメントに末尾の要約を付けない。 「what」ではなく「why」をコメントする。
- 公開関数には型ヒント。 内部ヘルパーは、明白な場合は省略可能。
- ライブラリコードではprintを使用しない。 ユーザー向け出力には
rich/textualを、診断にはloggingを使用。 - インポートはファイルの先頭に。 具体的な理由(循環インポートの回避、オプション/重量級依存関係の機能チェック待ち、CLI起動レイテンシ削減のための遅延ロード)がある場合のみ、関数内にインポートをプッシュする。便利さや「1箇所でしか使わない」は理由になりません。上に移動してください。
- 理由なく新しいトップレベル依存関係を追加しない。 標準ライブラリを優先。追加する必要がある場合は、
pyproject.tomlを更新。 - ハードウェア認識コードパスはグレースフルに劣化する必要があります — CUDA/Metal/CPUのフォールバック、アクセラレータがない場合にクラッシュしないこと。
- モデルファイル(
.gguf、.onnx、.bin、重み)をコミットしないでください。 これらは gitignored なmodels/の下に置かれます。
オーディオ / モデル規則
- サンプルレート:キャプチャとSTT入力は 16 kHz モノラル int16。
- TTS出力:
sounddeviceを介してデバイスレートにリサンプリング。 - VADフレームサイズ:32 ms(16 kHzで512サンプル)。
- レイテンシ予算:RTX 3080上でSTT < 0.5秒、LLM最初のトークン < 0.4秒、TTS最初のチャンク < 0.1秒。
- ストリーミングパイプラインを契約として扱う:イベントループをブロックするブロッキング呼び出しを導入しない。
ツール
- uv をパッケージ管理に使用。
pip/python -m venvの代わりにuv pip install/uv venvを使用。https://docs.astral.sh/uv/ を参照。 - pre-commit はruff(リント+フォーマット)、gitleaks、標準的な衛生フックを実行。
pre-commit installで一度インストール。 - gitleaks はすべてのコミットで秘密情報をスキャン。誤検知の場合は、
.gitleaks.tomlで理由をコメント付きで許可リストに追加 — 検出結果を削除しない。 - pytest をテストに使用(
pytest、asyncio モード = auto)。テストはtests/の下に配置。
ワークフローの期待
- ファイルを編集する前に読む。見ていないコードに変更を提案しない。
- タスクが完了したと宣言する前に
ruff format+ruff check --fixを実行。 - フックをバイパスしない(
--no-verify)— 根本的な問題を修正する。 - 自分自身やClaudeをコミット作成者/共同作成者として追加しない。具体的には:
Co-Authored-By: Claude …トレーラーなし、🤖 Generated with Claude Codeフッターなし — コミットメッセージは本文で終了し、それ以上は何も追加しない。 - 新しいファイルを作成するよりも既存のファイルを編集することを優先。特に指示がない限り、README/ドキュメントファイルを作成しない。
- 変更がストリーミングパイプラインに影響する場合は、PRの説明に手動でレイテンシの影響を記述する。
- マークダウンドキュメント(
docs/、website/、README.md、PR説明)では、ASCIIアートよりもMermaid図を優先。 GitHubとVitePressはmermaidフェンスブロックをネイティブにレンダリング。手描きのボックスアンドラインASCIIは読みにくく、クリーンに編集できず、等幅フォントの変更で壊れる。許容される唯一のASCII図はディレクトリツリー(├──/└──)— これらはそのままにする。
ドキュメント作成(docs/、README.md、website/)
(,),@,:,,,&,<br/>、または英数字、_、-以外の句読点を含むMermaidラベルは、常に引用符で囲む。 ノードには["foo(args)"]、エッジラベルには-->|"@tool call"|を使用。クオートされていない括弧が[...]や|...|内にあると、フローチャートパーサーが静かに壊れる — ページは読み込まれるが図は消える。Mermaidブロックを編集した後は、ローカルでページを開き(npm run docs:dev)、ブラウザコンソールにParse error on line Nのエントリがないことを確認する。この破損はソースレビューでは見えない。- 完了宣言の前に、開発サーバーでドキュメントをテストする。
npm run docs:dev(:5173上のVitePress)は、マークダウンソースが隠すMermaidパースエラー、壊れたリンク、デッドアンカーをキャッチする。視覚的な変更(新しい図、レイアウト、ヒーロー、サイドバー)の場合は、影響を受けるページのPlaywrightスクリーンショットをキャプチャして、レビューアがサーバーを起動せずに回帰を確認できるようにする。 - ページ間リンクはルート絶対パス、拡張子なし —
/documentation/hooks、決して./hooks.mdやhooksではない(後者はcleanUrls: trueの下で間違って解決される)。Mermaidノードクリックターゲットも同じ規則に従う。 - サイドバーへの登録は必須。
docs/documentation/の下の新しいページは、docs/.vitepress/config.tsのsidebarブロックに追加されるまで表示されない。両方を同時に更新する。
やってはいけないこと
- クラウドAPI呼び出しやテレメトリを追加しない。EdgeVoxはオフラインファースト。
- GPLライセンスの依存関係を導入しない(プロジェクトはMIT)。
- 新しい依存関係を追加する前に、ライセンスの確認が必須。 パッケージの実際のライセンス(PyPI/GitHub/ドキュメント — 単なる推測ではなく)を確認し、結果を
pyproject.tomlの依存関係の横にインラインで記録する(例:# MIT/# LGPL-3 — dynamic-linked, compatible)。拒否すべきコピーレフトライセンス:GPL-2/3、AGPL、SSPL。LGPLは純粋な動的リンクライブラリ(PySide6、Qt Multimedia、rlottie)の場合のみ許容。CC-BY-SAはアセット(SVGピースセットなど)にのみ許容され、ソースレベルの依存関係には絶対に使用しない。疑わしい場合は、寛容な代替案を選ぶか、議論のためにフラグを立てる。 dist/、build/、*.egg-info/、モデル重み、録音をコミットしない。- タスクが必要とする以上の投機的な抽象化や「将来性確保」を追加しない。