nrslib 8dcb23b147 fix: export-cc で facets/ のディレクトリ構造を保持するよう修正
ファセットを ~/.claude/skills/takt/personas/ 等に展開していたが、
ビルトインのピースYAMLで ../facets/personas/ という相対パスを
使用しているため、facets/ ディレクトリを維持する必要があった。
deploySkill.ts、SKILL.md、engine.md のパス例も合わせて修正。
2026-03-04 01:30:11 +09:00

17 KiB
Raw Blame History

TAKT 実行エンジン詳細

チームメイトの起動方法

全ての movement は Task tool でチームメイトを起動して実行する。 あなたTeam Leadが直接作業することは禁止。

Task tool の呼び出し

Task tool:
  subagent_type: "general-purpose"
  team_name: "takt"
  name: "{movement_name}"
  description: "{movement_name} - {piece_name}"
  prompt: <プロンプト構築で組み立てた内容>
  mode: permission_mode

permission_mode

コマンド引数で解析された permission_mode をそのまま Task tool の mode に渡す。

  • /takt coding --permit-full タスクpermission_mode = "bypassPermissions"(確認なし)
  • /takt coding --permit-edit タスクpermission_mode = "acceptEdits"(編集は自動許可)
  • /takt coding タスクpermission_mode = "default"(権限確認あり)

通常 Movement の実行

通常の movementparallel フィールドを持たないは、Task tool で1つのチームメイトを起動する。

  1. プロンプトを構築する(後述の「プロンプト構築」参照)
  2. Task tool でチームメイトを起動する
  3. チームメイトの出力を受け取る
  4. Rule 評価で次の 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 評価で使う)。

セクションマップの解決

ピースYAMLのトップレベルにある personas:, policies:, instructions:, output_contracts:, knowledge: はキーとファイルパスの対応表。movement 内ではキー名で参照する。

解決手順

  1. ピースYAMLを読み込む
  2. 各セクションマップのパスを、ピースYAMLファイルのディレクトリを基準に絶対パスに変換する
  3. movement の persona: coderpersonas: セクションの coder キー → ファイルパス → Read で内容を取得

例: ピースが ~/.claude/skills/takt/pieces/default.yaml の場合

  • personas.coder: ../facets/personas/coder.md~/.claude/skills/takt/facets/personas/coder.md
  • policies.coding: ../facets/policies/coding.md~/.claude/skills/takt/facets/policies/coding.md
  • instructions.plan: ../facets/instructions/plan.md~/.claude/skills/takt/facets/instructions/plan.md

プロンプト構築

各チームメイト起動時、以下を結合してプロンプトを組み立てる。

構成要素(上から順に結合)

1. ペルソナプロンプトpersona: で参照される .md の全内容)
2. ---(区切り線)
3. ポリシーpolicy: で参照される .md の内容。複数ある場合は結合)
4. ---(区切り線)
5. 実行コンテキスト情報
6. ナレッジknowledge: で参照される .md の内容)
7. インストラクション内容instruction: で参照される .md、または instruction_template のインライン内容)
8. ユーザーのタスク({task} が template に含まれない場合、末尾に自動追加)
9. 前の movement の出力pass_previous_response: true の場合、自動追加)
10. レポート出力指示report フィールドがある場合、自動追加)
11. ステータスタグ出力指示rules がある場合、自動追加)
12. ポリシーリマインダー(ポリシーがある場合、末尾に再掲)

ペルソナプロンプト

movement の persona: キーからセクションマップを経由して .md ファイルを解決し、その全内容をプロンプトの冒頭に配置する。ペルソナはドメイン知識と行動原則のみを含む(ピース固有の手順は含まない)。

ポリシー注入

movement の policy: キー(単一または配列)からポリシーファイルを解決し、内容を結合する。ポリシーは行動ルール(コーディング規約、レビュー基準等)を定義する。

Lost in the Middle 対策: ポリシーはプロンプトの前半に配置し、末尾にリマインダーとして再掲する。

(プロンプト冒頭付近)
## ポリシー(行動ルール)
{ポリシーの内容}

(プロンプト末尾)
---
**リマインダー**: 以下のポリシーに従ってください。
{ポリシーの内容(再掲)}

ナレッジ注入

movement の knowledge: キーからナレッジファイルを解決し、ドメイン固有の参考情報としてプロンプトに含める。

## ナレッジ
{ナレッジの内容}

