## 概要
`resources/` ディレクトリを `builtins/` にリネームし、用途を明確化。同時に export-cc コマンドを拡張して全リソースをコピーするように修正する。
---
## タスク一覧
### 1. ディレクトリリネーム(優先度: 高)
| 変更前 | 変更後 |
|--------|--------|
| `resources/` | `builtins/` |
| `resources/global/{lang}/` | `builtins/{lang}/`(global/ 階層を除去) |
| `resources/project/` | `builtins/project/` |
| `resources/skill/` | `builtins/skill/` |
### 2. 不要ファイル削除(優先度: 高)
- `builtins/{lang}/prompts/` を削除
- 対象: `interactive-system.md`, `interactive-summary.md`
- 理由: コードから未参照、実体は `src/shared/prompts/`
### 3. コード修正 — パス参照(優先度: 高)
`resources` → `builtins`、`global/{lang}` → `{lang}` に更新:
| ファイル | 修正内容 |
|----------|----------|
| `src/infra/resources/index.ts` | `getResourcesDir()`, `getGlobalResourcesDir()`, `getLanguageResourcesDir()` 等のパス |
| `src/infra/config/paths.ts` | `getBuiltinPiecesDir()`, `getBuiltinPersonasDir()` |
| `src/infra/config/global/initialization.ts` | `copyLanguageConfigYaml()` |
| `src/infra/config/loaders/pieceCategories.ts` | `getLanguageResourcesDir()` 参照 |
| `src/features/config/ejectBuiltin.ts` | `getLanguageResourcesDir()` 参照 |
| `src/features/config/deploySkill.ts` | `getResourcesDir()` 参照 |
### 4. export-cc 修正(優先度: 高)
ファイル: `src/features/config/deploySkill.ts`
**現状**: pieces/ と personas/ のみコピー
**修正後**:
- `builtins/{lang}/` 全体を `~/.claude/skills/takt/` にコピー
- `skill/` のファイル(SKILL.md, references/, takt-command.md)は従来通り
- サマリー表示を新リソースタイプ(stances, instructions, knowledge 等)に対応
- confirm メッセージ修正:
- 現状: `'上書きしますか?'`
- 修正後: `'既存のスキルファイルをすべて削除し、最新版に置き換えます。続行しますか?'`
### 5. テスト修正(優先度: 中)
| ファイル | 修正内容 |
|----------|----------|
| `src/__tests__/initialization.test.ts` | `getLanguageResourcesDir` のパス期待値 |
| `src/__tests__/piece-category-config.test.ts` | mock パス |
| その他 `resources` パスを参照しているテスト | パス更新 |
### 6. ビルド・パッケージ設定(優先度: 中)
| ファイル | 修正内容 |
|----------|----------|
| `package.json` | `files` フィールドで `resources/` → `builtins/` |
| `tsconfig.json` | `resources/` への参照があれば更新 |
| `.gitignore` | 必要に応じて更新 |
### 7. ドキュメント(優先度: 低)
- `CLAUDE.md` の Directory Structure セクションを更新
- JSDoc コメントから `prompts/` 記述を削除
---
## 制約
- `builtins/{lang}/` のフラット構造は変更不可(ピースYAML内の相対パス依存)
- eject のセーフティ(skip-if-exists)は変更不要
- export-cc のセーフティ(SKILL.md 存在チェック + confirm)は維持
---
## 確認方法
- `npm run build` が成功すること
- `npm test` が全てパスすること
- `takt init` / `takt eject` / `takt export-cc` が正常動作すること
14 KiB
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 yolo タスク→permission_mode = "bypassPermissions"(確認なし)/takt coding タスク→permission_mode = "default"(権限確認あり)
通常 Movement の実行
通常の movement(parallel フィールドを持たない)は、Task tool で1つのチームメイトを起動する。
- プロンプトを構築する(後述の「プロンプト構築」参照)
- Task tool でチームメイトを起動する
- チームメイトの出力を受け取る
- Rule 評価で次の movement を決定する
Parallel Movement の実行
parallel フィールドを持つ movement は、複数のチームメイトを並列起動する。
実行手順
- parallel 配列の各サブステップに対して Task tool を準備する
- 全ての Task tool を1つのメッセージで並列に呼び出す(依存関係がないため)
- 全チームメイトの完了を待つ
- 各サブステップの出力を収集する
- 各サブステップの出力に対して、そのサブステップの
rulesで条件マッチを判定する - 親 movement の
rulesで aggregate 評価(all()/any())を行う
サブステップの条件マッチ判定
各サブステップの出力テキストに対して、そのサブステップの rules の中からマッチする condition を特定する。
判定方法(通常 movement の Rule 評価と同じ優先順位):
[STEP:N]タグがあればインデックスで照合(最後のタグを採用)- タグがなければ、出力全体を読んでどの condition に最も近いかを判断する
マッチした condition 文字列を記録する(次の aggregate 評価で使う)。
プロンプト構築
各チームメイト起動時、以下を結合してプロンプトを組み立てる。
構成要素(上から順に結合)
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} のような記法がある場合:
- レポートディレクトリ内に対応するレポートファイルがあれば Read で読む
- 読み込んだ内容をプレースホルダーに展開する
- ファイルが存在しない場合は「(レポート未作成)」に置換する
agent フィールドがない場合
agent: が指定されていない movement の場合、エージェントプロンプト部分を省略し、instruction_template の内容のみでプロンプトを構成する。
レポート出力指示の自動注入
movement に report フィールドがある場合、プロンプト末尾にレポート出力指示を自動追加する。
形式1: name + format
report:
name: 01-plan.md
format: |
# タスク計画
## 元の要求
...
→ プロンプトに追加する指示:
---
## レポート出力(必須)
作業完了後、以下のフォーマットに従ってレポートを出力してください。
レポートは ```markdown ブロックで囲んで出力してください。
ファイル名: 01-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/reports/{timestamp}-{slug}/ に作成する。
{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_iterationsに到達したら強制終了(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:
agent: ../agents/default/supervisor.md
instruction_template: |
サイクルが {cycle_count} 回繰り返されました...
rules:
- condition: 健全
next: ai_review
- condition: 非生産的
next: reviewers
検出ロジック
- movement 遷移履歴を記録する(例:
[plan, implement, ai_review, ai_fix, ai_review, ai_fix, ...]) - 各 loop_monitor の
cycleパターンが履歴の末尾にthreshold回以上連続で出現するかチェックする - 閾値に達した場合:
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 でレポートディレクトリに保存する。
抽出手順:
- 出力内の ```markdown ブロックを検索する
- レポートのファイル名やセクション見出しから対応するレポートを特定する
- Write tool で
{report_dir}/{ファイル名}に保存する
レポートの参照
後続の movement の instruction_template 内で {report:ファイル名} として参照すると、そのレポートファイルを Read して内容をプレースホルダーに展開する。
状態遷移の全体像
[開始]
↓
ピースYAML読み込み + エージェント .md 読み込み
↓
Teammate(spawnTeam) でチーム作成
↓
レポートディレクトリ作成
↓
initial_movement を取得
↓
┌─→ Task tool でチームメイト起動
│ ├── 通常: 1つの Task tool 呼び出し
│ │ prompt = agent.md + context + 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 → Teammate(cleanup) → ユーザーに結果報告
│ ├── ABORT → Teammate(cleanup) → ユーザーにエラー報告
│ └── movement名 → ループ検出チェック → 次の movement
│ ↓
└──────────────────────────────────────────────┘