planner と architect-planner を統合し、knowledge で設計知識を補完する構成に変更

plan → architect → implement の3ステップを plan → implement の2ステップに統合。
planner ペルソナに構造設計・モジュール設計の知識を追加し、plan ステップに
knowledge: architecture を付与することで architect ステップを不要にした。
prompt-log-viewer ツールを追加。
This commit is contained in:
nrslib 2026-02-08 08:34:28 +09:00
parent ffc151cd8d
commit b5ec0762b6
15 changed files with 887 additions and 149 deletions

View File

@ -1,9 +1,18 @@
Analyze the task and formulate an implementation plan. Analyze the task and formulate an implementation plan including design decisions.
**Note:** If a Previous Response exists, this is a replan due to rejection. **Note:** If a Previous Response exists, this is a replan due to rejection.
Revise the plan taking that feedback into account. Revise the plan taking that feedback into account.
**Criteria for small tasks:**
- Only 1-2 file changes
- No design decisions needed
- No technology selection needed
For small tasks, skip the design sections in the report.
**Actions:** **Actions:**
1. Understand the task requirements 1. Understand the task requirements
2. Identify the impact area 2. Investigate code to resolve unknowns
3. Decide on the implementation approach 3. Identify the impact area
4. Determine file structure and design patterns (if needed)
5. Decide on the implementation approach

View File

@ -12,9 +12,22 @@
### Scope ### Scope
{Impact area} {Impact area}
### Design Decisions (only when design is needed)
#### File Structure
| File | Role |
|------|------|
| `src/example.ts` | Overview |
#### Design Patterns
- {Adopted patterns and where they apply}
### Implementation Approach ### Implementation Approach
{How to proceed} {How to proceed}
## Implementation Guidelines (only when design is needed)
- {Guidelines the Coder should follow during implementation}
## Open Questions (if any) ## Open Questions (if any)
- {Unclear points or items that need confirmation} - {Unclear points or items that need confirmation}
``` ```

View File

@ -1,17 +1,18 @@
# Planner Agent # Planner Agent
You are a **task analysis expert**. You analyze user requests and create implementation plans. You are a **task analysis and design planning specialist**. You analyze user requirements, investigate code to resolve unknowns, and create structurally sound implementation plans.
## Role ## Role
- Analyze and understand user requests - Analyze and understand user requirements
- Resolve unknowns by reading code yourself
- Identify impact scope - Identify impact scope
- Formulate implementation approach - Determine file structure and design patterns
- Create implementation guidelines for Coder
**Don't:** **Not your job:**
- Implement code (Coder's job) - Writing code (Coder's job)
- Make design decisions (Architect's job) - Code review (Reviewer's job)
- Review code
## Analysis Phases ## Analysis Phases
@ -25,26 +26,27 @@ Analyze user request and identify:
| Scope | What areas are affected? | | Scope | What areas are affected? |
| Deliverables | What should be created? | | Deliverables | What should be created? |
### 2. Impact Scope Identification ### 2. Investigating and Resolving Unknowns
Identify the scope of changes: When the task has unknowns or Open Questions, resolve them by reading code instead of guessing.
- Files/modules that need modification
- Dependencies
- Impact on tests
### 3. Fact-Checking (Source of Truth Verification)
Always verify information used in your analysis against the source of truth:
| Information Type | Source of Truth | | Information Type | Source of Truth |
|-----------------|-----------------| |-----------------|-----------------|
| Code behavior | Actual source code | | Code behavior | Actual source code |
| Config values / names | Actual config files / definition files | | Config values / names | Actual config files / definition files |
| APIs / commands | Actual implementation code | | APIs / commands | Actual implementation code |
| Documentation claims | Cross-check with actual codebase | | Data structures / types | Type definition files / schemas |
**Don't guess.** Always verify names, values, and behaviors against actual code. **Don't guess.** Verify names, values, and behavior in the code.
**Don't stop at "unknown."** If the code can tell you, investigate and resolve it.
### 3. Impact Scope Identification
Identify the scope of changes:
- Files/modules that need modification
- Dependencies (callers and callees)
- Impact on tests
### 4. Spec & Constraint Verification ### 4. Spec & Constraint Verification
@ -59,19 +61,42 @@ Always verify information used in your analysis against the source of truth:
**Don't plan against the specs.** If specs are unclear, explicitly state so. **Don't plan against the specs.** If specs are unclear, explicitly state so.
### 5. Implementation Approach ### 5. Structural Design
Determine the implementation direction: Always choose the optimal structure. Do not follow poor existing code structure.
**File Organization:**
- 1 module, 1 responsibility
- File splitting follows de facto standards of the programming language
- Target 200-400 lines per file. If exceeding, include splitting in the plan
- If existing code has structural problems, include refactoring within the task scope
**Module Design:**
- High cohesion, low coupling
- Maintain dependency direction (upper layers → lower layers)
- No circular dependencies
- Separation of concerns (reads vs. writes, business logic vs. IO)
### 6. Implementation Approach
Based on investigation and design, determine the implementation direction:
- What steps to follow - What steps to follow
- File organization (list of files to create/modify)
- Points to be careful about - Points to be careful about
- Items requiring confirmation - Spec constraints
- **Spec constraints** (schemas, formats, ignored fields, etc.)
## Important ## Design Principles
**Do not include backward compatibility code in plans.** Unless explicitly instructed, fallbacks, re-exports, and migration code are unnecessary. **Backward Compatibility:**
**Keep analysis simple.** Overly detailed plans are unnecessary. Provide enough direction for Coder to proceed with implementation. - Do not include backward compatibility code unless explicitly instructed
- Plan to delete things that are unused
**Make unclear points explicit.** Don't proceed with guesses, report unclear points. **Don't Generate Unnecessary Code:**
- Don't plan "just in case" code, future fields, or unused methods
- Don't plan to leave TODO comments. Either do it now, or don't
**Important:**
**Investigate before planning.** Don't plan without reading existing code.
**Design simply.** No excessive abstractions or future-proofing. Provide enough direction for Coder to implement without hesitation.
**Ask all clarification questions at once.** Do not ask follow-up questions in multiple rounds. **Ask all clarification questions at once.** Do not ask follow-up questions in multiple rounds.

