パイプラインステップ
パイプラインのステップには、互いに独立した 2 つの軸があります:
- 種別(
StepKind)— エンジンがトリガーに対してそのステップをどのようにスケジュールするか。 - ボディキー(
BuiltInBodyKeys)— 登録されたどのボディクロージャがステップの作業を実行するか。
ステップの種類
「ステップの種類」というセクションpackages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart で定義されています。
| 種別 | スケジューリングのセマンティクス |
|---|---|
trigger |
必須のエントリーポイント — テンプレートごとにちょうど 1 つで、常に最初のノードです。それ自体は何の作業も行いません。実行を開始するもの(手動/イベント/スケジュール)は PipelineTrigger の行として別途追跡されます。そのボディは何もしない pipeline.trigger です。 |
listen |
すべてのソースステップ(StepTrigger.sourceStepIds 内)が完了したときに発火します。 |
join |
waitForStepIds 内のすべてのステップが終端状態に達したときに発火します。 |
router |
条件分岐 — ボディは StepResult.route(key) を返し、routeKey が一致する下流のエッジだけを発火させます。選択されなかったブランチはスキップ済みとしてマークされます。 |
forEach |
listen と同じようにスケジュールされます(すべての sourceStepIds が完了したときに発火)。反復するのは登録された flow.forEach ボディであり、エンジンが項目ごとに子ステップを生成するわけではありません。 |
terminal |
ボディを持たないスケジューラーのセンチネルです。終端ステップが完了するとパイプライン実行が完了します。 |
ステップボディ
「ステップボディ」というセクションBuiltInBodyKeys(packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart)の定数をキーとして登録されたボディクロージャです。25 個あり、すべて下記に挙げます。特に断りのない限り、設定はステップの PipelineNodeConfig(下記参照)から読み取られます。「ステートキー」は実行時にパイプラインステート/トリガーペイロードから読み取られます。
bodyKey が登録されていないステップは、テンプレートの読み込み時に警告を出し、その後は決して実行されません — 実行を失敗させることはありません。trigger と terminal のステップはこの警告の対象外です。trigger は何もしない pipeline.trigger ボディを実行し、terminal ステップはボディを持ちません。
pipeline.trigger
「pipeline.trigger」というセクション必須の trigger ノードの何もしないボディです — 即座に完了し、エンジンが下流のリスナーへファンアウトできるようにします。設定はありません。
pipeline.bashScript
「pipeline.bashScript」というセクションエージェントを使わないシェルステップ(bash -c)です。スクリプト内の {{key}} プレースホルダーは、ステート + トリガーペイロードからシェルエスケープ済みの値で置換されます。
| 設定フィールド | 説明 |
|---|---|
script |
実行するシェルコマンド(必須) |
outputKey |
終了コード 0 のときにトリム済みの stdout を受け取るステートキー |
cwd を <cc_root>/pipelines/<pipelineRunId>/(実行内のすべての bash ステップで共有)とし、環境変数に GITHUB_TOKEN を設定して実行されます。また、<stepId>_runDir をステートに書き込みます。ゼロ以外の終了コードは、stderr の末尾とともにステップを失敗させます。
conversation.promptAgent
「conversation.promptAgent」というセクション汎用のプロンプト&ディスパッチノードです。プロンプトをレンダリングし、エージェントを会話へディスパッチし、その実行が完了するまでサスペンドします。エージェントの submit_output ペイロードは outputKey の下でステートに回収されます。
| 設定フィールド | 説明 |
|---|---|
agentId |
ディスパッチするワークスペーススコープのエージェント UUID(必須) |
prompt |
指示テキスト。{{key}} の置換に対応(必須) |
outputKey |
回収された出力のステートキー |
outputSchema |
出力が満たす必要のある JSON Schema |
label |
キャンバスに表示される人間向けラベル |
extras.spaceId |
作業対象とする既存の会話(デフォルト: 非表示の会話) |
extras.conversationTitle |
そのスペース内の名前付きストリーム(任意) |
extras.mode |
ここではなく、ルームを開くノード(messaging.createSpace)で読み取られます。デフォルトは review。 |
pipeline.condition
「pipeline.condition」というセクションルーターボディです — config.extras を読み取り、条件を評価して StepResult.route(key) を返します。条件は JavaScript 式ではありません。3 つの記述形式を優先順にサポートしています:
- 述語ツリー(
extras.predicate)—"true"/"false"にルーティングするブールツリーです。各ノードはtypeを持つマップです:{"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false}— リストされたパスのいずれかがディスク上に存在するときに true になります。negateはそれを反転させます。recursiveはサブディレクトリも検索します(.git、node_modules、build、.dart_toolをスキップ)。相対パスはstate[baseKey](デフォルトはrepo_local_path)を基準に解決され、そうでなければ実行ごとのワークスペースディレクトリを基準にします。{"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80}— 演算子はequals、notEquals、contains、exists、notExists、gt、ltです。ファイルシステムではなくパイプラインステートを読み取ります。{"type": "and" | "or", "of": [<predicate>, ...]}— ブールグループです。{"type": "not", "of": <predicate>}— 否定です。
- スイッチ(
extras.switchKey)—{"switchKey": "pr_class", "cases": [...], "default": "standard"}。ステートの値が大文字小文字を区別せずに含む最初の case へルーティングし、どれにも含まれなければdefaultへルーティングします。 - 比較(レガシーのトップレベル
extras.left/extras.op/extras.right)—comparison述語と同等で、ツリー以前に作成されたテンプレートのために残されています。
ノードから出るエッジは、返されたキーと一致しなければならない routeKey を持ちます。
prReview.comment
「prReview.comment」というセクション統合された指摘を、GitHub PR クライアントを介して PR レビューコメントとして投稿します。
| ステートキー | 説明 |
|---|---|
repo_full_name |
owner/repo(必須) |
pr_number |
PR 番号 — int または数値文字列(必須) |
consolidated_findings |
コメント本文(必須) |
ステートに comment_review_id と commented_at を伴う StepResult.terminal を返します。
messaging.postSpace
「messaging.postSpace」というセクションMessagingPort を介してメッセージングスペースにメッセージを投稿します。
| ステートキー | 説明 |
|---|---|
space_id |
対象のスペース(必須) |
content |
メッセージ本文。ステートからそのまま読み取られます(必須) |
posted_space_id と posted_at をステートに書き込みます。
team.dispatch
「team.dispatch」というセクション単一のエージェントではなくチーム全体をディスパッチし、メンバーの実行が完了するまでサスペンドします。
| 設定フィールド | 説明 |
|---|---|
teamId |
ディスパッチするワークスペーススコープのチーム(必須。agentId とは排他的) |
prompt |
ゴールのテキスト。{{key}} の置換に対応(必須) |
dispatchMode |
allParallel(デフォルト — メンバーごとに 1 タスク)または manager(調整役のリーダーだけをディスパッチ) |
outputKey |
回収されたメンバー出力のステートキー |
outputSchema, label, extras.spaceId |
conversation.promptAgent と同様 |
human.gate
「human.gate」というセクション承認ゲートです。承認者エージェントを、ゲートプロンプトと {decision, reason} の出力契約を伴って会話(review モード)へディスパッチし、承認者が submit_output を介して送信するまでサスペンドします。
| 設定フィールド | 説明 |
|---|---|
agentId |
承認者エージェント(必須) |
prompt |
ゲートプロンプト(任意。省略時はデフォルトが使われます) |
outputKey |
回収された {decision, reason} ペイロードのステートキー |
outputSchema |
デフォルトは承認スキーマ(decision: approved / rejected、reason) |
label, extras.spaceId |
conversation.promptAgent と同様 |
ゲートは submit_output を介してのみ解決されます。BuiltInBodyKeys.humanGate、ノードタイプライブラリ、およびある組み込みテンプレートのプロンプトテキストは、いずれも approve_step と reject_step という MCP ツールを指していますが、どちらのツールもどのパッケージやレジストリにも存在しません。
repos.cleanup
「repos.cleanup」というセクション古くなった分離ワークツリーを削除します。モードはトリガーペイロードから選びます。実行の dryRun フラグを尊重します。
| ステートキー | 説明 |
|---|---|
ticket_id |
そのチケットのワークツリーを解放します |
repo_full_name + pr_number |
一時的な PR エディターのワークツリーを解放します |
space_id |
その会話のワークツリーとフォルダを破棄します |
| (上記のいずれでもない) | ワークスペースをスイープします: 消えたディレクトリ、死んだスペース、孤立した会話フォルダ |
outputKey(任意)は要約文字列を受け取ります。
flow.forEach
「flow.forEach」というセクションステートのコレクションに対するマップ/ファンアウトです。項目ごとにプロンプトを 1 回レンダリングし、それらのプロンプトを連結した(--- 区切り)うえでエージェントを1 回ディスパッチし、その実行が完了するまでサスペンドします。空のコレクションは、空のリストとともに即座に完了します。項目ごとに 1 回ずつ並列ディスパッチするわけではありません。
| 設定フィールド | 説明 |
|---|---|
agentId |
項目ごとにディスパッチするエージェント(必須) |
prompt |
項目ごとのプロンプト。{{key}} の置換に対応(必須) |
extras.iterableKey |
コレクションを保持するステートキー(必須) |
extras.itemKey |
プロンプト内で現在の項目がバインドされるキー(デフォルトは item) |
outputKey |
回収された出力のステートキー(1 回のディスパッチで、リストではありません) |
flow.callPipeline
「flow.callPipeline」というセクション別のパイプラインテンプレートをネストされたサブステップとして実行します(サブパイプラインは parentPipelineRunId が設定された子実行として実行されます)。ステップは子が終端状態に達するまでサスペンドし、その後、子の最終ステートが outputKey の下にマージされます。
| 設定フィールド | 説明 |
|---|---|
extras.templateId |
実行する子テンプレート(必須。パイプラインは自身を呼び出せません) |
inputKeys |
子のトリガーペイロードへコピーされるステートキー |
outputKey |
子のマージされた最終ステートのステートキー |
code.index
「code.index」というセクションバックグラウンドの tree-sitter インデックス作成です。リポジトリを走査し、ワーカーアイソレートでシンボル/エッジを抽出して、ワークスペースのコードグラフに取り込みます。進捗はステップ実行の行へストリーミングされます。ドライランに対応します。tree-sitter とその文法は必須のネイティブであり、dylib が欠けていればサーバーは起動すらしていません。実行中に解決に失敗する文法は、スキップされるのではなくステップを失敗させます。
| ステートキー | 説明 |
|---|---|
repo_id |
インデックスを作成するリポジトリ(必須) |
repo_local_path |
チェックアウトのローカルパス(必須) |
meeting.diarize
「meeting.diarize」というセクションオフラインの話者分離です。ミーティングで保持されている音声を読み込み、話者(Person 1、Person 2、…)へクラスタリングし、文字起こしのセグメントにラベルを付け直し、transcript ステートを書き換えます。並行する meeting.updateTranscript ステップ向けに diarization_spans も出力します。音声が保持されていない場合やモデルがインストールされていない場合は、文字起こしをそのまま通します。
| ステートキー | 説明 |
|---|---|
meeting_id |
話者分離するミーティング(必須) |
meeting.saveNotes, meeting.addActionItems, meeting.addDecisions
「meeting.saveNotes, meeting.addActionItems, meeting.addDecisions」というセクション決定論的なミーティング要約の永続化ボディです。それぞれが、ステートから meeting_id とエージェントステップの構造化された meeting_outcome ペイロード({summary, enhancedNotes, actionItems[], decisions[]})を読み取り、自身の担当部分(ノート、アクションアイテム、または決定事項)を自身のテーブルに書き込みます。以前に保存された行が、劣化した実行で消去されることはありません。
その他の組み込みボディ
「その他の組み込みボディ」というセクション| ボディキー | 説明 |
|---|---|
meeting.identifySpeakers |
ミーティングをまたぐ話者認識です。話者分離された話者を保存済みの音声プロファイルと照合し、確度の高い一致を自動適用します。プロファイル/埋め込みがない場合は何もしません。 |
meeting.updateTranscript |
diarization_spans から Person N ラベルを適用し、ウィンドウごとの断片を話者ごとの発話へマージして、クリーンアップされた文字起こしを永続化します。話者分離が何も生成しなかった場合は何もしません。 |
meeting.assemblePlayback |
保持されているチャンネルごとの WAV から、ミーティングのミックス再生トラックを組み立てます。音声が保持されていない場合は何もしません。 |
orchestration.markPhase |
作業 DAG の最後に、出力のないサブチケットの失敗センチネルを書き込み、オーケストレーションを synthesizing に切り替えます。 |
orchestration.persistDeliverable |
統合の出力を親チケットに書き込み、それを完了させ、成果物を投稿して、オーケストレーションを completed としてマークします。 |
orchestration.awaitApproval |
部分承認ゲートです。ステップのノードキーがオーケストレーションの承認済みセットに含まれていれば即座に完了し、そうでなければ後続の承認が再開するまでサスペンドします。extras.awaitApproval を設定する唯一のボディであり、これにより 24 時間のサスペンドステップタイムアウトから免除されます。 |
messaging.createSpace |
テンプレートの残りの部分が作業する会話を開き、ステップの outputKey の下に公開します(組み込みでは pipeline_space_id を使用)。repoIds リストが空であれば何もチェックアウトしません。extras['allRepos'] はワークスペースのすべてのリポジトリをチェックアウトします。extras['createConversation'](デフォルトではオフ)は名前付きストリームも開きます。エージェントステップはルームに参加するだけで、ルームを開くことはないため、このノードのないファンアウトはディスパッチ時に失敗します。そしてこれを一度配線しておけば、ファンアウト全体が 1 つのチェックアウトを共有し、それぞれに 1 つずつ用意する必要がなくなります。 |
prReview.finalize |
PR レビューテンプレートの最後のステップです。蓄積されたレビューノードをコンセンサスバケットに振り分け、PR ごとの判定を算出します。 |
skills.analyze |
ワークスペースにインストールされたスキルに対してスキルのサプライチェーンスキャンを行い、各判定を記録します。 |
ステップの結果
「ステップの結果」というセクションステップボディは StepResult(packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart)を返します。すべてのファクトリは、パイプラインステートにマージされる任意の mutatedState マップを受け取りますが、failed は例外です。
| ファクトリ | シグネチャ | 説明 |
|---|---|---|
ok |
StepResult.ok({mutatedState}) |
通常の完了。下流のリスナーが評価されます |
route |
StepResult.route(nextRouterKey, {mutatedState}) |
ルーターの完了。routeKey が一致する下流のブランチを選択します |
suspendUntilEvent |
StepResult.suspendUntilEvent(eventType, {mutatedState}) |
特定のドメインイベント種別が発火するまで一時停止します |
suspendUntilTasksComplete |
StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) |
リストされたすべてのタスクが終端状態に達するまで一時停止します |
terminal |
StepResult.terminal({mutatedState}) |
パイプライン実行が終了しました — これ以上のステップはありません |
failed |
StepResult.failed(errorMessage) |
ステップがエラーメッセージとともに失敗しました |
StepRetryPolicy
「StepRetryPolicy」というセクション失敗するノードボディの再試行動作です(PipelineNodeConfig.retryPolicy。null は再試行を無効にします)。
| フィールド | 型 | 説明 |
|---|---|---|
maxAttempts |
int |
最初の試行を含む総試行回数(3 = 1 回の試行 + 2 回の再試行)。≥ 1 でなければなりません |
backoff |
String |
linear または exponential(デフォルト) |
initialDelayMs |
int |
最初の再試行前の遅延(ミリ秒)。以降の遅延は backoff に従って増加します |
PipelineNodeConfig
「PipelineNodeConfig」というセクションステップ定義の内部に保持されるノードごとの設定です(packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart)。組み込みノードとカスタムノードはどちらもこの形を共有し、各ボディは自身が関心のあるフィールドだけを読み取ります。
| フィールド | 型 | 説明 |
|---|---|---|
prompt |
String? |
{{key}} 置換対応のプロンプトテンプレート |
script |
String? |
{{key}} 置換対応の Bash スクリプトボディ |
agentId |
String? |
ディスパッチするワークスペーススコープのエージェント UUID |
inputKeys |
List<String> |
このノードが入力として消費するステートキー |
repoIds |
List<String> |
messaging.createSpace ノードがチェックアウトするリポジトリ(<repoId> または <repoId>@<branch>)。空 = なし。extras['allRepos'] = ワークスペースのすべてのリポジトリ。エージェントステップでは無視されます。 |
outputKey |
String? |
このノードの出力が書き込まれるステートキー |
label |
String? |
キャンバスに表示される人間向けラベル(デフォルトはステップ ID) |
outputSchema |
Map<String, dynamic>? |
出力値が満たす必要のある JSON Schema(サブセット) |
reducer |
String? |
並列ブランチが同じ outputKey に書き込むときのマージ戦略: append、mergeLists、mergeMaps、sum、または override(デフォルト) |
retryPolicy |
StepRetryPolicy? |
ボディ失敗時の再試行ポリシー。null = 1 回だけ試行 |
continueOnFail |
bool |
true のとき、終端の失敗は実行を失敗させません。エラーは state['_stepErrors'][stepId] の下に退避されます |
timeoutMs |
int? |
ノードボディの実時間タイムアウト(ミリ秒)。null = タイムアウトなし |
teamId |
String? |
ディスパッチするチーム(team.dispatch ノード)。agentId とは排他的 |
dispatchMode |
String? |
チームの実行モード: allParallel または manager |
extras |
Map<String, dynamic> |
自由形式のボディ固有の設定(例: iterableKey、templateId、条件ツリー) |
派生アクセサー: spaceId(extras['spaceId'] — 作業対象とする既存の会話)、createsConversation(extras['createConversation'])、conversationTitle(extras['conversationTitle'])、modeName(extras['mode'] — chat / review / plan。スペースを開くノードで読み取られます)、runWhen(extras['runWhen'] — 満たされない場合はノードをスキップします)。