インストラクション

movement の instruction: キーから指示テンプレートファイルを解決する。または instruction_template: でインライン記述。テンプレート変数({task}, {previous_response} 等)を展開した上でプロンプトに含める。

実行コンテキスト情報

## 実行コンテキスト
- ワーキングディレクトリ: {cwd}
- ピース: {piece_name}
- Movement: {movement_name}
- イテレーション: {iteration} / {max_movements}
- Movement イテレーション: {movement_iteration} 回目

テンプレート変数の展開

インストラクション内の以下のプレースホルダーを置換する:

変数
{task} ユーザーが入力したタスク内容
{previous_response} 前の movement のチームメイト出力
{iteration} ピース全体のイテレーション数1始まり
{max_movements} ピースの max_movements 値
{movement_iteration} この movement が実行された回数1始まり
{report_dir} レポートディレクトリパス(.takt/runs/{slug}/reports
{report:ファイル名} 指定レポートファイルの内容Read で取得)

{report:ファイル名} の処理

インストラクション内に {report:ai-review.md} のような記法がある場合:

  1. レポートディレクトリ内に対応するレポートファイルがあれば Read で読む
  2. 読み込んだ内容をプレースホルダーに展開する
  3. ファイルが存在しない場合は「(レポート未作成)」に置換する

persona フィールドがない場合

persona: が指定されていない movement の場合、ペルソナプロンプト部分を省略し、インストラクションの内容のみでプロンプトを構成する。

レポート出力指示の自動注入

movement に report フィールドがある場合、プロンプト末尾にレポート出力指示を自動追加する。

形式1: name + formatキー参照

report:
  name: 01-plan.md
  format: plan                 # output_contracts セクションのキー

output_contracts: セクションの plan キーから .md ファイルを解決し、Read で読んだ内容を出力契約指示に使う:

---
## レポート出力(必須)
作業完了後、以下の出力契約に従ってレポートを出力してください。
レポートは ```markdown ブロックで囲んで出力してください。

ファイル名: 01-plan.md
出力契約:
{output_contracts の plan キーの .md ファイル内容}

形式2: 配列(複数レポート)

report:
  - Summary: summary.md
  - Scope: 01-scope.md

→ プロンプトに追加する指示:

---
## レポート出力(必須)
作業完了後、以下の各レポートを出力してください。
各レポートは見出し付きの ```markdown ブロックで囲んで出力してください。

1. Summary → ファイル名: summary.md
2. Scope → ファイル名: 01-scope.md

レポートの抽出と保存

チームメイトの出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。 この作業は Team Leadあなたが行う。 チームメイトの出力を受け取った後に実施する。

実行ディレクトリ: .takt/runs/{timestamp}-{slug}/ に作成する。

  • レポートは .takt/runs/{timestamp}-{slug}/reports/ に保存する。
  • Knowledge / Policy / Previous Response.takt/runs/{timestamp}-{slug}/context/ 配下に保存する。
  • 最新の previous response は .takt/runs/{timestamp}-{slug}/context/previous_responses/latest.md とする。
  • {timestamp}: YYYYMMDD-HHmmss 形式
  • {slug}: タスク内容の先頭30文字をスラグ化