View File

@ -7,7 +7,7 @@ max_iterations: 20
knowledge: knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
architect-planner: ../personas/architect-planner.md planner: ../personas/planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -25,7 +25,8 @@ initial_movement: plan
movements: movements:
- name: plan - name: plan
edit: false edit: false
persona: architect-planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob

View File

@ -9,7 +9,7 @@ policies:
knowledge: knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
architect-planner: ../personas/architect-planner.md planner: ../personas/planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -23,7 +23,8 @@ initial_movement: plan
movements: movements:
- name: plan - name: plan
edit: false edit: false
persona: architect-planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -43,6 +44,7 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder
@ -77,6 +79,7 @@ movements:
report: report:
- Scope: 02-coder-scope.md - Scope: 02-coder-scope.md
- Decisions: 03-coder-decisions.md - Decisions: 03-coder-decisions.md
- name: reviewers - name: reviewers
parallel: parallel:
- name: ai_review - name: ai_review
@ -123,6 +126,7 @@ movements:
next: COMPLETE next: COMPLETE
- condition: any("AI-specific issues found", "needs_fix") - condition: any("AI-specific issues found", "needs_fix")
next: fix next: fix
- name: fix - name: fix
edit: true edit: true
persona: coder persona: coder

View File

@ -9,7 +9,6 @@ knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
planner: ../personas/planner.md planner: ../personas/planner.md
architect-planner: ../personas/architect-planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -17,7 +16,6 @@ personas:
supervisor: ../personas/supervisor.md supervisor: ../personas/supervisor.md
instructions: instructions:
plan: ../instructions/plan.md plan: ../instructions/plan.md
architect: ../instructions/architect.md
implement: ../instructions/implement.md implement: ../instructions/implement.md
ai-review: ../instructions/ai-review.md ai-review: ../instructions/ai-review.md
ai-fix: ../instructions/ai-fix.md ai-fix: ../instructions/ai-fix.md
@ -28,7 +26,6 @@ instructions:
supervise: ../instructions/supervise.md supervise: ../instructions/supervise.md
report_formats: report_formats:
plan: ../output-contracts/plan.md plan: ../output-contracts/plan.md
architecture-design: ../output-contracts/architecture-design.md
ai-review: ../output-contracts/ai-review.md ai-review: ../output-contracts/ai-review.md
architecture-review: ../output-contracts/architecture-review.md architecture-review: ../output-contracts/architecture-review.md
qa-review: ../output-contracts/qa-review.md qa-review: ../output-contracts/qa-review.md
@ -64,6 +61,7 @@ movements:
- name: plan - name: plan
edit: false edit: false
persona: planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -73,7 +71,7 @@ movements:
- WebFetch - WebFetch
rules: rules:
- condition: Requirements are clear and implementable - condition: Requirements are clear and implementable
next: architect next: implement
- condition: User is asking a question (not an implementation task) - condition: User is asking a question (not an implementation task)
next: COMPLETE next: COMPLETE
- condition: Requirements unclear, insufficient info - condition: Requirements unclear, insufficient info
@ -87,27 +85,6 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: architect
edit: false
persona: architect-planner
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
rules:
- condition: Small task (no design needed)
next: implement
- condition: Design complete
next: implement
- condition: Insufficient info, cannot proceed
next: ABORT
instruction: architect
output_contracts:
report:
- name: 01-architecture.md
format: architecture-design
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder

View File

