# TAKT 実行エンジン詳細 ## 通常 Movement の実行 通常の movement(`parallel` フィールドを持たない movement)は、Task tool で1つのエージェントを起動する。 ### Task tool の呼び出し ``` Task tool: subagent_type: "general-purpose" description: "{movement名} - {ピース名}" (3-5語) prompt: <後述のプロンプト構築で組み立てた内容> mode: ``` ### permission_mode の決定 movement の `edit` フィールドと `permission_mode` フィールドから決定する: | edit | permission_mode | Task tool の mode | |------|----------------|-------------------| | true | 未指定 | "bypassPermissions" | | true | "edit" | "bypassPermissions" | | true | "full" | "bypassPermissions" | | false | 未指定 | "default" | | false | "readonly" | "default" | `edit: false` の movement は読み取り専用。`edit: true` の movement はファイル編集が可能。 ## Parallel Movement の実行 `parallel` フィールドを持つ movement は、複数のサブステップを並列実行する。 ### 実行手順 1. parallel 配列の各サブステップに対して Task tool を起動する 2. **全ての Task tool を1つのメッセージで並列に呼び出す**(依存関係がないため) 3. 全エージェントの完了を待つ 4. 各サブステップの出力を収集する 5. 各サブステップの出力に対して、そのサブステップの `rules` で条件マッチを判定する 6. 親 movement の `rules` で aggregate 評価(all()/any())を行う ### サブステップの条件マッチ判定 各サブステップの出力テキストに対して、そのサブステップの `rules` の中からマッチする condition を特定する。 判定方法(通常 movement の Rule 評価と同じ優先順位): 1. `[STEP:N]` タグがあればインデックスで照合(最後のタグを採用) 2. タグがなければ、出力全体を読んでどの condition に最も近いかを判断する マッチした condition 文字列を記録する(次の aggregate 評価で使う)。 ## プロンプト構築 各 movement のエージェント起動時、以下を結合してプロンプトを組み立てる。 ### 構成要素(上から順に結合) ``` 1. エージェントプロンプト(agent: で参照される .md の全内容) 2. ---(区切り線) 3. 実行コンテキスト情報 4. instruction_template の内容(テンプレート変数を展開済み) 5. ユーザーのタスク({task} が template に含まれない場合、末尾に自動追加) 6. 前の movement の出力(pass_previous_response: true の場合、自動追加) 7. レポート出力指示(report フィールドがある場合、自動追加) 8. ステータスタグ出力指示(rules がある場合、自動追加) ``` ### 実行コンテキスト情報 ``` ## 実行コンテキスト - ワーキングディレクトリ: {cwd} - ピース: {piece_name} - Movement: {movement_name} - イテレーション: {iteration} / {max_iterations} - Movement イテレーション: {movement_iteration} 回目 ``` ### テンプレート変数の展開 `instruction_template` 内の以下のプレースホルダーを置換する: | 変数 | 値 | |-----|-----| | `{task}` | ユーザーが入力したタスク内容 | | `{previous_response}` | 前の movement のエージェント出力 | | `{iteration}` | ピース全体のイテレーション数(1始まり) | | `{max_iterations}` | ピースの max_iterations 値 | | `{movement_iteration}` | この movement が実行された回数(1始まり) | | `{report_dir}` | レポートディレクトリパス | | `{report:ファイル名}` | 指定レポートファイルの内容(Read で取得) | ### {report:ファイル名} の処理 `instruction_template` 内に `{report:04-ai-review.md}` のような記法がある場合: 1. レポートディレクトリ内に対応するレポートファイルがあれば Read で読む 2. 読み込んだ内容をプレースホルダーに展開する 3. ファイルが存在しない場合は「(レポート未作成)」に置換する ### agent フィールドがない場合 `agent:` が指定されていない movement の場合、エージェントプロンプト部分を省略し、`instruction_template` の内容のみでプロンプトを構成する。 ## レポート出力指示の自動注入 movement に `report` フィールドがある場合、プロンプト末尾にレポート出力指示を自動追加する。これにより、takt 本体の Phase 2(レポート出力フェーズ)を1回の呼び出しに統合する。 ### 形式1: name + format ```yaml report: name: 01-plan.md format: | # タスク計画 ## 元の要求 ... ``` → プロンプトに追加する指示: ``` --- ## レポート出力(必須) 作業完了後、以下のフォーマットに従ってレポートを出力してください。 レポートは ```markdown ブロックで囲んで出力してください。 ファイル名: 01-plan.md フォーマット: # タスク計画 ## 元の要求 ... ``` ### 形式2: 配列(複数レポート) ```yaml report: - Summary: summary.md - Scope: 01-scope.md ``` → プロンプトに追加する指示: ``` --- ## レポート出力(必須) 作業完了後、以下の各レポートを出力してください。 各レポートは見出し付きの ```markdown ブロックで囲んで出力してください。 1. Summary → ファイル名: summary.md 2. Scope → ファイル名: 01-scope.md ``` ### レポートの抽出と保存 エージェントの出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。 **レポートディレクトリ**: `.takt/reports/{timestamp}-{slug}/` に作成する(takt 本体と同じ構造)。 - `{timestamp}`: `YYYYMMDD-HHmmss` 形式 - `{slug}`: タスク内容の先頭30文字をスラグ化 抽出方法: - 出力内の ```markdown ブロックからレポート内容を取得する - ファイル名の手がかり(見出しやコメント)から対応するレポートを特定する - 特定できない場合は出力全体をレポートとして保存する ## ステータスタグ出力指示の自動注入 movement に `rules` がある場合、プロンプト末尾にステータスタグ出力指示を自動追加する。これにより、takt 本体の Phase 3(ステータス判定フェーズ)を1回の呼び出しに統合する。 ### 注入する指示 ``` --- ## ステータス出力(必須) 全ての作業とレポート出力が完了した後、最後に以下のいずれかのタグを出力してください。 あなたの作業結果に最も合致するものを1つだけ選んでください。 [STEP:0] = {rules[0].condition} [STEP:1] = {rules[1].condition} [STEP:2] = {rules[2].condition} ... ``` ### ai() 条件の場合 condition が `ai("条件テキスト")` 形式の場合でも、同じくタグ出力指示に含める: ``` [STEP:0] = 条件テキスト [STEP:1] = 別の条件テキスト ``` これにより、エージェントが自ら判断して適切なタグを出力する。ai() の括弧は除去して condition テキストのみを表示する。 ### サブステップの場合 parallel のサブステップにも同様にタグ出力指示を注入する。サブステップの rules からタグリストを生成する。 ## Rule 評価 movement 実行後、エージェントの出力テキストからどの rule にマッチするかを判定する。 ### 通常 Movement の Rule 評価 判定優先順位(最初にマッチしたものを採用): #### 1. タグベース検出(優先) エージェント出力に `[STEP:N]` タグ(N は 0始まりのインデックス)が含まれる場合、そのインデックスに対応する rule を選択する。複数のタグがある場合は **最後のタグ** を採用する。 例: rules が `["タスク完了", "進行できない"]` で出力に `[STEP:0]` → "タスク完了" を選択 #### 2. フォールバック(AI 判定) タグが出力に含まれない場合、出力テキスト全体を読み、全ての condition と比較して最もマッチするものを選択する。 **出力テキストの判定例**: - rules: `["実装完了", "判断できない"]` - 出力: 「全てのファイルを修正し、テストもパスしました。」 - → "実装完了" にマッチ ### Parallel Movement の Rule 評価(Aggregate) 親 movement の rules に `all()` / `any()` の aggregate 条件を使用する。 #### all() の評価 ```yaml - condition: all("approved") next: COMPLETE ``` **引数が1つ**: 全サブステップのマッチ条件が "approved" であれば true。 ```yaml - condition: all("AI特有の問題なし", "すべて問題なし") next: COMPLETE ``` **引数が複数(位置対応)**: サブステップ1が "AI特有の問題なし" にマッチ AND サブステップ2が "すべて問題なし" にマッチ であれば true。 #### any() の評価 ```yaml - condition: any("needs_fix") next: fix ``` いずれかのサブステップのマッチ条件が "needs_fix" であれば true。 ```yaml - condition: any("AI特有の問題あり") next: ai_fix ``` **引数が1つ**: いずれかのサブステップが "AI特有の問題あり" にマッチすれば true。 #### Aggregate 評価の順序 親 rules を上から順に評価し、最初にマッチした rule を採用する。 ### Rule にマッチしない場合 全ての rule を評価してもマッチしない場合は ABORT する。エラーメッセージとともに、マッチしなかった出力の要約をユーザーに報告する。 ## ループ検出 ### 基本ルール - 同じ movement が連続3回以上実行されたら警告を表示する - `max_iterations` に到達したら強制終了(ABORT)する ### カウンター管理 以下のカウンターを管理する: | カウンター | 説明 | リセットタイミング | |-----------|------|-------------------| | `iteration` | ピース全体の movement 実行回数 | リセットしない | | `movement_iteration[name]` | 各 movement の実行回数 | リセットしない | | `consecutive_count[name]` | 同じ movement の連続実行回数 | 別の movement に遷移したとき | ## Loop Monitors ピースに `loop_monitors` が定義されている場合、特定の movement サイクルを監視する。 ### 動作 ```yaml loop_monitors: - cycle: [ai_review, ai_fix] threshold: 3 judge: agent: ../agents/default/supervisor.md instruction_template: | サイクルが {cycle_count} 回繰り返されました... rules: - condition: 健全 next: ai_review - condition: 非生産的 next: reviewers ``` ### 検出ロジック 1. movement 遷移履歴を記録する(例: `[plan, implement, ai_review, ai_fix, ai_review, ai_fix, ...]`) 2. 各 loop_monitor の `cycle` パターン(例: `[ai_review, ai_fix]`)が履歴の末尾に `threshold` 回以上連続で出現するかチェックする 3. 閾値に達した場合: a. judge の `agent` を Read で読み込む b. `instruction_template` の `{cycle_count}` を実際のサイクル回数に置換する c. Task tool で judge エージェントを起動する d. judge の出力を judge の `rules` で評価する e. マッチした rule の `next` に遷移する(通常のルール評価をオーバーライドする) ## レポート管理 ### レポートディレクトリの作成 ピース実行開始時にレポートディレクトリを作成する: ``` .takt/reports/{YYYYMMDD-HHmmss}-{slug}/ ``` このパスを `{report_dir}` 変数として全 movement から参照可能にする。 ### レポートの保存 エージェント出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。 抽出手順: 1. 出力内の ```markdown ブロックを検索する 2. レポートのファイル名やセクション見出しから対応するレポートを特定する 3. Write tool で `{report_dir}/{ファイル名}` に保存する ### レポートの参照 後続の movement の `instruction_template` 内で `{report:ファイル名}` として参照すると、engine がそのレポートファイルを Read して内容をプレースホルダーに展開する。 ## 状態遷移の全体像 ``` [開始] ↓ レポートディレクトリ作成 ↓ initial_movement を取得 ↓ ┌─→ movement を実行 │ ├── 通常: Task tool (1エージェント) │ │ prompt = agent.md + context + instruction + task │ │ + previous_response + レポート指示 + タグ指示 │ └── parallel: Task tool (複数エージェント並列) │ 各サブステップも同様のプロンプト構築 │ ↓ │ 出力からレポート抽出 → Write で保存 │ ↓ │ Loop Monitor チェック(該当サイクルがあれば judge 介入) │ ↓ │ Rule 評価 │ ├── タグ検出 [STEP:N] → rule 選択 │ └── タグなし → AI フォールバック判定 │ ├── parallel: サブステップ条件 → aggregate(all/any) │ ↓ │ next を決定 │ ├── COMPLETE → [成功終了] ユーザーに結果報告 │ ├── ABORT → [失敗終了] ユーザーにエラー報告 │ └── movement名 → ループ検出チェック → 次の movement │ ↓ └──────────────────────────────────────────────┘ ```