本文へスキップ

アーキテクチャ

10クレートで構成されるCargoワークスペース設計: クレートの役割、分離不変条件、そしてCLIブートストラップからマルチレイヤーエージェントのオーケストレーションを経てTUIに至るデータフロー。

stepperはRustで構築されたレイヤード型のCLI/TUI AIコーディングエージェントで、10クレートで構成されるCargoワークスペースとして構造化されています。本ページでは、クレート構成、CLIブートストラップからエージェント実行までのデータフロー、そしてクリーンなアーキテクチャ境界を保証する中核的な分離不変条件を概説します。

クレート概要

ワークスペースには(当初計画された13個のうち)10個のクレートが実装されており、それぞれがシステム内で固有の責務を担います:

クレート役割
stepper-protocolチャネル型とDTO: Action(TUI→core)、AppEvent(core→TUI)、ApprovalRequest(oneshot)。serde、uuid、tokioの同期プリミティブのみに依存します。
stepper-tuiインラインビューポートを備えたRatatuiベースのTUI。stepper-protocolのみに依存します(これにratatuiスタックを加えます)。
stepper-cliClap CLIバイナリ。RealCoreを接続し(デフォルト=TUIエージェント、-pフラグ=ヘッドレス自動承認モード)、auth loginconfiginitコマンドとMCPサーバーのライフサイクルを処理します。
stepper-providerLLMプロバイダー向けのトレイトと正規化された型: ChatRequestMessageContentBlockChatEventUsageStopReasonToolSpec。HTTPを含まず、reqwestもtokio-rtも使用しません。
stepper-providers具体的なプロバイダーアダプター(Anthropic、OpenAI互換、Responses)、認証(APIキー、OAuth Codex)、reqwest+SSEによるストリーミング、キーリングへのトークン保存。
stepper-config設定の読み込み: .stepper/の探索、setting.jsonのディープマージ、frontmatterのパース(YAML)、置換エンジン、モデル/プロバイダーの解決、JSONスキーマ検証。
stepper-permission純粋な権限評価エンジン: deny > ask > allow > modeの優先順位、bashのリダイレクト/コマンドのパース、シンボリックリンクによる脱出の防止、パスの正規化。
stepper-toolsToolトレイトとレジストリ。9個の組み込みツール(read/write/edit/bash/search/grep/todo/web_fetch)、MCPツールのブリッジ、秘密パスの検出、ToolCxによる権限ゲーティング。
stepper-mcpMCP 1.7クライアント(stdio/HTTPトランスポート)、ツールのネームスペーシング、タイムアウト、ローカルツールレジストリとの統合。context7で検証済み。
stepper-coreメインオーケストレーター: プロバイダーの解決、AgentLoop(ReActパターン)、マルチステップパイプライン、並列レイヤー実行、セッション/チェックポイント管理、ハンドオフの要約、組み込みスラッシュコマンド。

分離不変条件

3つの厳格なアーキテクチャ境界が、cargo metadata解析を用いたCIテスト(crates/stepper-cli/tests/isolation.rs)によって強制されます:

  • stepper-tuistepper-protocolのみに依存します(これにratatuiを加えます)。core、config、providers、HTTPアクセスは一切ありません。
  • reqwestとHTTPはstepper-providersstepper-tools(web_fetch)、stepper-mcp(HTTPトランスポート)に限定されます。stepper-protocolstepper-providerトレイトはHTTPを含まず、tokio-rtも使用しません。
  • stepper-protocolはclapを使用しません(チャネル契約にCLIパースが含まれない)。

高レベルのデータフロー