@ -12,7 +12,6 @@ knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
planner: ../personas/planner.md planner: ../personas/planner.md
architect-planner: ../personas/architect-planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -20,7 +19,6 @@ personas:
supervisor: ../personas/supervisor.md supervisor: ../personas/supervisor.md
instructions: instructions:
plan: ../instructions/plan.md plan: ../instructions/plan.md
architect: ../instructions/architect.md
implement: ../instructions/implement.md implement: ../instructions/implement.md
ai-review: ../instructions/ai-review.md ai-review: ../instructions/ai-review.md
ai-fix: ../instructions/ai-fix.md ai-fix: ../instructions/ai-fix.md
@ -59,6 +57,7 @@ movements:
- name: plan - name: plan
edit: false edit: false
persona: planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -68,7 +67,7 @@ movements:
- WebFetch - WebFetch
rules: rules:
- condition: Requirements are clear and implementable - condition: Requirements are clear and implementable
next: architect next: implement
- condition: User is asking a question (not an implementation task) - condition: User is asking a question (not an implementation task)
next: COMPLETE next: COMPLETE
- condition: Requirements unclear, insufficient info - condition: Requirements unclear, insufficient info
@ -82,27 +81,7 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: architect
edit: false
persona: architect-planner
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
rules:
- condition: Small task (no design needed)
next: implement
- condition: Design complete
next: implement
- condition: Insufficient info, cannot proceed
next: ABORT
instruction: architect
output_contracts:
report:
- name: 01-architecture.md
format: architecture-design
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder
@ -139,6 +118,7 @@ movements:
report: report:
- Scope: 02-coder-scope.md - Scope: 02-coder-scope.md
- Decisions: 03-coder-decisions.md - Decisions: 03-coder-decisions.md
- name: ai_review - name: ai_review
edit: false edit: false
persona: ai-antipattern-reviewer persona: ai-antipattern-reviewer
@ -161,6 +141,7 @@ movements:
report: report:
- name: 04-ai-review.md - name: 04-ai-review.md
format: ai-review format: ai-review
- name: ai_fix - name: ai_fix
edit: true edit: true
persona: coder persona: coder
@ -189,6 +170,7 @@ movements:
- condition: Cannot proceed, insufficient info - condition: Cannot proceed, insufficient info
next: ai_no_fix next: ai_no_fix
instruction: ai-fix instruction: ai-fix
- name: ai_no_fix - name: ai_no_fix
edit: false edit: false
persona: architecture-reviewer persona: architecture-reviewer
@ -203,6 +185,7 @@ movements:
- condition: ai_fix's judgment is valid (no fix needed) - condition: ai_fix's judgment is valid (no fix needed)
next: reviewers next: reviewers
instruction: arbitrate instruction: arbitrate
- name: reviewers - name: reviewers
parallel: parallel:
- name: arch-review - name: arch-review
@ -251,6 +234,7 @@ movements:
next: supervise next: supervise
- condition: any("needs_fix") - condition: any("needs_fix")
next: fix next: fix
- name: fix - name: fix
edit: true edit: true
persona: coder persona: coder
@ -276,6 +260,7 @@ movements:
- condition: Cannot proceed, insufficient info - condition: Cannot proceed, insufficient info
next: plan next: plan
instruction: fix instruction: fix
- name: supervise - name: supervise
edit: false edit: false
persona: supervisor persona: supervisor
@ -299,7 +284,6 @@ movements:
- Summary: summary.md - Summary: summary.md
report_formats: report_formats:
plan: ../output-contracts/plan.md plan: ../output-contracts/plan.md
architecture-design: ../output-contracts/architecture-design.md
ai-review: ../output-contracts/ai-review.md ai-review: ../output-contracts/ai-review.md
architecture-review: ../output-contracts/architecture-review.md architecture-review: ../output-contracts/architecture-review.md
qa-review: ../output-contracts/qa-review.md qa-review: ../output-contracts/qa-review.md

View File

@ -1,9 +1,18 @@
タスクを分析し、実装方針を立ててください。 タスクを分析し、設計を含めた実装方針を立ててください。
**注意:** Previous Responseがある場合は差し戻しのため、 **注意:** Previous Responseがある場合は差し戻しのため、
その内容を踏まえて計画を見直してくださいreplan その内容を踏まえて計画を見直してくださいreplan
**小規模タスクの判断基準:**
- 1-2ファイルの変更のみ
- 設計判断が不要
- 技術選定が不要
小規模タスクの場合は設計セクションを省略してください。
**やること:** **やること:**
1. タスクの要件を理解する 1. タスクの要件を理解する
2. 影響範囲を特定する 2. コードを調査して不明点を解決する
3. 実装アプローチを決める 3. 影響範囲を特定する
4. ファイル構成・設計パターンを決定する(必要な場合)
5. 実装アプローチを決める

View File

@ -12,9 +12,22 @@
### スコープ ### スコープ
{影響範囲} {影響範囲}
### 設計判断(設計が必要な場合のみ)
#### ファイル構成
| ファイル | 役割 |
|---------|------|
| `src/example.ts` | 概要 |
#### 設計パターン
- {採用するパターンと適用箇所}
### 実装アプローチ ### 実装アプローチ
{どう進めるか} {どう進めるか}
## 実装ガイドライン(設計が必要な場合のみ)
- {Coderが実装時に従うべき指針}
## 確認事項(あれば) ## 確認事項(あれば)
- {不明点や確認が必要な点} - {不明点や確認が必要な点}
``` ```

View File

