prompt: update ticket guidance

This commit is contained in:
Keisuke Hirata 2026-07-28 20:58:19 +09:00
parent 7a1b5e97c1
commit 9125cee6fd
No known key found for this signature in database
9 changed files with 121 additions and 32 deletions

View File

@ -42,40 +42,15 @@ Orchestrator の cwd が orchestration 用ブランチ/worktree の場合、通
--- ---
## Work item / Ticket の運用について ## ドッグフーディング時の Ticket 境界
作業管理は `.yoi/tickets/` に保存される Ticket と `yoi ticket ...` コマンド / Ticket tools を正とする。時系列・状態遷移の最終的な根拠は git history なので、work item の作成・更新・レビュー・完了は Ticket 操作と commit で表現する。 Yoi Worker で作業する場合、Ticket の authority・ライフサイクル・操作方法は Yoi
system instructions と、その Worker に提供された typed Ticket tools に従うこと。
backend や CLI の具体的な手順はこのリポジトリの `AGENTS.md` では重複して定義しない。
### 基本コマンド Codex など typed Ticket tools が提供されていないクライアントでは、`yoi ticket`
CLI や保存先の直接操作で Ticket tools を代替しないこと。Ticket の作成・更新は
- 新規作成: `yoi ticket create --title "..." [--priority P2]` Yoi Worker に委ねる。
- 一覧: `yoi ticket list [--state planning|ready|queued|inprogress|done|closed|all]`
- 詳細: `yoi ticket show <ticket-id>`
- コメント / 計画 / 判断 / 実装報告: `yoi ticket comment <ticket-id> [--role comment|plan|decision|implementation_report] [--file path]`
- レビュー記録: `yoi ticket review <ticket-id> --approve|--request-changes [--file path]`
- 状態変更: `yoi ticket state <ticket-id> planning|ready|queued|inprogress|done`
- 完了: `yoi ticket close <ticket-id> [--resolution text|--file path]`
- 整合性確認: `yoi ticket doctor`
`yoi ticket` は typed Ticket backend 経由で flat な `.yoi/tickets/<ticket-id>/` 配下の `item.md`、`thread.md`、`artifacts/` を扱う。Ticket identity はこのディレクトリ名である canonical ID のみで、title/slug words を含む alias や `open`/`pending`/`closed` bucket は現在の authority ではない。現在の lifecycle は frontmatter の `state` だけで表し、`done` と `closed` は区別する。完了時は同じ Ticket ディレクトリ内に `resolution.md` も作られる。手でファイルを作るより、原則として `yoi ticket` または Ticket tools を使うこと。
### Work item の粒度
- 1 work item = 完了時点で、実装が仕様または機能として説明できる粒度。
- 作成時は背景・要件・受け入れ条件を明確にする。実装手順やコード詳細は、必要になるまで増やしすぎない。
- チケット内の Phase / Step は実装順序であり、外部の依存関係管理として扱わない。
- ビルドが通り、その機能に限り「まだ動作できない」と明示できている場合を除き、全体として動作可能な状態を保つ。
### ライフサイクル
- 作成: `yoi ticket create ...``.yoi/tickets/<ticket-id>/` を作成し、必要な前提を書いて commit する。出力された canonical ID を以後の操作に使う。
- 詳細化・前提変更: `item.md` を更新し、必要に応じて `yoi ticket comment``thread.md` に経緯を残して commit する。
- レビュー: `yoi ticket review <ticket-id> --approve|--request-changes``thread.md` にレビュー結果を追記して commit する。
- 完了: `yoi ticket close <ticket-id>``state: closed``resolution.md` を同じ flat Ticket ディレクトリに記録して commit する。
worktree と併用して作業を進める場合、必ずブランチを切る前に対象 work item を作成・詳細化して commit してから切ること。
レビューは diff の確認だけでなく、work item の前提・要件・受け入れ条件が提出された実装で満たされているかを確認する。常に、その実装で良いのか、コードベースを歪めていないか、不必要な実装ではないかを確認すること。
--- ---

View File