text
stepper-cli main.rs (#[tokio::main])
  ├─ build_orchestrator(model, mode, cwd)
  │    Config::load → build_steps(layer frontmatter+skills) → ensure_provider(convention fallback)
  │    McpManager::connect(mcpServers) → register tools to base_tools
  │    ConfigProviderResolver + RuleSet + HookHost
  ├─ channels: mpsc<Action>(TUI→core) + mpsc<AppEvent>(core→TUI) + CancellationToken
  ├─ stepper-core::spawn_core(orchestrator, session, action_rx, cancel) → event_rx  [RealCore]
  │    while action:
  │      SubmitInput → checkpoint_turn → Orchestrator.run_turn → session append/save
  │      SlashCommand → commands::expand(substitution) → run_turn
  │      Rewind → restore+turns truncate
  │      RunShell → bash tool single-turn execution
  │    Orchestrator.run_turn: SessionStart → step layers (sequence or parallel):
  │      resolver.resolve(model) → Box<dyn LlmProvider>
  │      base_tools.filtered(allow/deny).filter_mcp
  │      ToolCx{cwd, project_root, mode, rules, approver=ChannelApprover, cancel}
  │      AgentLoop.drive(system, handoff): stream→token/usage emit→compact→tool exec
  │        (gate→approver) → result injection → repeat
  │      emit: LayerStarted/Finished/ModelChanged/UsageUpdated/ToolCall* → handoff
  └─ stepper-tui::run_tui(event_rx, action_tx, init, cancel)
       blocking input thread(event::poll/read) → mpsc → select!{input, 33ms tick, AppEvent rx, cancel}
       input → (mode-dependent) Action → AppState.apply_action → Effect(Send/CommitToScrollback)
       ApprovalRequested(oneshot) → overlay y/a/n → reply.send (resumes agent loop)
spawn_fake_core(モック)はウォーキングスケルトンのテスト用にstepper-tuiに残っていますが、CLIはRealCore(stepper-core::spawn_core)のみを使用します。両者は同一のチャネル契約を満たすため、相互に置き換え可能です。

主要な型と契約

  • **チャネル契約**(固定): mpsc<Action> + mpsc<AppEvent> + CancellationToken。RealCoreとモックの両方が満たします。
  • **LlmProvider**: chat_stream(req, cancel) → BoxStream<ChatEvent>を実装します。正規化はWireDeltaStreamAccumulatorChatEventの経路で行われます。
  • **Tool**: spec() / call(args, cx) → ToolResultを実装します。ToolCx.gate(PermissionRequest)が権限評価と承認ゲーティングを強制します。組み込みツールとMCPツールは同じトレイトを使用します。
  • **ProviderResolver**: モデル参照 → Box<dyn LlmProvider> + ModelInfoConfigProviderResolverが実装します。
  • **Approver**(tools) → **ChannelApprover**(core): Ask判定時にAppEvent::ApprovalRequested{oneshot}を発生させ → TUIオーバーレイ → ユーザー応答 → エージェントループを再開します。
  • **Orchestrator / AgentLoop**: run_turn → ステップレイヤー(それぞれ独立したコンテキスト、プロバイダー、ツールを持つ) → AgentLoop.drive(ReActパターン)。ハンドオフ = フリーテキストの要約チェーン。
  • **セッションとチェックポイント**: SessionStore(.stepper/sessions/<id>.json)、Snapshotter(.stepper/checkpoints/<turn>/のファイルコピー)。--resumeresume_contextをシードし、Rewindは復元・整理・ターンの切り詰めを行います。

高度な機能

  • **並列レイヤー**: parallel: true(および任意のparallel-maxワーカー上限)が設定されたステップは、オーケストレーターが前のレイヤーのassign_tasksリストをワーカーにファンアウトさせます。各ワーカーはサブエージェントです。タスクリストがない場合は逐次実行にフォールバックします。
  • **組み込みスラッシュコマンド**: /help/clear(セッションのリセット)、/model [provider/model-id](検証 + 最初のステップの切り替え + ModelChangedイベント)、/context(コンテキストウィンドウの要約)。
  • **スキル**: レイヤーがfrontmatterにskillsを宣言すると、SkillToolを通じてモデルがskill { name }を呼び出してレイヤー固有のスキルを利用できます。プログレッシブディスクロージャー: スキル名と説明はシステムプロンプトに提示され、本文はオンデマンドで提供されます。
  • **dispatchツール**(C4): モデルはdispatch(...)を呼び出して、現在のレイヤー以降に並列サブエージェント(ワーカー)を生成できます。オーケストレーターが有効化する必要があり、サブエージェントは再帰できません。
  • **プロンプトキャッシュ**: ChatRequest.cache: boolオプションがAnthropicのプレフィックスキャッシュを有効にし、システムメッセージはcache_control: ephemeralでラップされます。
  • **モデル駆動コンパクション**: compaction.providerが構成されている場合、オーケストレーターはソフトしきい値(コンテキストの0.70)で当該プロバイダーのモデルを用いてメッセージ履歴を要約し、直近6件のメッセージはそのまま保持します。
  • **権限ゲーティング**: ToolCx::gate(request)はモード(Auto/Plan/AcceptEdits)に対してルールを評価します。リダイレクト/$()を含むbashアトムはAskを引き上げ、明示的な承認を要求させます。
  • **MCPタイムアウト**: 接続タイムアウト(デフォルト10秒、STEPPER_MCP_CONNECT_TIMEOUT_MS)は起動時にハングしたサーバーを防ぎます。ツール呼び出しタイムアウト(デフォルト120秒、STEPPER_MCP_TOOL_TIMEOUT_MS)はターン途中のハングを防ぎます。

ビルドとテスト

sh
cargo check --workspace                       # Type check
cargo clippy --workspace --all-targets        # Lint (0 warnings enforced)
cargo test --workspace                        # full network-less suite (live mcp_live/e2e skip if env unset)
cargo run                                     # Interactive TUI (real tty + API keys required)
cargo run -- -p "..." --model anthropic/claude-x   # Headless one-shot (auto-approve)
cargo run -- --resume <session-id>            # Resume session
cargo run -- auth login --codex               # Codex OAuth login
cargo run -- config --schema | --validate     # Settings schema/validation
cargo run -- init                             # Scaffold .stepper/ (stepper.md + setting.json)