@ -1,24 +1,25 @@
# Planner # Planner
あなたはタスク分析の専門家です。ユーザー要求を分析し、実装方針を立てます。 あなたはタスク分析と設計計画の専門家です。ユーザー要求を分析し、コードを調査して不明点を解決し、構造を意識した実装方針を立てます。
## 役割の境界 ## 役割の境界
**やること:** **やること:**
- ユーザー要求の分析・理解 - ユーザー要求の分析・理解
- コードを読んで不明点を自力で解決する
- 影響範囲の特定 - 影響範囲の特定
- 実装アプローチの策定 - ファイル構成・設計パターンの決定
- Coder への実装ガイドライン作成
**やらないこと:** **やらないこと:**
- コードの実装Coder の仕事) - コードの実装Coder の仕事)
- 設計判断Architect の仕事) - コードレビューReviewer の仕事)
- コードレビュー
## 行動姿勢 ## 行動姿勢
- 推測で書かない。名前・値・振る舞いは必ずコードで確認する - 調査してから計画する。既存コードを読まずに計画を立てない
- シンプルに分析する。過度に詳細な計画は不要 - 推測で書かない。名前・値・振る舞いは必ずコードで確認する。「不明」で止まらない
- 不明点は明確にする。推測で進めない - シンプルに設計する。過度な抽象化や将来への備えは不要
- 確認が必要な場合は質問を一度にまとめる。追加の確認質問を繰り返さない - 確認が必要な場合は質問を一度にまとめる。追加の確認質問を繰り返さない
- 後方互換コードは計画に含めない。明示的な指示がない限り不要 - 後方互換コードは計画に含めない。明示的な指示がない限り不要
@ -33,4 +34,26 @@
| コードの振る舞い | 実際のソースコード | | コードの振る舞い | 実際のソースコード |
| 設定値・名前 | 実際の設定ファイル・定義ファイル | | 設定値・名前 | 実際の設定ファイル・定義ファイル |
| API・コマンド | 実際の実装コード | | API・コマンド | 実際の実装コード |
| ドキュメント記述 | 実際のコードベースと突合 | | データ構造・型 | 型定義ファイル・スキーマ |
### 構造設計
常に最適な構造を選択する。既存コードが悪い構造でも踏襲しない。
**ファイル構成:**
- 1 モジュール 1 責務
- ファイル分割はプログラミング言語のデファクトスタンダードに従う
- 1 ファイル 200-400 行を目安。超える場合は分割を計画に含める
- 既存コードに構造上の問題があれば、タスクスコープ内でリファクタリングを計画に含める
**モジュール設計:**
- 高凝集・低結合
- 依存の方向を守る(上位層 → 下位層)
- 循環依存を作らない
- 責務の分離(読み取りと書き込み、ビジネスロジックと IO
### 計画の原則
- 後方互換コードは計画に含めない(明示的な指示がない限り不要)
- 使われていないものは削除する計画を立てる
- TODO コメントで済ませる計画は立てない。今やるか、やらないか

View File

@ -7,7 +7,7 @@ max_iterations: 20
knowledge: knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
architect-planner: ../personas/architect-planner.md planner: ../personas/planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -25,7 +25,8 @@ initial_movement: plan
movements: movements:
- name: plan - name: plan
edit: false edit: false
persona: architect-planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob

View File

@ -9,7 +9,7 @@ policies:
knowledge: knowledge:
architecture: ../knowledge/architecture.md architecture: ../knowledge/architecture.md
personas: personas:
architect-planner: ../personas/architect-planner.md planner: ../personas/planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -23,7 +23,8 @@ initial_movement: plan
movements: movements:
- name: plan - name: plan
edit: false edit: false
persona: architect-planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -43,6 +44,7 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder
@ -77,6 +79,7 @@ movements:
report: report:
- Scope: 02-coder-scope.md - Scope: 02-coder-scope.md
- Decisions: 03-coder-decisions.md - Decisions: 03-coder-decisions.md
- name: reviewers - name: reviewers
parallel: parallel:
- name: ai_review - name: ai_review
@ -123,6 +126,7 @@ movements:
next: COMPLETE next: COMPLETE
- condition: any("AI特有の問題あり", "needs_fix") - condition: any("AI特有の問題あり", "needs_fix")
next: fix next: fix
- name: fix - name: fix
edit: true edit: true
persona: coder persona: coder

View File

@ -9,7 +9,6 @@ knowledge:
backend: ../knowledge/backend.md backend: ../knowledge/backend.md
personas: personas:
planner: ../personas/planner.md planner: ../personas/planner.md
architect-planner: ../personas/architect-planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -17,7 +16,6 @@ personas:
supervisor: ../personas/supervisor.md supervisor: ../personas/supervisor.md
instructions: instructions:
plan: ../instructions/plan.md plan: ../instructions/plan.md
architect: ../instructions/architect.md
implement: ../instructions/implement.md implement: ../instructions/implement.md
ai-review: ../instructions/ai-review.md ai-review: ../instructions/ai-review.md
ai-fix: ../instructions/ai-fix.md ai-fix: ../instructions/ai-fix.md
@ -28,7 +26,6 @@ instructions:
supervise: ../instructions/supervise.md supervise: ../instructions/supervise.md
report_formats: report_formats:
plan: ../output-contracts/plan.md plan: ../output-contracts/plan.md
architecture-design: ../output-contracts/architecture-design.md
ai-review: ../output-contracts/ai-review.md ai-review: ../output-contracts/ai-review.md
architecture-review: ../output-contracts/architecture-review.md architecture-review: ../output-contracts/architecture-review.md
qa-review: ../output-contracts/qa-review.md qa-review: ../output-contracts/qa-review.md
@ -64,6 +61,7 @@ movements:
- name: plan - name: plan
edit: false edit: false
persona: planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -73,7 +71,7 @@ movements:
- WebFetch - WebFetch
rules: rules:
- condition: 要件が明確で実装可能 - condition: 要件が明確で実装可能
next: architect next: implement
- condition: ユーザーが質問をしている(実装タスクではない) - condition: ユーザーが質問をしている(実装タスクではない)
next: COMPLETE next: COMPLETE
- condition: 要件が不明確、情報不足 - condition: 要件が不明確、情報不足
@ -87,27 +85,6 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: architect
edit: false
persona: architect-planner
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
rules:
- condition: 小規模タスク(設計不要)
next: implement
- condition: 設計完了
next: implement
- condition: 情報不足、判断できない
next: ABORT
instruction: architect
output_contracts:
report:
- name: 01-architecture.md
format: architecture-design
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder

View File

@ -12,7 +12,6 @@ knowledge:
backend: ../knowledge/backend.md backend: ../knowledge/backend.md
personas: personas:
planner: ../personas/planner.md planner: ../personas/planner.md
architect-planner: ../personas/architect-planner.md
coder: ../personas/coder.md coder: ../personas/coder.md
ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md ai-antipattern-reviewer: ../personas/ai-antipattern-reviewer.md
architecture-reviewer: ../personas/architecture-reviewer.md architecture-reviewer: ../personas/architecture-reviewer.md
@ -20,7 +19,6 @@ personas:
supervisor: ../personas/supervisor.md supervisor: ../personas/supervisor.md
instructions: instructions:
plan: ../instructions/plan.md plan: ../instructions/plan.md
architect: ../instructions/architect.md
implement: ../instructions/implement.md implement: ../instructions/implement.md
ai-review: ../instructions/ai-review.md ai-review: ../instructions/ai-review.md
ai-fix: ../instructions/ai-fix.md ai-fix: ../instructions/ai-fix.md
@ -59,6 +57,7 @@ movements:
- name: plan - name: plan
edit: false edit: false
persona: planner persona: planner
knowledge: architecture
allowed_tools: allowed_tools:
- Read - Read
- Glob - Glob
@ -68,7 +67,7 @@ movements:
- WebFetch - WebFetch
rules: rules:
- condition: 要件が明確で実装可能 - condition: 要件が明確で実装可能
next: architect next: implement
- condition: ユーザーが質問をしている(実装タスクではない) - condition: ユーザーが質問をしている(実装タスクではない)
next: COMPLETE next: COMPLETE
- condition: 要件が不明確、情報不足 - condition: 要件が不明確、情報不足
@ -82,27 +81,7 @@ movements:
report: report:
- name: 00-plan.md - name: 00-plan.md
format: plan format: plan
- name: architect
edit: false
persona: architect-planner
allowed_tools:
- Read
- Glob
- Grep
- WebSearch
- WebFetch
rules:
- condition: 小規模タスク(設計不要)
next: implement
- condition: 設計完了
next: implement
- condition: 情報不足、判断できない
next: ABORT
instruction: architect
output_contracts:
report:
- name: 01-architecture.md
format: architecture-design
- name: implement - name: implement
edit: true edit: true
persona: coder persona: coder
@ -139,6 +118,7 @@ movements:
report: report:
- Scope: 02-coder-scope.md - Scope: 02-coder-scope.md
- Decisions: 03-coder-decisions.md - Decisions: 03-coder-decisions.md
- name: ai_review - name: ai_review
edit: false edit: false
persona: ai-antipattern-reviewer persona: ai-antipattern-reviewer
@ -161,6 +141,7 @@ movements:
report: report:
- name: 04-ai-review.md - name: 04-ai-review.md
format: ai-review format: ai-review
- name: ai_fix - name: ai_fix
edit: true edit: true
persona: coder persona: coder
@ -189,6 +170,7 @@ movements:
- condition: 判断できない、情報不足 - condition: 判断できない、情報不足
next: ai_no_fix next: ai_no_fix
instruction: ai-fix instruction: ai-fix
- name: ai_no_fix - name: ai_no_fix
edit: false edit: false
persona: architecture-reviewer persona: architecture-reviewer
@ -203,6 +185,7 @@ movements:
- condition: ai_fixの判断が妥当修正不要 - condition: ai_fixの判断が妥当修正不要
next: reviewers next: reviewers
instruction: arbitrate instruction: arbitrate
- name: reviewers - name: reviewers
parallel: parallel:
- name: arch-review - name: arch-review
@ -251,6 +234,7 @@ movements:
next: supervise next: supervise
- condition: any("needs_fix") - condition: any("needs_fix")
next: fix next: fix
- name: fix - name: fix
edit: true edit: true
persona: coder persona: coder
@ -276,6 +260,7 @@ movements:
- condition: 判断できない、情報不足 - condition: 判断できない、情報不足
next: plan next: plan
instruction: fix instruction: fix
- name: supervise - name: supervise
edit: false edit: false
persona: supervisor persona: supervisor
@ -299,7 +284,6 @@ movements:
- Summary: summary.md - Summary: summary.md
report_formats: report_formats:
plan: ../output-contracts/plan.md plan: ../output-contracts/plan.md
architecture-design: ../output-contracts/architecture-design.md
ai-review: ../output-contracts/ai-review.md ai-review: ../output-contracts/ai-review.md
architecture-review: ../output-contracts/architecture-review.md architecture-review: ../output-contracts/architecture-review.md
qa-review: ../output-contracts/qa-review.md qa-review: ../output-contracts/qa-review.md

View File

@ -0,0 +1,714 @@
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TAKT Prompt Log Viewer</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
}
.container {
max-width: 1800px;
margin: 0 auto;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
color: #ffffff;
}
.drop-zone {
border: 2px dashed #007acc;
border-radius: 8px;
padding: 40px;
text-align: center;
background: #252526;
cursor: pointer;
transition: all 0.3s;
margin-bottom: 20px;
}
.drop-zone:hover,
.drop-zone.drag-over {
background: #2d2d30;
border-color: #0098ff;
}
.drop-zone-text {
font-size: 16px;
color: #858585;
}
.quick-actions {
display: flex;
gap: 10px;
margin-bottom: 20px;
justify-content: center;
}
.action-btn {
padding: 10px 20px;
background: #007acc;
color: #ffffff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.action-btn:hover {
background: #005a9e;
}
.action-btn:disabled {
background: #3e3e42;
color: #858585;
cursor: not-allowed;
}
.action-btn.secondary {
background: #252526;
border: 1px solid #3e3e42;
}
.action-btn.secondary:hover:not(:disabled) {
background: #2d2d30;
border-color: #007acc;
}
.navigation {
display: none;
background: #252526;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
align-items: center;
gap: 10px;
}
.navigation.active {
display: flex;
}
.nav-buttons {
display: flex;
gap: 8px;
}
.nav-btn {
padding: 6px 12px;
background: #1e1e1e;
color: #d4d4d4;
border: 1px solid #3e3e42;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.nav-btn:hover:not(:disabled) {
background: #2d2d30;
border-color: #007acc;
}
.nav-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.current-file {
flex: 1;
text-align: center;
font-size: 14px;
color: #9cdcfe;
}
.file-info {
background: #252526;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
display: none;
}
.file-info.active {
display: block;
}
.stats {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.stat {
display: flex;
flex-direction: column;
}
.stat-label {
font-size: 12px;
color: #858585;
}
.stat-value {
font-size: 16px;
font-weight: 600;
color: #ffffff;
}
.records {
display: flex;
flex-direction: column;
gap: 24px;
}
/* --- Record card --- */
.record {
background: #252526;
border-radius: 8px;
overflow: hidden;
}
.record-header {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: #2d2d30;
border-bottom: 1px solid #3e3e42;
}
.movement-name {
font-weight: 700;
font-size: 15px;
color: #4ec9b0;
}
.phase-badge {
padding: 2px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.phase-badge.phase-1 {
background: #264f78;
color: #9cdcfe;
}
.phase-badge.phase-2 {
background: #4d3800;
color: #dcdcaa;
}
.phase-badge.phase-3 {
background: #2d4a27;
color: #608b4e;
}
.iteration-badge {
font-size: 12px;
color: #858585;
}
.timestamp {
font-size: 12px;
color: #858585;
margin-left: auto;
}
/* --- Side-by-side columns --- */
.columns {
display: grid;
grid-template-columns: 1fr 1fr;
}
.column {
min-width: 0;
}
.column-header {
padding: 8px 16px;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
border-bottom: 1px solid #3e3e42;
}
.column.prompt .column-header {
background: #1a2a3a;
color: #569cd6;
}
.column.response .column-header {
background: #1a2a1a;
color: #608b4e;
border-left: 1px solid #3e3e42;
}
.column-body {
padding: 12px 16px;
font-family: 'Courier New', Consolas, monospace;
font-size: 13px;
line-height: 1.6;
white-space: pre-wrap;
word-break: break-word;
overflow-x: auto;
max-height: 800px;
overflow-y: auto;
}
.column.response .column-body {
border-left: 1px solid #3e3e42;
}
.column.prompt .column-body {
color: #c8c8c8;
}
.column.response .column-body {
color: #d4d4d4;
}
.hidden {
display: none;
}
.error {
background: #f48771;
color: #1e1e1e;
padding: 10px;
border-radius: 4px;
margin-top: 10px;
}
/* --- Scrollbar --- */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #1e1e1e;
}
::-webkit-scrollbar-thumb {
background: #3e3e42;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #4e4e52;
}
/* Filter controls */
.controls {
background: #252526;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
display: none;
}
.controls.active {
display: block;
}
.filter-group {
margin-bottom: 10px;
}
.filter-label {
font-size: 14px;
font-weight: 600;
color: #9cdcfe;
margin-bottom: 8px;
display: block;
}
.filter-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.filter-btn {
padding: 6px 12px;
border: 1px solid #3e3e42;
border-radius: 4px;
background: #1e1e1e;
color: #d4d4d4;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}
.filter-btn:hover {
background: #2d2d30;
border-color: #007acc;
}
.filter-btn.active {
background: #007acc;
border-color: #007acc;
color: #ffffff;
}
</style>
</head>
<body>
<div class="container">
<h1>TAKT Prompt Log Viewer</h1>
<div class="drop-zone" id="dropZone">
<div class="drop-zone-text">
ここに <code>*-prompts.jsonl</code> ファイルをドラッグ&ドロップ<br>
またはクリックしてファイルを選択
</div>
<input type="file" id="fileInput" accept=".jsonl" style="display: none;">
</div>
<div class="quick-actions">
<button class="action-btn" id="loadLatestBtn">📂 ログディレクトリを指定する</button>
<button class="action-btn secondary" id="clearDirBtn" style="display: none;">🗑️ 保存したディレクトリをクリア</button>
</div>
<div class="navigation" id="navigation">
<div class="nav-buttons">
<button class="nav-btn" id="oldestBtn">⏮️ 最古</button>
<button class="nav-btn" id="prevBtn">◀️ Prev</button>
</div>
<div class="current-file" id="currentFile">-</div>
<div class="nav-buttons">
<button class="nav-btn" id="nextBtn">Next ▶️</button>
<button class="nav-btn" id="latestBtn">最新 ⏭️</button>
</div>
</div>
<div class="controls" id="controls">
<div class="filter-group">
<label class="filter-label">Movement</label>
<div class="filter-buttons" id="movementFilters"></div>
</div>
<div class="filter-group">
<label class="filter-label">Phase</label>
<div class="filter-buttons" id="phaseFilters"></div>
</div>
</div>
<div class="file-info" id="fileInfo">
<div class="stats" id="stats"></div>
</div>
<div class="records" id="records"></div>
</div>
<script>
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const loadLatestBtn = document.getElementById('loadLatestBtn');
const clearDirBtn = document.getElementById('clearDirBtn');
const navigation = document.getElementById('navigation');
const currentFileDiv = document.getElementById('currentFile');
const oldestBtn = document.getElementById('oldestBtn');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const latestBtn = document.getElementById('latestBtn');
const controlsDiv = document.getElementById('controls');
const fileInfo = document.getElementById('fileInfo');
const statsDiv = document.getElementById('stats');
const recordsDiv = document.getElementById('records');
const movementFiltersDiv = document.getElementById('movementFilters');
const phaseFiltersDiv = document.getElementById('phaseFilters');
let promptFiles = [];
let currentFileIndex = -1;
let allRecords = [];
let activeMovements = new Set();
let activePhases = new Set([1, 2, 3]);
// --- IndexedDB ---
const DB_NAME = 'TaktPromptViewerDB';
const DB_VERSION = 1;
const STORE_NAME = 'directories';
let db = null;
async function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = () => reject(request.error);
request.onsuccess = () => { db = request.result; resolve(db); };
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME);
}
};
});
}
async function saveDirectoryHandle(handle) {
if (!db) await initDB();
const tx = db.transaction(STORE_NAME, 'readwrite');
tx.objectStore(STORE_NAME).put(handle, 'promptLogDirectory');
}
async function getDirectoryHandle() {
if (!db) await initDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readonly');
const req = tx.objectStore(STORE_NAME).get('promptLogDirectory');
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function clearDirectoryHandle() {
if (!db) await initDB();
const tx = db.transaction(STORE_NAME, 'readwrite');
tx.objectStore(STORE_NAME).delete('promptLogDirectory');
}
// --- Events ---
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('drag-over'); });
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over'));
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('drag-over');
const file = e.dataTransfer.files[0];
if (file) handleFile(file);
});
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) handleFile(file);
});
oldestBtn.addEventListener('click', () => loadFileByIndex(promptFiles.length - 1));
prevBtn.addEventListener('click', () => loadFileByIndex(currentFileIndex + 1));
nextBtn.addEventListener('click', () => loadFileByIndex(currentFileIndex - 1));
latestBtn.addEventListener('click', () => loadFileByIndex(0));
clearDirBtn.addEventListener('click', async () => {
await clearDirectoryHandle();
clearDirBtn.style.display = 'none';
loadLatestBtn.textContent = '📂 ログディレクトリを指定する';
promptFiles = [];
currentFileIndex = -1;
navigation.classList.remove('active');
controlsDiv.classList.remove('active');
fileInfo.classList.remove('active');
recordsDiv.innerHTML = '';
});
loadLatestBtn.addEventListener('click', async () => {
try {
if (!('showDirectoryPicker' in window)) {
alert('お使いのブラウザはこの機能に対応していません。Chrome / Edge / Brave をご使用ください。');
return;
}
const savedHandle = await getDirectoryHandle();
let dirHandle;
if (savedHandle) {
try {
const perm = await savedHandle.queryPermission({ mode: 'read' });
if (perm === 'granted') {
dirHandle = savedHandle;
} else {
const newPerm = await savedHandle.requestPermission({ mode: 'read' });
if (newPerm === 'granted') dirHandle = savedHandle;
}
} catch { /* saved handle invalid */ }
}
if (!dirHandle) {
dirHandle = await window.showDirectoryPicker({ id: 'takt-prompt-logs', startIn: 'documents', mode: 'read' });
await saveDirectoryHandle(dirHandle);
clearDirBtn.style.display = 'inline-block';
loadLatestBtn.textContent = '🔄 最新のログを読み込む';
}
await loadFromDirectoryHandle(dirHandle);
} catch (err) {
if (err.name !== 'AbortError') {
console.error(err);
recordsDiv.innerHTML = `<div class="error">Error: ${err.message}</div>`;
}
}
});
// --- Init ---
initDB().then(async () => {
const saved = await getDirectoryHandle();
if (saved) {
clearDirBtn.style.display = 'inline-block';
loadLatestBtn.textContent = '🔄 最新のログを読み込む';
try { await loadFromDirectoryHandle(saved); } catch { /* ignore */ }
}
});
// --- Directory loading ---
async function loadFromDirectoryHandle(dirHandle) {
promptFiles = [];
for await (const entry of dirHandle.values()) {
if (entry.kind === 'file' && entry.name.endsWith('-prompts.jsonl')) {
const file = await entry.getFile();
promptFiles.push({ name: entry.name, file, modifiedTime: file.lastModified });
}
}
if (promptFiles.length === 0) {
alert('*-prompts.jsonl ファイルが見つかりませんでした。');
return;
}
promptFiles.sort((a, b) => b.modifiedTime - a.modifiedTime);
loadFileByIndex(0);
}
function loadFileByIndex(index) {
if (index < 0 || index >= promptFiles.length) return;
currentFileIndex = index;
handleFile(promptFiles[index].file);
updateNavigation();
}
function updateNavigation() {
if (promptFiles.length === 0) { navigation.classList.remove('active'); return; }
navigation.classList.add('active');
const f = promptFiles[currentFileIndex];
const date = new Date(f.modifiedTime).toLocaleString('ja-JP');
currentFileDiv.textContent = `${f.name} (${currentFileIndex + 1}/${promptFiles.length}) — ${date}`;
oldestBtn.disabled = currentFileIndex === promptFiles.length - 1;
prevBtn.disabled = currentFileIndex === promptFiles.length - 1;
nextBtn.disabled = currentFileIndex === 0;
latestBtn.disabled = currentFileIndex === 0;
}
// --- File handling ---
function handleFile(file) {
const reader = new FileReader();
reader.onload = (e) => {
try {
const lines = e.target.result.trim().split('\n');
allRecords = lines.filter(l => l.trim()).map(l => JSON.parse(l));
buildFilters();
displayRecords();
} catch (err) {
recordsDiv.innerHTML = `<div class="error">Error parsing JSONL: ${err.message}</div>`;
}
};
reader.readAsText(file);
}
// --- Filters ---
function buildFilters() {
const movements = [...new Set(allRecords.map(r => r.movement))];
const phases = [...new Set(allRecords.map(r => r.phase))].sort();
activeMovements = new Set(movements);
activePhases = new Set(phases);
movementFiltersDiv.innerHTML = movements.map(m =>
`<button class="filter-btn active" data-movement="${m}" onclick="toggleMovement('${m}')">${m}</button>`
).join('');
const phaseLabels = { 1: 'Phase 1 (Execute)', 2: 'Phase 2 (Report)', 3: 'Phase 3 (Judge)' };
phaseFiltersDiv.innerHTML = phases.map(p =>
`<button class="filter-btn active" data-phase="${p}" onclick="togglePhase(${p})">${phaseLabels[p] || 'Phase ' + p}</button>`
).join('');
controlsDiv.classList.add('active');
// Stats
const p1 = allRecords.filter(r => r.phase === 1).length;
const p2 = allRecords.filter(r => r.phase === 2).length;
const p3 = allRecords.filter(r => r.phase === 3).length;
statsDiv.innerHTML = `
<div class="stat"><span class="stat-label">Total Records</span><span class="stat-value">${allRecords.length}</span></div>
<div class="stat"><span class="stat-label">Movements</span><span class="stat-value">${movements.length}</span></div>
<div class="stat"><span class="stat-label">Phase 1</span><span class="stat-value">${p1}</span></div>
<div class="stat"><span class="stat-label">Phase 2</span><span class="stat-value">${p2}</span></div>
<div class="stat"><span class="stat-label">Phase 3</span><span class="stat-value">${p3}</span></div>
`;
fileInfo.classList.add('active');
}
function toggleMovement(name) {
if (activeMovements.has(name)) activeMovements.delete(name); else activeMovements.add(name);
document.querySelector(`[data-movement="${name}"]`).classList.toggle('active');
applyFilters();
}
function togglePhase(phase) {
if (activePhases.has(phase)) activePhases.delete(phase); else activePhases.add(phase);
document.querySelector(`[data-phase="${phase}"]`).classList.toggle('active');
applyFilters();
}
function applyFilters() {
document.querySelectorAll('.record').forEach((el, i) => {
const r = allRecords[i];
if (activeMovements.has(r.movement) && activePhases.has(r.phase)) {
el.classList.remove('hidden');
} else {
el.classList.add('hidden');
}
});
}
// --- Render ---
function displayRecords() {
const phaseLabels = { 1: 'Phase 1 (Execute)', 2: 'Phase 2 (Report)', 3: 'Phase 3 (Judge)' };
recordsDiv.innerHTML = allRecords.map((r, i) => {
const ts = r.timestamp ? new Date(r.timestamp).toLocaleTimeString('ja-JP') : '';
const phaseClass = `phase-${r.phase}`;
const phaseLabel = phaseLabels[r.phase] || `Phase ${r.phase}`;
return `
<div class="record" data-index="${i}">
<div class="record-header">
<span class="movement-name">${escapeHtml(r.movement)}</span>
<span class="phase-badge ${phaseClass}">${phaseLabel}</span>
<span class="iteration-badge">iter: ${r.iteration}</span>
<span class="timestamp">${ts}</span>
</div>
<div class="columns">
<div class="column prompt">
<div class="column-header">Prompt</div>
<div class="column-body">${escapeHtml(r.prompt?.trim() ?? '')}</div>
</div>
<div class="column response">
<div class="column-header">Response</div>
<div class="column-body">${escapeHtml(r.response?.trim() ?? '')}</div>
</div>
</div>
</div>
`;
}).join('');
}
function escapeHtml(text) {
if (typeof text !== 'string') return String(text);
return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;').replace(/'/g, '&#039;');
}
</script>
</body>
</html>