抽出方法:

  • 出力内の ```markdown ブロックからレポート内容を取得する
  • ファイル名の手がかり(見出しやコメント)から対応するレポートを特定する
  • 特定できない場合は出力全体をレポートとして保存する

ステータスタグ出力指示の自動注入

movement に rules がある場合、プロンプト末尾にステータスタグ出力指示を自動追加する。

注入する指示

---
## ステータス出力(必須)
全ての作業とレポート出力が完了した後、最後に以下のいずれかのタグを出力してください。
あなたの作業結果に最も合致するものを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 評価

チームメイトの出力からどの rule にマッチするかを判定する。

通常 Movement の Rule 評価

判定優先順位(最初にマッチしたものを採用):

1. タグベース検出(優先)

チームメイト出力に [STEP:N] タグN は 0始まりのインデックスが含まれる場合、そのインデックスに対応する rule を選択する。複数のタグがある場合は 最後のタグ を採用する。

例: rules が ["タスク完了", "進行できない"] で出力に [STEP:0] → "タスク完了" を選択

2. フォールバックAI 判定)

タグが出力に含まれない場合、出力テキスト全体を読み、全ての condition と比較して最もマッチするものを選択する。

Parallel Movement の Rule 評価Aggregate

親 movement の rules に all() / any() の aggregate 条件を使用する。

all() の評価

- condition: all("approved")
  next: COMPLETE

引数が1つ: 全サブステップのマッチ条件が "approved" であれば true。

- condition: all("AI特有の問題なし", "すべて問題なし")
  next: COMPLETE

引数が複数(位置対応): サブステップ1が "AI特有の問題なし" にマッチ AND サブステップ2が "すべて問題なし" にマッチ であれば true。

any() の評価

- condition: any("needs_fix")
  next: fix

いずれかのサブステップのマッチ条件が "needs_fix" であれば true。

Aggregate 評価の順序

親 rules を上から順に評価し、最初にマッチした rule を採用する。

Rule にマッチしない場合

全ての rule を評価してもマッチしない場合は ABORT する。エラーメッセージとともに、マッチしなかった出力の要約をユーザーに報告する。

ループ検出

基本ルール

  • 同じ movement が連続3回以上実行されたら警告を表示する
  • max_movements に到達したら強制終了ABORTする

カウンター管理

以下のカウンターを管理する:

カウンター 説明 リセットタイミング
iteration ピース全体の movement 実行回数 リセットしない
movement_iteration[name] 各 movement の実行回数 リセットしない
consecutive_count[name] 同じ movement の連続実行回数 別の movement に遷移したとき

Loop Monitors

ピースに loop_monitors が定義されている場合、特定の movement サイクルを監視する。

動作

loop_monitors:
  - cycle: [ai_review, ai_fix]
    threshold: 3
    judge:
      persona: supervisor
      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 パターンが履歴の末尾に threshold 回以上連続で出現するかチェックする
  3. 閾値に達した場合: a. judge の persona キーからペルソナファイルを Read で読み込む b. instruction_template{cycle_count} を実際のサイクル回数に置換する c. Task tool でチームメイトjudgeを起動する d. judge の出力を judge の rules で評価する e. マッチした rule の next に遷移する(通常のルール評価をオーバーライドする)

実行アーティファクト管理

実行ディレクトリの作成

ピース実行開始時に実行ディレクトリを作成する:

.takt/runs/{YYYYMMDD-HHmmss}-{slug}/
  reports/
  context/
    knowledge/
    policy/
    previous_responses/
  logs/
  meta.json

このうち reports/ のパスを {report_dir} 変数として全 movement から参照可能にする。

レポートの保存

チームメイト出力からレポート内容を抽出し、Write tool でレポートディレクトリに保存する。

抽出手順:

  1. 出力内の ```markdown ブロックを検索する
  2. レポートのファイル名やセクション見出しから対応するレポートを特定する
  3. Write tool で {report_dir}/{ファイル名} に保存する

レポートの参照

後続の movement のインストラクション内で {report:ファイル名} として参照すると、そのレポートファイルを Read して内容をプレースホルダーに展開する。

状態遷移の全体像

[開始]
  ↓
ピースYAML読み込み + セクションマップ解決personas, policies, instructions, output_contracts, knowledge
  ↓
TeamCreate でチーム作成
  ↓
実行ディレクトリ作成
  ↓
initial_movement を取得
  ↓
┌─→ Task tool でチームメイト起動
│     ├── 通常: 1つの Task tool 呼び出し
│     │     prompt = persona + policy + context + knowledge
│     │           + instruction + task + previous_response
│     │           + レポート指示 + タグ指示 + ポリシーリマインダー
│     └── parallel: 複数の Task tool を1メッセージで並列呼び出し
│           各サブステップを別々のチームメイトとして起動
│   ↓
│   チームメイトの出力を受け取る
│   ↓
│   出力からレポート抽出 → Write で保存Team Lead が実施)
│   ↓
│   Loop Monitor チェック(該当サイクルがあれば judge チームメイト介入)
│   ↓
│   Rule 評価Team Lead が実施)
│     ├── タグ検出 [STEP:N] → rule 選択
│     └── タグなし → AI フォールバック判定
│     ├── parallel: サブステップ条件 → aggregate(all/any)
│   ↓
│   next を決定
│     ├── COMPLETE → TeamDelete → ユーザーに結果報告
│     ├── ABORT → TeamDelete → ユーザーにエラー報告
│     └── movement名 → ループ検出チェック → 次の movement
│                                              ↓
└──────────────────────────────────────────────┘