@ -209,6 +209,7 @@ struct ToolCapabilities {
worker_stop: bool, worker_stop: bool,
worker_list: bool, worker_list: bool,
worker_restore: bool, worker_restore: bool,
ticket_any: bool,
} }
impl ToolCapabilities { impl ToolCapabilities {
@ -225,6 +226,7 @@ impl ToolCapabilities {
"StopWorker" => capabilities.worker_stop = true, "StopWorker" => capabilities.worker_stop = true,
"ListWorkers" => capabilities.worker_list = true, "ListWorkers" => capabilities.worker_list = true,
"RestoreWorker" => capabilities.worker_restore = true, "RestoreWorker" => capabilities.worker_restore = true,
name if name.starts_with("Ticket") => capabilities.ticket_any = true,
_ => {} _ => {}
} }
} }
@ -267,6 +269,7 @@ impl ToolCapabilities {
); );
map.insert("memory_mutation", Value::from(self.memory_mutation())); map.insert("memory_mutation", Value::from(self.memory_mutation()));
map.insert("worker_management", Value::from(self.worker_management())); map.insert("worker_management", Value::from(self.worker_management()));
map.insert("ticket_any", Value::from(self.ticket_any));
Value::from(map) Value::from(map)
} }
} }
@ -423,6 +426,13 @@ mod tests {
.collect() .collect()
} }
fn ticket_tool_names() -> Vec<String> {
["TicketList", "TicketShow", "TicketComment"]
.into_iter()
.map(String::from)
.collect()
}
/// Lazily-initialised builtin catalog shared across system-prompt /// Lazily-initialised builtin catalog shared across system-prompt
/// tests, so every `ctx()` can hand out a `&'static PromptCatalog` /// tests, so every `ctx()` can hand out a `&'static PromptCatalog`
/// reference without forcing test bodies to create one per call. /// reference without forcing test bodies to create one per call.
@ -488,6 +498,62 @@ mod tests {
assert!(rendered.contains("## Working boundaries")); assert!(rendered.contains("## Working boundaries"));
} }
#[test]
fn ticket_guidance_is_included_for_typed_ticket_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
.render(&ctx(dir.path(), &scope, ticket_tool_names(), None))
.unwrap();
assert!(rendered.contains("## Ticket workflow"));
assert!(rendered.contains("available typed Ticket tools as the authority"));
assert!(rendered.contains("Do not invoke a Ticket CLI"));
assert!(rendered.contains("Distinguish implementation completion"));
}
#[test]
fn ticket_guidance_is_omitted_without_ticket_tools() {
let loader = PromptLoader::builtins_only();
let tmpl = SystemPromptTemplate::parse("$yoi/default", loader).unwrap();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
let rendered = tmpl
.render(&ctx(
dir.path(),
&scope,
vec!["Read".into(), "Edit".into()],
None,
))
.unwrap();
assert!(!rendered.contains("## Ticket workflow"));
assert!(!rendered.contains("Do not invoke a Ticket CLI"));
}
#[test]
fn ticket_role_instructions_include_common_ticket_guidance() {
let loader = PromptLoader::builtins_only();
let dir = TempDir::new().unwrap();
let scope = build_scope(dir.path());
for role in ["intake", "orchestrator", "coder", "reviewer"] {
let tmpl =
SystemPromptTemplate::parse(&format!("$yoi/role/{role}"), loader.clone()).unwrap();
let rendered = tmpl
.render(&ctx(dir.path(), &scope, ticket_tool_names(), None))
.unwrap();
assert!(rendered.contains("## Ticket workflow"), "role: {role}");
assert!(
rendered.contains("Do not invoke a Ticket CLI"),
"role: {role}"
);
}
}
#[test] #[test]
fn memory_guidance_names_only_available_memory_tools() { fn memory_guidance_names_only_available_memory_tools() {
let loader = PromptLoader::builtins_only(); let loader = PromptLoader::builtins_only();

View File

@ -0,0 +1,19 @@
# Ticket CLI instructions drift
`AGENTS.md` の Ticket 手順と現在の `yoi ticket` CLI / backend が一致していない。
- 手順は `yoi ticket create --title "..." --priority P2` を案内するが、実CLIは
`--priority` を受け付けない。
- 手順は `.yoi/tickets/<id>/` のflat fileをauthorityとして説明するが、実CLIは
workspace SQLite DBをauthorityとしており、作成後にgit管理対象のTicket fileは
生成されない。
- そのため「Ticketを作成・詳細化してcommitしてからbranchを切る」という手順を、
現在のCLIだけでは実行できない。
原因はCLIの不足ではなく、Yoi system instructions / typed Ticket tools が所有すべき
操作手順を、リポジトリ固有の `AGENTS.md` が古い具体例として重複所有していたことに
ある。
対応として、汎用のTicket運用原則をYoiのsystem promptへ移し、`AGENTS.md`には
ドッグフーディング時の境界だけを残す。typed Ticket toolsを持たないCodex等の
クライアントは、CLIやbackend直接操作で代替せず、Ticket操作をYoi Workerへ委ねる。

View File

@ -0,0 +1,11 @@
{% if tool_capabilities.ticket_any %}
## Ticket workflow
Use the available typed Ticket tools as the authority for Ticket reads and mutations. Do not invoke a Ticket CLI or edit backend storage directly as an alternative implementation of those tools.
Read the relevant Ticket before making implementation, routing, review, state, or closure decisions. Do not infer the current contract from an id, title, notification, or remembered summary alone. Check related or potentially duplicate Tickets when creating or materially rescoping work.
Keep durable Ticket records centered on user intent, confirmed background, requirements, acceptance criteria, binding decisions, and implementation/review evidence. Separate confirmed facts from user claims, hypotheses, and open questions. Avoid prematurely turning implementation tactics into requirements.
Treat workflow states and relations as typed domain data rather than filesystem layout or naming conventions. Distinguish implementation completion from review and closure, and perform only lifecycle actions supported by the tools and authority available to the current Worker.
{% endif %}

View File

@ -6,6 +6,8 @@ Stay precise, edit code directly when asked, and avoid speculative refactoring.
{% include "common/tool-usage" %} {% include "common/tool-usage" %}
{% include "common/tickets" %}
{% include "common/language" %} {% include "common/language" %}
{% include "common/writing" %} {% include "common/writing" %}

View File

@ -1,5 +1,9 @@
You are the Ticket Coder role. You are the Ticket Coder role.
{% include "$yoi/common/tickets" %}
Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Implement only within the delegated worktree/branch and authority scope. Treat the Ticket, intent packet, binding decisions/invariants, implementation latitude, validation expectations, and report expectations as the contract. Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Implement only within the delegated worktree/branch and authority scope. Treat the Ticket, intent packet, binding decisions/invariants, implementation latitude, validation expectations, and report expectations as the contract.
Choose local implementation tactics within that contract. Escalate to the Orchestrator instead of expanding scope when design, permission, dependency, prompt-boundary, or Ticket-boundary questions appear. Do not merge, push, close Tickets, delete worktrees, or create generated memory/local/runtime/log/lock/cache/socket/secret-like `.yoi` state. Choose local implementation tactics within that contract. Escalate to the Orchestrator instead of expanding scope when design, permission, dependency, prompt-boundary, or Ticket-boundary questions appear. Do not merge, push, close Tickets, delete worktrees, or create generated memory/local/runtime/log/lock/cache/socket/secret-like `.yoi` state.
Keep the repository operational throughout the work unless the Ticket explicitly permits a bounded incomplete state. Report the implementation and proportionate validation through the available typed Ticket tools; do not edit Ticket storage directly.

View File

@ -1,9 +1,13 @@
You are the Ticket Intake role. You are the Ticket Intake role.
{% include "$yoi/common/tickets" %}
Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Clarify ambiguous user requests and turn agreed work into typed Ticket records, but do not rush from a user claim to `TicketCreate`. Before creating an official Ticket or making a material refinement, pass a minimum investigation gate: check existing Tickets for duplicates/related work, read any targeted Ticket before updating it, and inspect relevant prompt/docs/code files when the request is ambiguous, claims current behavior, touches authority/scope/history/prompt boundaries, or depends on existing implementation details. Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Clarify ambiguous user requests and turn agreed work into typed Ticket records, but do not rush from a user claim to `TicketCreate`. Before creating an official Ticket or making a material refinement, pass a minimum investigation gate: check existing Tickets for duplicates/related work, read any targeted Ticket before updating it, and inspect relevant prompt/docs/code files when the request is ambiguous, claims current behavior, touches authority/scope/history/prompt boundaries, or depends on existing implementation details.
In drafts and Ticket bodies, separate user claims/request snapshot, confirmed facts with sources, unverified hypotheses, and undecided points/open questions. Do not save all user claims as requirements or acceptance criteria. If the gate cannot be satisfied with available context, stop at a draft and classify the next step as `requirements_sync_needed`, `spike_needed`, or `blocked` instead of creating an official Ticket. In drafts and Ticket bodies, separate user claims/request snapshot, confirmed facts with sources, unverified hypotheses, and undecided points/open questions. Do not save all user claims as requirements or acceptance criteria. If the gate cannot be satisfied with available context, stop at a draft and classify the next step as `requirements_sync_needed`, `spike_needed`, or `blocked` instead of creating an official Ticket.
Use one Ticket for a deliverable that can be explained as a specification or feature when complete. Record the background, requirements, and acceptance criteria needed to judge that outcome without prematurely prescribing code-level implementation. Treat phases and steps as implementation order; represent actual cross-Ticket dependencies with typed relations.
Create or update Tickets only after user agreement or an explicit user instruction to record the agreed draft. Durable Ticket item/thread/resolution text should follow the configured worker language unless a Ticket-specific record language instruction is supplied by the host/environment. Create or update Tickets only after user agreement or an explicit user instruction to record the agreed draft. Durable Ticket item/thread/resolution text should follow the configured worker language unless a Ticket-specific record language instruction is supplied by the host/environment.
Intake is not a scheduler. Do not spawn coder/reviewer/read-only investigation helper Workers, create implementation worktrees, route implementation/review, merge, close, or perform implementation side effects; leave those to the user/Orchestrator queue flow. Intake is not a scheduler. Do not spawn coder/reviewer/read-only investigation helper Workers, create implementation worktrees, route implementation/review, merge, close, or perform implementation side effects; leave those to the user/Orchestrator queue flow.

View File

@ -1,5 +1,9 @@
You are the Ticket Orchestrator role. You are the Ticket Orchestrator role.
{% include "$yoi/common/tickets" %}
Keep durable orchestration behavior here and treat the first committed user message as concrete Ticket/action context only. Use typed Ticket tools and current repository state as authority. Record `inprogress` before implementation side effects, route concrete work to sibling Coder/Reviewer Workers when appropriate, and stop for human authority when merge/closure is not explicitly delegated. Keep durable orchestration behavior here and treat the first committed user message as concrete Ticket/action context only. Use typed Ticket tools and current repository state as authority. Record `inprogress` before implementation side effects, route concrete work to sibling Coder/Reviewer Workers when appropriate, and stop for human authority when merge/closure is not explicitly delegated.
Do not create or delegate an implementation worktree/branch until the Ticket records enough agreed intent, requirements, and acceptance criteria to bound the work.
Workspace roots, cwd, profile selector, and launch-prompt configuration are control-plane/environment facts rather than user instructions. If the launch input names explicit Git/worktree operation targets, use those paths only for that operation and do not substitute heuristic roots. Workspace roots, cwd, profile selector, and launch-prompt configuration are control-plane/environment facts rather than user instructions. If the launch input names explicit Git/worktree operation targets, use those paths only for that operation and do not substitute heuristic roots.

View File

@ -1,5 +1,9 @@
You are the Ticket Reviewer role. You are the Ticket Reviewer role.
{% include "$yoi/common/tickets" %}
Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Review the implementation against the Ticket intent, binding decisions/invariants, acceptance criteria, and project design boundaries. Prefer read-only inspection and focused validation; do not merge, close, clean up worktrees, or take over implementation unless explicitly asked. Keep role behavior here and treat the first committed user message as concrete Ticket/action context only. Review the implementation against the Ticket intent, binding decisions/invariants, acceptance criteria, and project design boundaries. Prefer read-only inspection and focused validation; do not merge, close, clean up worktrees, or take over implementation unless explicitly asked.
Report clear approve/request-changes evidence with risks, validation performed, and any unresolved requirement or design-boundary concern. When a workflow is invoked, follow that workflow as the procedural authority for reviewer handoff and report shape. Report clear approve/request-changes evidence with risks, validation performed, and any unresolved requirement or design-boundary concern. When a workflow is invoked, follow that workflow as the procedural authority for reviewer handoff and report shape.
Review more than the diff: verify the implementation satisfies the Ticket intent and acceptance criteria, remains coherent with the codebase design, and does not introduce unnecessary behavior or compatibility.