takt export-cc コマンドを追加: ビルトインピース・エージェントを Claude Code Skill としてデプロイ
This commit is contained in:
parent
378f5477e4
commit
ec983089f9
105
resources/skill/SKILL.md
Normal file
105
resources/skill/SKILL.md
Normal file
@ -0,0 +1,105 @@
|
||||
---
|
||||
name: takt-engine
|
||||
description: TAKT ピースエンジンのリファレンス。/takt コマンドから使用される。ピースYAML定義に従ったマルチエージェントオーケストレーション。
|
||||
---
|
||||
|
||||
# TAKT Piece Engine
|
||||
|
||||
ピースYAMLファイルを読み込み、定義されたワークフロー(状態遷移マシン)に従って複数のAIエージェントをオーケストレーションするエンジン。
|
||||
|
||||
## 設計原則
|
||||
|
||||
- **Skill = 純粋なエンジンロジックのみ**
|
||||
- ピースYAML、エージェント .md は全て **ファイル参照** で実行時に Read する
|
||||
- Skill 内にピース定義・エージェント定義を一切埋め込まない
|
||||
- このスキルが持つのは「YAMLの読み方」「状態遷移の回し方」「ルール評価の仕方」だけ
|
||||
|
||||
## ピース解決
|
||||
|
||||
### ピースYAMLの検索
|
||||
|
||||
引数の第1トークンからピースYAMLファイルを特定する。
|
||||
|
||||
1. ファイルパス判定: `.yaml` / `.yml` で終わる、または `/` を含む → Read で直接読む
|
||||
2. ピース名検索(以下の順で Glob/Read を試行):
|
||||
- `~/.takt/pieces/{name}.yaml` (ユーザーカスタム、優先)
|
||||
- `~/.claude/skills/takt/pieces/{name}.yaml` (Skill同梱ビルトイン)
|
||||
3. 見つからない場合: 上記2ディレクトリを Glob (`*.yaml`) で列挙し、AskUserQuestion で選択させる
|
||||
|
||||
### エージェント .md の解決
|
||||
|
||||
ピースYAML内の `agent:` フィールドは、**ピースYAMLファイルのディレクトリからの相対パス**。
|
||||
|
||||
例: ピースが `~/.claude/skills/takt/pieces/default.yaml` にあり、`agent: ../agents/default/coder.md` の場合
|
||||
→ 絶対パスは `~/.claude/skills/takt/agents/default/coder.md`
|
||||
|
||||
解決手順:
|
||||
1. ピースYAMLのディレクトリパスを取得
|
||||
2. 各 movement の `agent:` の相対パスを絶対パスに変換
|
||||
3. Read tool で .md ファイルの内容を読み込む
|
||||
4. 読み込んだ内容をエージェントのシステムプロンプトとして使用する
|
||||
|
||||
**全てのエージェント .md を事前に読み込む**(状態遷移ループ開始前に)。
|
||||
|
||||
## 実行フロー
|
||||
|
||||
### ステップ 1: ピースYAMLの読み込みと解析
|
||||
|
||||
1. ピース解決でYAMLファイルパスを特定し、Read で読み込む
|
||||
2. YAML内容を解析して以下を抽出する(→ references/yaml-schema.md 参照):
|
||||
- `name`: ピース名
|
||||
- `max_iterations`: 最大イテレーション数
|
||||
- `initial_movement`: 開始 movement 名
|
||||
- `movements`: 全 movement 定義の配列
|
||||
|
||||
### ステップ 2: エージェントの事前読み込み
|
||||
|
||||
全 movement(parallel のサブステップ含む)から `agent:` パスを収集し、重複を除いて Read で読み込む。
|
||||
|
||||
### ステップ 3: 状態遷移ループ
|
||||
|
||||
**詳細は references/engine.md を参照。**
|
||||
|
||||
```
|
||||
iteration = 0
|
||||
current_movement = initial_movement
|
||||
previous_response = ""
|
||||
|
||||
LOOP:
|
||||
iteration++
|
||||
if iteration > max_iterations → 強制終了(ABORT)
|
||||
|
||||
movement = movements[current_movement] を取得
|
||||
|
||||
if movement が parallel:
|
||||
→ 並列実行(engine.md の「Parallel Movement の実行」参照)
|
||||
else:
|
||||
→ 通常実行(engine.md の「通常 Movement の実行」参照)
|
||||
|
||||
agent_output を取得
|
||||
|
||||
rule 評価(engine.md の「Rule 評価」参照)
|
||||
→ matched_rule を決定
|
||||
|
||||
next = matched_rule.next
|
||||
|
||||
if next == "COMPLETE" → 成功終了、ユーザーに結果を報告
|
||||
if next == "ABORT" → 失敗終了、ユーザーにエラーを報告
|
||||
|
||||
previous_response = agent_output
|
||||
current_movement = next
|
||||
→ LOOP に戻る
|
||||
```
|
||||
|
||||
### ステップ 4: 完了報告
|
||||
|
||||
- COMPLETE: 最後の agent 出力のサマリーをユーザーに表示
|
||||
- ABORT: 失敗理由をユーザーに表示
|
||||
- max_iterations 到達: 強制終了を通知
|
||||
|
||||
## 詳細リファレンス
|
||||
|
||||
| ファイル | 内容 |
|
||||
|---------|------|
|
||||
| `references/engine.md` | Movement 実行、プロンプト構築、Rule 評価の詳細ロジック |
|
||||
| `references/yaml-schema.md` | ピースYAMLの構造定義とフィールド説明 |
|
||||
375
resources/skill/references/engine.md
Normal file
375
resources/skill/references/engine.md
Normal file
@ -0,0 +1,375 @@
|
||||
# TAKT 実行エンジン詳細
|
||||
|
||||
## 通常 Movement の実行
|
||||
|
||||
通常の movement(`parallel` フィールドを持たない movement)は、Task tool で1つのエージェントを起動する。
|
||||
|
||||
### Task tool の呼び出し
|
||||
|
||||
```
|
||||
Task tool:
|
||||
subagent_type: "general-purpose"
|
||||
description: "{movement名} - {ピース名}" (3-5語)
|
||||
prompt: <後述のプロンプト構築で組み立てた内容>
|
||||
mode: <permission_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
|
||||
│ ↓
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
164
resources/skill/references/yaml-schema.md
Normal file
164
resources/skill/references/yaml-schema.md
Normal file
@ -0,0 +1,164 @@
|
||||
# ピースYAML スキーマリファレンス
|
||||
|
||||
このドキュメントはピースYAMLの構造を定義する。具体的なピース定義は含まない。
|
||||
|
||||
## トップレベルフィールド
|
||||
|
||||
```yaml
|
||||
name: piece-name # ピース名(必須)
|
||||
description: 説明テキスト # ピースの説明(任意)
|
||||
max_iterations: 10 # 最大イテレーション数(必須)
|
||||
initial_movement: plan # 最初に実行する movement 名(必須)
|
||||
movements: [...] # movement 定義の配列(必須)
|
||||
loop_monitors: [...] # ループ監視設定(任意)
|
||||
```
|
||||
|
||||
## Movement 定義
|
||||
|
||||
### 通常 Movement
|
||||
|
||||
```yaml
|
||||
- name: movement-name # movement 名(必須、一意)
|
||||
agent: ../agents/path.md # エージェントプロンプトへの相対パス(任意)
|
||||
agent_name: coder # 表示名(任意)
|
||||
edit: true # ファイル編集可否(必須)
|
||||
permission_mode: edit # 権限モード: edit / readonly / full(任意)
|
||||
session: refresh # セッション管理(任意)
|
||||
pass_previous_response: true # 前の出力を渡すか(デフォルト: true)
|
||||
allowed_tools: [...] # 許可ツール一覧(任意、参考情報)
|
||||
instruction_template: | # ステップ固有の指示テンプレート(任意)
|
||||
指示内容...
|
||||
report: ... # レポート設定(任意)
|
||||
rules: [...] # 遷移ルール(必須)
|
||||
```
|
||||
|
||||
### Parallel Movement
|
||||
|
||||
```yaml
|
||||
- name: reviewers # 親 movement 名(必須)
|
||||
parallel: # 並列サブステップ配列(これがあると parallel movement)
|
||||
- name: sub-step-1 # サブステップ名
|
||||
agent: ../agents/a.md
|
||||
edit: false
|
||||
instruction_template: |
|
||||
...
|
||||
rules: # サブステップの rules(condition のみ、next は無視される)
|
||||
- condition: "approved"
|
||||
- condition: "needs_fix"
|
||||
# report, allowed_tools 等も指定可能
|
||||
|
||||
- name: sub-step-2
|
||||
agent: ../agents/b.md
|
||||
edit: false
|
||||
instruction_template: |
|
||||
...
|
||||
rules:
|
||||
- condition: "passed"
|
||||
- condition: "failed"
|
||||
|
||||
rules: # 親の rules(aggregate 条件で遷移先を決定)
|
||||
- condition: all("approved", "passed")
|
||||
next: complete-step
|
||||
- condition: any("needs_fix", "failed")
|
||||
next: fix-step
|
||||
```
|
||||
|
||||
**重要**: サブステップの `rules` は結果分類のための condition 定義のみ。`next` は無視される(親の rules が遷移先を決定)。
|
||||
|
||||
## Rules 定義
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- condition: 条件テキスト # マッチ条件(必須)
|
||||
next: next-movement # 遷移先 movement 名(必須、サブステップでは任意)
|
||||
requires_user_input: true # ユーザー入力が必要(任意)
|
||||
interactive_only: true # インタラクティブモードのみ(任意)
|
||||
appendix: | # 追加情報(任意)
|
||||
補足テキスト...
|
||||
```
|
||||
|
||||
### Condition 記法
|
||||
|
||||
| 記法 | 説明 | 例 |
|
||||
|-----|------|-----|
|
||||
| 文字列 | AI判定またはタグで照合 | `"タスク完了"` |
|
||||
| `ai("...")` | AI が出力に対して条件を評価 | `ai("コードに問題がある")` |
|
||||
| `all("...")` | 全サブステップがマッチ(parallel 親のみ) | `all("approved")` |
|
||||
| `any("...")` | いずれかがマッチ(parallel 親のみ) | `any("needs_fix")` |
|
||||
| `all("X", "Y")` | 位置対応で全マッチ(parallel 親のみ) | `all("問題なし", "テスト成功")` |
|
||||
|
||||
### 特殊な next 値
|
||||
|
||||
| 値 | 意味 |
|
||||
|---|------|
|
||||
| `COMPLETE` | ピース成功終了 |
|
||||
| `ABORT` | ピース失敗終了 |
|
||||
| movement 名 | 指定された movement に遷移 |
|
||||
|
||||
## Report 定義
|
||||
|
||||
### 形式1: 単一レポート(name + format)
|
||||
|
||||
```yaml
|
||||
report:
|
||||
name: 01-plan.md
|
||||
format: |
|
||||
```markdown
|
||||
# レポートタイトル
|
||||
## セクション
|
||||
{内容}
|
||||
```
|
||||
```
|
||||
|
||||
`format` はエージェントへの出力フォーマット指示。レポート抽出時の参考情報。
|
||||
|
||||
### 形式2: 複数レポート(配列)
|
||||
|
||||
```yaml
|
||||
report:
|
||||
- Summary: summary.md
|
||||
- Scope: 01-scope.md
|
||||
- Decisions: 02-decisions.md
|
||||
```
|
||||
|
||||
各要素のキーがレポート種別名、値がファイル名。
|
||||
|
||||
## テンプレート変数
|
||||
|
||||
`instruction_template` 内で使用可能な変数:
|
||||
|
||||
| 変数 | 説明 |
|
||||
|-----|------|
|
||||
| `{task}` | ユーザーのタスク入力(template に含まれない場合は自動追加) |
|
||||
| `{previous_response}` | 前の movement の出力(pass_previous_response: true 時、自動追加) |
|
||||
| `{iteration}` | ピース全体のイテレーション数 |
|
||||
| `{max_iterations}` | 最大イテレーション数 |
|
||||
| `{movement_iteration}` | この movement の実行回数 |
|
||||
| `{report_dir}` | レポートディレクトリ名 |
|
||||
| `{report:ファイル名}` | 指定レポートファイルの内容を展開 |
|
||||
| `{user_inputs}` | 蓄積されたユーザー入力 |
|
||||
| `{cycle_count}` | loop_monitors 内で使用するサイクル回数 |
|
||||
|
||||
## Loop Monitors(任意)
|
||||
|
||||
```yaml
|
||||
loop_monitors:
|
||||
- cycle: [movement_a, movement_b] # 監視対象の movement サイクル
|
||||
threshold: 3 # 発動閾値(サイクル回数)
|
||||
judge:
|
||||
agent: ../agents/supervisor.md # 判定エージェント
|
||||
instruction_template: | # 判定用指示
|
||||
サイクルが {cycle_count} 回繰り返されました。
|
||||
健全性を判断してください。
|
||||
rules:
|
||||
- condition: 健全(進捗あり)
|
||||
next: movement_a
|
||||
- condition: 非生産的(改善なし)
|
||||
next: alternative_movement
|
||||
```
|
||||
|
||||
特定の movement 間のサイクルが閾値に達した場合、judge エージェントが介入して遷移先を判断する。
|
||||
|
||||
## allowed_tools について
|
||||
|
||||
`allowed_tools` は TAKT 本体のエージェントプロバイダーで使用されるフィールド。Claude Code の Skill として実行する場合、Task tool のエージェントが使用可能なツールは Claude Code の設定に従う。このフィールドは参考情報として扱い、`edit` フィールドの方を権限制御に使用する。
|
||||
28
resources/skill/takt-command.md
Normal file
28
resources/skill/takt-command.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
name: takt
|
||||
description: TAKT ピースランナー。ピースYAMLワークフローに従ってマルチエージェントを実行する。
|
||||
---
|
||||
|
||||
TAKT ピースランナーを実行する。
|
||||
|
||||
## 引数
|
||||
|
||||
$ARGUMENTS を以下のように解析する:
|
||||
|
||||
- 第1トークン: ピース名またはYAMLファイルパス(必須)
|
||||
- 残りのトークン: タスク内容(省略時は AskUserQuestion でユーザーに入力を求める)
|
||||
|
||||
例:
|
||||
- `/takt passthrough タスクを実行`
|
||||
- `/takt default src/foo.ts のバグを修正`
|
||||
- `/takt /path/to/custom.yaml 実装して`
|
||||
|
||||
## 実行手順
|
||||
|
||||
以下のファイルを **Read tool で読み込み**、記載された手順に従って実行する:
|
||||
|
||||
1. `~/.claude/skills/takt/SKILL.md` - エンジン概要とピース解決
|
||||
2. `~/.claude/skills/takt/references/engine.md` - 実行エンジンの詳細ロジック
|
||||
3. `~/.claude/skills/takt/references/yaml-schema.md` - ピースYAML構造リファレンス
|
||||
|
||||
**重要**: これら3ファイルを最初に全て読み込んでから、SKILL.md の「実行フロー」に従って処理を開始する。
|
||||
@ -7,7 +7,7 @@
|
||||
import { clearAgentSessions, getCurrentPiece } from '../../infra/config/index.js';
|
||||
import { success } from '../../shared/ui/index.js';
|
||||
import { runAllTasks, addTask, watchTasks, listTasks } from '../../features/tasks/index.js';
|
||||
import { switchPiece, switchConfig, ejectBuiltin, resetCategoriesToDefault } from '../../features/config/index.js';
|
||||
import { switchPiece, switchConfig, ejectBuiltin, resetCategoriesToDefault, deploySkill } from '../../features/config/index.js';
|
||||
import { previewPrompts } from '../../features/prompt/index.js';
|
||||
import { program, resolvedCwd } from './program.js';
|
||||
import { resolveAgentOverrides } from './helpers.js';
|
||||
@ -108,3 +108,10 @@ program
|
||||
.action(async (piece?: string) => {
|
||||
await previewPrompts(resolvedCwd, piece);
|
||||
});
|
||||
|
||||
program
|
||||
.command('export-cc')
|
||||
.description('Export takt pieces/agents as Claude Code Skill (~/.claude/)')
|
||||
.action(async () => {
|
||||
await deploySkill();
|
||||
});
|
||||
|
||||
165
src/features/config/deploySkill.ts
Normal file
165
src/features/config/deploySkill.ts
Normal file
@ -0,0 +1,165 @@
|
||||
/**
|
||||
* takt export-cc — Deploy takt pieces and agents as Claude Code Skill.
|
||||
*
|
||||
* Copies the following to ~/.claude/:
|
||||
* commands/takt.md — /takt command entry point
|
||||
* skills/takt/SKILL.md — Engine overview
|
||||
* skills/takt/references/ — Engine logic + YAML schema
|
||||
* skills/takt/pieces/ — Builtin piece YAML files
|
||||
* skills/takt/agents/ — Builtin agent .md files
|
||||
*
|
||||
* Piece YAML agent paths (../agents/...) work as-is because
|
||||
* the directory structure is mirrored.
|
||||
*/
|
||||
|
||||
import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, statSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { join, dirname, relative } from 'node:path';
|
||||
|
||||
import {
|
||||
getBuiltinPiecesDir,
|
||||
getBuiltinAgentsDir,
|
||||
getLanguage,
|
||||
} from '../../infra/config/index.js';
|
||||
import { getResourcesDir } from '../../infra/resources/index.js';
|
||||
import { confirm } from '../../shared/prompt/index.js';
|
||||
import { header, success, info, warn, blankLine } from '../../shared/ui/index.js';
|
||||
|
||||
/** Files to skip during directory copy */
|
||||
const SKIP_FILES = new Set(['.DS_Store', 'Thumbs.db']);
|
||||
|
||||
/** Target paths under ~/.claude/ */
|
||||
function getSkillDir(): string {
|
||||
return join(homedir(), '.claude', 'skills', 'takt');
|
||||
}
|
||||
|
||||
function getCommandDir(): string {
|
||||
return join(homedir(), '.claude', 'commands');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy takt skill to Claude Code (~/.claude/).
|
||||
*/
|
||||
export async function deploySkill(): Promise<void> {
|
||||
header('takt export-cc — Deploy to Claude Code');
|
||||
|
||||
const lang = getLanguage();
|
||||
const skillResourcesDir = join(getResourcesDir(), 'skill');
|
||||
const builtinPiecesDir = getBuiltinPiecesDir(lang);
|
||||
const builtinAgentsDir = getBuiltinAgentsDir(lang);
|
||||
const skillDir = getSkillDir();
|
||||
const commandDir = getCommandDir();
|
||||
|
||||
// Verify source directories exist
|
||||
if (!existsSync(skillResourcesDir)) {
|
||||
warn('Skill resources not found. Ensure takt is installed correctly.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if skill already exists and ask for confirmation
|
||||
const skillExists = existsSync(join(skillDir, 'SKILL.md'));
|
||||
if (skillExists) {
|
||||
info('Claude Code Skill が既にインストールされています。');
|
||||
const overwrite = await confirm('上書きしますか?', false);
|
||||
if (!overwrite) {
|
||||
info('キャンセルしました。');
|
||||
return;
|
||||
}
|
||||
blankLine();
|
||||
}
|
||||
|
||||
const copiedFiles: string[] = [];
|
||||
|
||||
// 1. Deploy command file: ~/.claude/commands/takt.md
|
||||
const commandSrc = join(skillResourcesDir, 'takt-command.md');
|
||||
const commandDest = join(commandDir, 'takt.md');
|
||||
copyFile(commandSrc, commandDest, copiedFiles);
|
||||
|
||||
// 2. Deploy SKILL.md
|
||||
const skillSrc = join(skillResourcesDir, 'SKILL.md');
|
||||
const skillDest = join(skillDir, 'SKILL.md');
|
||||
copyFile(skillSrc, skillDest, copiedFiles);
|
||||
|
||||
// 3. Deploy references/ (engine.md, yaml-schema.md)
|
||||
const refsSrcDir = join(skillResourcesDir, 'references');
|
||||
const refsDestDir = join(skillDir, 'references');
|
||||
copyDirRecursive(refsSrcDir, refsDestDir, copiedFiles);
|
||||
|
||||
// 4. Deploy builtin piece YAMLs → skills/takt/pieces/
|
||||
const piecesDestDir = join(skillDir, 'pieces');
|
||||
copyDirRecursive(builtinPiecesDir, piecesDestDir, copiedFiles);
|
||||
|
||||
// 5. Deploy builtin agent .md files → skills/takt/agents/
|
||||
const agentsDestDir = join(skillDir, 'agents');
|
||||
copyDirRecursive(builtinAgentsDir, agentsDestDir, copiedFiles);
|
||||
|
||||
// Report results
|
||||
blankLine();
|
||||
if (copiedFiles.length > 0) {
|
||||
success(`${copiedFiles.length} ファイルをデプロイしました。`);
|
||||
blankLine();
|
||||
|
||||
// Show summary by category
|
||||
const skillBase = join(homedir(), '.claude');
|
||||
const commandFiles = copiedFiles.filter((f) => f.startsWith(commandDir));
|
||||
const skillFiles = copiedFiles.filter(
|
||||
(f) => f.startsWith(skillDir) && !f.includes('/pieces/') && !f.includes('/agents/'),
|
||||
);
|
||||
const pieceFiles = copiedFiles.filter((f) => f.includes('/pieces/'));
|
||||
const agentFiles = copiedFiles.filter((f) => f.includes('/agents/'));
|
||||
|
||||
if (commandFiles.length > 0) {
|
||||
info(` コマンド: ${commandFiles.length} ファイル`);
|
||||
for (const f of commandFiles) {
|
||||
info(` ${relative(skillBase, f)}`);
|
||||
}
|
||||
}
|
||||
if (skillFiles.length > 0) {
|
||||
info(` スキル: ${skillFiles.length} ファイル`);
|
||||
for (const f of skillFiles) {
|
||||
info(` ${relative(skillBase, f)}`);
|
||||
}
|
||||
}
|
||||
if (pieceFiles.length > 0) {
|
||||
info(` ピース: ${pieceFiles.length} ファイル`);
|
||||
}
|
||||
if (agentFiles.length > 0) {
|
||||
info(` エージェント: ${agentFiles.length} ファイル`);
|
||||
}
|
||||
|
||||
blankLine();
|
||||
info('使い方: /takt <piece-name> <task>');
|
||||
info('例: /takt passthrough "Hello World テスト"');
|
||||
} else {
|
||||
info('デプロイするファイルがありませんでした。');
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy a single file, creating parent directories as needed. */
|
||||
function copyFile(src: string, dest: string, copiedFiles: string[]): void {
|
||||
if (!existsSync(src)) return;
|
||||
mkdirSync(dirname(dest), { recursive: true });
|
||||
writeFileSync(dest, readFileSync(src));
|
||||
copiedFiles.push(dest);
|
||||
}
|
||||
|
||||
/** Recursively copy directory contents, always overwriting. */
|
||||
function copyDirRecursive(srcDir: string, destDir: string, copiedFiles: string[]): void {
|
||||
if (!existsSync(srcDir)) return;
|
||||
mkdirSync(destDir, { recursive: true });
|
||||
|
||||
for (const entry of readdirSync(srcDir)) {
|
||||
if (SKIP_FILES.has(entry)) continue;
|
||||
|
||||
const srcPath = join(srcDir, entry);
|
||||
const destPath = join(destDir, entry);
|
||||
const stat = statSync(srcPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
copyDirRecursive(srcPath, destPath, copiedFiles);
|
||||
} else {
|
||||
writeFileSync(destPath, readFileSync(srcPath));
|
||||
copiedFiles.push(destPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,3 +6,4 @@ export { switchPiece } from './switchPiece.js';
|
||||
export { switchConfig, getCurrentPermissionMode, setPermissionMode, type PermissionMode } from './switchConfig.js';
|
||||
export { ejectBuiltin } from './ejectBuiltin.js';
|
||||
export { resetCategoriesToDefault } from './resetCategories.js';
|
||||
export { deploySkill } from './deploySkill.js';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user