作成日: 2026-06-02
ステータス: Draft
対象 issue: #50 Brain の issue 操作抽象化: gitea 依存を隠す
関連文書:
本仕様は、Brain が Gitea・Git の詳細を知らずに作業記録・issue 操作を行える Brain-facing インターフェースを定義する。
Butler を「作業を観測し、記録し、共有し、issue と結び、締める」作業記録システムとして Brain に見せることで、Brain のトークン消費を低レベル操作から切り離し、判断・設計・会話に集中させることを目的とする。
本仕様は BWR capability の全体方針を定義しつつ、
現時点で実装対象とする Phase 1 の詳細仕様を中心に記述する。
Phase 2 以降は候補として扱い、詳細仕様は別途定義する。
Brain から見ると、Butler は Git の便利ラッパーではない。Butler は独自の作業記録システム (Butler Work Record System, BWR) であり、Brain はその上で作業を行う。
Brain が使う語彙:
| Brain の言葉 | Butler の操作 |
|---|---|
| 作業を記録する | work_record |
| 未記録の作業を確認する | work_observe |
| 記録済みの作業を共有先に反映する | work_publish |
| 作業を締める | work_finish |
| issue を読む | issue_read |
| issue にコメントする | issue_comment |
| issue コメントを削除する | issue_delete_comment |
| issue タイトルを更新する | issue_update_title |
| issue 本文を更新する | issue_update_body |
Brain に見えないもの: Git / Gitea の語彙・コマンド・ツール名はすべて内部実装に隠蔽される。
Brain の基本的な作業フローは次の 6 ステップで構成される。
work_session_start(project_root)
↓
work_start(issue_id?)
↓
work_observe() ← 状態確認・次アクション誘導の入口
↓
work_record(message, issue_ids?)
↓
work_publish()
↓
work_finish()
work_session_start(project_root)役割: Butler セッションを初期化する。最初に一度だけ呼ぶ。
project_root を指定することで、Butler が backend / owner / repo を自動解決し、以降の work_* / issue_* 呼び出しからこれらのパラメータが不要になる。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
project_root |
必須 | 作業対象プロジェクトの絶対パス |
セッション状態の保持スコープ(Phase 1 制約): project_root および default_issue は MCP connection スコープに保存することが目標だが、Phase 1 では stdio 1接続前提 で実装する。FastMCP が接続単位の識別子を提供しないため、セッション状態は内部 session key を使ったプロセス内 dict で管理し、最後に呼んだ work_session_start のセッションがアクティブになる。複数の同時接続(HTTP モード等)での混線は Phase 2 以降で解決する。Brain-facing API は実装方式によらず変わらない。
戻り値:
{
"status": "ok",
"summary": "セッションを初期化しました",
"data": {
"project_root": "/home/akira/develop/butler2",
"resolved_repo": "akira/butler2"
}
}
Brain-facing description:
Butler セッションを初期化します。最初に一度だけ呼んでください。
project_root を指定することで、以降の work_* / issue_* 呼び出しで
owner / repo / backend の指定が不要になります。
work_start(issue_id?)役割: 作業セッションの default issue を設定する。
work_start は作業をロックするのではなく、「この作業は基本的に issue #N に関係する」という既定値を Butler セッションに記録するだけである。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
任意 | 作業の主たる issue 番号 |
設計原則:
work_record は issue_ids 省略時にのみ default issue を使うwork_record(issue_ids=[...]) で明示的に上書き可能work_record(issue_ids=[]) で issue 紐付けなしを明示可能issue_read / issue_comment などは default issue に関係なく呼べるwork_observe()役割: 現在の作業状態を返し、次に必須のアクションと任意で選べるアクションを構造化して提示する。
work_observe はこの仕様の中核である。Brain がセッション開始時、または次に何をすべきか確認したい時に呼ぶ。
work_observe は軽量な現在地確認・次アクション誘導・コンテキスト回復の入口であり、git status 相当の状態確認を置き換える。git diff 相当の詳細確認はこのツールには含めず、必要な時だけ work_diff に明示的に委譲する。
Brain が長い作業やコンテキスト圧縮で失いやすいのは raw diff ではなく、「何の issue で、直近何を記録し、今どの状態にいるか」という作業文脈である。そのため work_observe は patch / stat / 行数ではなく、changed_files / recent_records / active_issue を中心に返す。
パラメータ: なし
work_state の値:
| 値 | 意味 |
|---|---|
uninitialized |
セッションが未初期化 |
clean_idle |
変更なし・active issue なし(アイドル) |
clean_with_active_issue |
変更なし・記録済み・公開済み・active issue あり |
dirty |
未記録の変更がある |
recorded_unpublished |
記録済みだが未公開 |
dirty_and_unpublished |
未記録の変更があり、かつ未公開記録もある |
blocked |
何らかのブロック状態 |
unknown |
状態が特定できない |
戻り値パターン:
共通フィールド:
| フィールド | 内容 |
|---|---|
work_state |
現在の作業状態 |
default_issue |
互換・内部状態用の issue 番号。Brain-facing には active_issue を優先する |
active_issue |
現在の作業 issue。少なくとも number / title を含む |
changed_files |
変更ファイル一覧。patch / stat / 行数は含めない |
recent_records |
直近の work_record メッセージ一覧 |
unpublished_records |
未公開記録数 |
required_action |
次に必須の操作。必須操作がなければ null |
available_next |
任意で選べる次操作の候補 |
diff_summary は返さない。過去の実装・互換で存在する場合も非推奨フィールドとして扱い、Brain-facing の通常仕様には含めない。diff / stat / patch の確認が必要な場合は work_diff を呼ぶ。
通常(未記録変更あり):
{
"status": "ok",
"summary": "未記録の変更があります。work_record で記録してください",
"data": {
"work_state": "dirty",
"default_issue": 50,
"active_issue": {
"number": 50,
"title": "Brain の issue 操作抽象化: gitea 依存を隠す"
},
"changed_files": ["src/mcp_facade.py"],
"recent_records": [
{
"id": "20260612-001",
"message": "work_observe ツールを追加",
"issue_ids": [50],
"published": false,
"created_at": "2026-06-12T10:20:00+09:00"
}
],
"unpublished_records": 0,
"required_action": {
"tool": "work_record",
"reason": "未記録の変更があります",
"required_args": ["message"]
},
"available_next": ["work_record", "work_diff", "work_history"]
}
}
クリーン・active issue あり(締め待ち):
{
"status": "ok",
"summary": "作業は記録・公開済みです。締め処理を行ってください",
"data": {
"work_state": "clean_with_active_issue",
"default_issue": 50,
"active_issue": {
"number": 50,
"title": "Brain の issue 操作抽象化: gitea 依存を隠す"
},
"changed_files": [],
"recent_records": [
{
"id": "20260612-001",
"message": "work_observe ツールを追加",
"issue_ids": [50],
"published": true,
"created_at": "2026-06-12T10:20:00+09:00"
}
],
"unpublished_records": 0,
"required_action": {
"tool": "work_finish",
"reason": "作業は記録・公開済みです。締め処理を行ってください",
"required_args": []
},
"available_next": ["work_finish", "work_history"]
}
}
クリーン・アイドル(active issue なし):
{
"status": "ok",
"summary": "作業中の変更はありません",
"data": {
"work_state": "clean_idle",
"default_issue": null,
"active_issue": null,
"changed_files": [],
"recent_records": [],
"unpublished_records": 0,
"required_action": null,
"available_next": ["work_start"]
}
}
required_action: null は「今すぐ何かしなければならない状態ではない」ことを意味する。
未公開記録あり:
{
"status": "ok",
"summary": "未公開の記録があります。work_publish で共有先に反映してください",
"data": {
"work_state": "recorded_unpublished",
"default_issue": 50,
"active_issue": {
"number": 50,
"title": "Brain の issue 操作抽象化: gitea 依存を隠す"
},
"changed_files": [],
"recent_records": [
{
"id": "20260612-001",
"message": "work_observe ツールを追加",
"issue_ids": [50],
"published": false,
"created_at": "2026-06-12T10:20:00+09:00"
}
],
"unpublished_records": 2,
"required_action": {
"tool": "work_publish",
"reason": "未公開の記録があります",
"required_args": []
},
"available_next": ["work_publish", "work_history"]
}
}
セッション未初期化:
{
"status": "ok",
"summary": "セッションが初期化されていません。work_session_start を呼んでください",
"data": {
"work_state": "uninitialized",
"default_issue": null,
"active_issue": null,
"changed_files": null,
"recent_records": [],
"required_action": {
"tool": "work_session_start",
"reason": "セッションが初期化されていません",
"required_args": ["project_root"]
},
"available_next": ["work_session_start"]
}
}
default_issue 未設定(issue 紐付けヒント付き):
{
"status": "ok",
"summary": "未記録の変更があります。issue_ids を指定するか、省略してください",
"data": {
"work_state": "dirty",
"default_issue": null,
"active_issue": null,
"changed_files": ["src/mcp_facade.py"],
"recent_records": [
{
"id": "20260612-001",
"message": "work_observe ツールを追加",
"issue_ids": [],
"published": false,
"created_at": "2026-06-12T10:20:00+09:00"
}
],
"unpublished_records": 0,
"required_action": {
"tool": "work_record",
"reason": "未記録の変更があります",
"required_args": ["message"],
"policy_hint": "issue_ids に紐付け先を指定するか、issue_ids=[] で紐付けなしにしてください"
},
"available_next": ["work_record", "work_start", "work_diff", "work_history"]
}
}
設計原則:
required_action は文字列ではなく構造化フィールドにするrequired_action は次に必須の操作だけを表すavailable_next は必須ではないが選択可能な操作を表すrequired_args で Brain が次に何を埋めるべきか分かるようにするwork_state は機械判定しやすい enum 的な値にするchanged_files はファイル一覧に留め、diff 本文・stat・行数を含めないrecent_records は小さい固定件数をデフォルトとし、詳細な履歴検索は work_history に委譲するactive_issue は番号だけでなくタイトルを含め、Brain のコンテキスト回復を助けるwork_diff は原則として required_action ではなく available_next に置くBrain-facing description:
セッション開始時、または次に何をすべきか確認したい時に呼ぶツールです。
現在の作業状態、変更ファイル一覧、直近の作業記録、active issue、次に必須の操作と任意で選べる操作を返します。
work_record(message, issue_ids?)役割: 現在の作業内容を、後から参照できる永続的な作業記録として保存する。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
message |
必須 | 作業記録のメッセージ |
issue_ids |
任意 | 紐付ける issue 番号のリスト |
issue_ids の意味:
| 指定方法 | 意味 |
|---|---|
| 省略 | work_start(issue_id) の default issue を使う |
[50, 123] など明示 |
指定 issue 群へ紐付ける |
[] |
issue 紐付けなしを明示する |
呼び出し例:
work_record(message="docs: 作業記録インターフェース案を追加")
work_record(message="fix: バグ修正", issue_ids=[50])
work_record(message="fix: 派生バグも修正", issue_ids=[50, 123])
work_record(message="chore: コード整理", issue_ids=[])
Brain-facing description:
現在の作業内容を、後から参照できる永続的な作業記録として保存します。
work_publish()役割: 記録済みの作業を共有先へ反映する。
パラメータ: なし
状態別の挙動:
| 作業状態 | 挙動 |
|---|---|
recorded_unpublished |
正常に共有先へ反映する |
dirty / dirty_and_unpublished |
実行せず policy_blocked を返し、先に work_record を促す |
clean_idle / clean_with_active_issue |
共有済みのため ok を返し、その旨を summary に含める |
dirty 状態でのエラー応答例:
{
"status": "error",
"error_code": "policy_blocked",
"summary": "未記録の変更があるため共有できません",
"hint": "先に work_record で作業を記録してください"
}
Brain-facing description:
記録済みの作業を共有先へ反映します。
未記録の作業が残っている場合は実行せず、先に work_record を促します。
work_finish()役割: 作業を締めるための抽象操作。
Brain が作業終了時に行うべき確認をチェックリストとして順に評価し、提案を返す。実行はしない。
Phase 1 の動作(提案のみ・自動実行なし):
1. 未記録変更がある → work_record を促す(以降のチェックをスキップ)
2. 公開状態が不明(upstream 未設定)
→ configure_upstream を案内する(以降のチェックをスキップ)
※ 公開状態未確認のまま issue_close を提案しない
3. 未公開記録がある → work_publish を促す(以降のチェックをスキップ)
4. default issue がある → issue_comment で作業要約コメントを促す
5. 完了条件を満たしていそう → issue_close を提案する(実行はしない)
ステップ 5 の「完了条件を満たしていそう」は、現状の heuristic として「未記録・未公開がなく、default issue がある」で判定する。実際に close するかは Brain が判断する。
close 提案の戻り値例:
{
"status": "ok",
"summary": "作業は記録・公開済みです。以下を確認してください",
"data": {
"pending_actions": [
{
"action": "issue_comment",
"reason": "作業要約を issue #50 に残すことを推奨します",
"required_args": ["issue_id", "body"]
},
{
"action": "issue_close",
"reason": "完了条件を満たしていそうです。issue #50 を閉じますか?",
"required_args": ["issue_id"]
}
]
}
}
Phase 2 では work_finish(auto=True) のような自動実行オプションを検討する。
パラメータ: なし
issue_read(issue_id, last_n_comments?)役割: issue の詳細を取得する。Brain が owner / repo / backend を指定する必要はない。
トークン削減のため、コメントはデフォルトで取得しない。必要な件数を last_n_comments で明示する。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
必須 | issue 番号 |
last_n_comments |
任意 | 末尾 N 件のコメントを取得する。省略時はコメントなし(本文のみ) |
呼び出し例:
issue_read(50) # 本文のみ(コメントなし)
issue_read(50, last_n_comments=3) # 末尾 3 件のコメントを含む
issue_read(50, last_n_comments=0) # 本文のみ(明示版)
issue_create(title, body?, label_names?)役割: 新規 issue を作成する。Brain は owner / repo / backend の詳細を指定しない。
Brain-facing パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
title |
必須 | issue のタイトル |
body |
任意 | issue 本文。指定する場合は後述の構造化本文契約を満たす |
label_names |
任意 | ラベル名のリスト。名前で指定し、ID は Brain が意識しない |
設計原則:
owner / repo は work_session_start で解決済みのものを使うlabel_ids は受け付けない。名前から Butler が解決するbody の構造制約は Brain-facing 仕様として明示する構造化本文契約:
body を指定する場合は、少なくとも次の3項目を含める。
## 現在の状態(なぜOpenか)
## 次にすること(Next Action)
## ブロック要因
見出しの括弧内補足は省略してもよいが、Brain は「現在の状態」「次にすること」「ブロック要因」を明確に分けて渡す必要がある。
body を省略した場合、Butler はデフォルトテンプレートを適用する。ただし、テンプレート作成に必要な情報が不足している場合は、勝手に推測せず need_input / invalid_body として不足項目を返す。
期待する不足時レスポンス例:
{
"status": "error",
"error_code": "invalid_body",
"summary": "issue の本文形式が不足しています",
"hint": "現在の状態、次にすること、ブロック要因を教えてください",
"data": {
"required_fields": ["current_state", "next_action", "blocker"]
}
}
この仕様の目的は、毎回長いテンプレート説明を Brain に背負わせることではなく、issue_create の入力契約を短く明示し、不足時だけ Butler がインタビューできるようにすることである。
呼び出し例:
issue_create(title="新機能: work_observe を追加する")
issue_create(
title="新機能: work_observe を追加する",
body="## 現在の状態(なぜOpenか)\n未実装のため Open\n\n## 次にすること(Next Action)\n仕様書に基づき実装する\n\n## ブロック要因\nなし",
label_names=["enhancement"]
)
issue_comment(issue_id, body)役割: issue にコメントを追加する。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
必須 | コメントを追加する issue 番号 |
body |
必須 | コメント本文 |
issue_delete_comment(issue_id, comment_id, reason?)役割: issue の既存コメントを削除する。Brain は owner / repo / backend の詳細を指定しない。
誤投稿・重複投稿・不要になった作業記録コメントを整理するための目的別 API である。低レベル Gitea API を Brain に公開せず、コメント削除も Butler の抽象操作として扱う。
Brain-facing パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
必須 | コメントが属する issue 番号 |
comment_id |
必須 | 削除するコメント ID |
reason |
任意 | 削除理由。監査・作業記録用の補助情報 |
設計原則:
owner / repo は work_session_start で解決済みのものを使うdelete_issue_comment に委譲するissue_update ではなく、削除対象をコメントに限定した目的別 API とするissue_update_title(issue_id, title)issue_update_title は、issue 起票後にタイトルを実態に合わせて短く正確に直したい場合のための目的別 API である。
Brain-facing には汎用 issue_update を公開しない。タイトル更新だけを目的にした issue_update_title として公開し、backend 固有の PATCH /issues/{index} や Gitea の payload 形式を隠す。
入力:
issue_idtitle振る舞い:
update_issue(title=...) に委譲するnot_found または backend error として返すissue_update_body(issue_id, body)役割: 既存 issue の本文を更新する。Brain は owner / repo / backend の詳細を指定しない。
issue_update_body は、issue 起票後に本文を清書・補完したい場合や、テンプレート本文を作業状況に合わせて整理したい場合のための目的別 API である。
Phase 1 では汎用 issue_update を Brain-facing に公開しない。title / state / labels などを含む汎用更新は影響範囲が広いため、まず本文更新だけを明示的に公開する。
Brain-facing パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
必須 | 本文を更新する issue 番号 |
body |
必須 | 更新後の issue 本文 |
設計原則:
owner / repo は work_session_start で解決済みのものを使うinvalid_body または need_input として返すupdate_issue(body=...) に委譲するtitle / state / labels は受け付けない。必要になった場合は目的別 API を追加する戻り値例:
{
"status": "ok",
"summary": "issue #50 の本文を更新しました",
"data": {
"issue": {
"number": 50,
"body": "## 現在の状態..."
}
}
}
issue_reopen(issue_id)役割: closed issue を再オープンする。
Brain は issue の状態更新方法や backend の state 値を意識しない。issue_reopen は「閉じた issue を再び作業対象に戻す」という Brain-facing の抽象操作として扱う。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
issue_id |
必須 | 再オープンする issue 番号 |
戻り値例:
{
"status": "ok",
"summary": "issue #50 を再オープンしました",
"data": {
"issue": {
"number": 50,
"state": "open"
}
}
}
Phase 1 では、Brain-facing の主要入口を work_observe / work_record / work_publish / work_finish に寄せる。
ただし #69 の方針により、work_observe は diff 詳細や履歴詳細を返さない。Brain が差分確認や履歴確認を明示的に必要とする場面のため、work_diff と work_history は Phase 1.5 の最小実装として扱う。
work_diff(path?, level?, record_id?)役割: Brain が変更内容を明示的に確認したい時だけ呼ぶ。
work_observe が diff / stat / patch を自動で返さない代わりに、詳細確認の入口として work_diff を用意する。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
path |
任意 | 対象ファイルパス。指定時はそのファイルの差分に絞る |
level |
任意 | stat または full。省略時は短く安全な概要を返す |
record_id |
任意 | 特定 work_record の変更内容を確認するための識別子 |
設計原則:
work_observe から自動的には呼ばないlevel="full" はトークン消費が大きくなり得るため、Brain が明示的に要求した時だけ使うrecord_id 指定により、work_history や recent_records から詳細確認へつなげられるwork_history(n?, path?)役割: 直近数件では足りない場合に、過去の作業記録を探す。
#69 の raw git log 対策として、Phase 1.5 の最小実装に含める。これは高度な履歴検索ではなく、Brain が git log に流れた時の deterministic な代替導線である。
パラメータ:
| 名前 | 必須 | 説明 |
|---|---|---|
n |
任意 | 取得件数。省略時は 10 件程度の小さい固定値 |
path |
任意 | 対象ファイルパス。指定時はそのファイルに関係する記録に絞る |
戻り値の方針:
record_id / message / created_at を含めるrecord_id は work_diff(record_id=...) に渡せる形式にするwork_status ← work_observe の subset であり入口が増えるため不要
issue_update ← 汎用 issue 更新は影響が大きく、Phase 1 では扱わない
ただし、本文更新は issue 起票後の清書・補完で必要になるため、汎用 issue_update ではなく目的別の issue_update_body として Phase 1 に含める。
issue_list は issue 番号が分からない場合の探索用として実装してもよい。ただし Phase 1 の完了条件には含めない。
issue_close は補助ツールではなく Phase 1 の Brain-facing 主要ツールに含める。
ただし work_finish の提案を経由することを推奨し、Brain が単独で判断して呼んでもよい。
すべての work_* / issue_* ツールは次の共通形式で返す。
成功時:
{
"status": "ok",
"summary": "人間が読める結果の要約(任意)",
"data": { }
}
summary は任意フィールドだが、Brain が状態を素早く把握するために可能な限り返すことを推奨する。work_observe のように data 自体が豊富な構造化情報を持つ場合は省略してよい。
エラー時:
{
"status": "error",
"error_code": "conflict | auth_failed | not_found | need_input | invalid_body | invalid_title | label_not_found | policy_blocked | backend_error | upstream_not_configured",
"summary": "何が起きたかの説明",
"hint": "Brain が次に取るべき対処の候補"
}
error_code の意味:
| コード | 意味 |
|---|---|
conflict |
変更の競合 |
auth_failed |
認証エラー |
not_found |
対象が見つからない |
need_input |
Brain からの追加情報が必要 |
invalid_body |
issue 本文が Brain-facing 仕様の構造を満たしていない |
invalid_title |
issue タイトルが空、または仕様上不正 |
label_not_found |
指定された label_names を解決できない |
policy_blocked |
操作ポリシーにより実行できない状態 |
backend_error |
backend 側の予期しないエラー |
upstream_not_configured |
共有先(upstream)が設定されておらず公開状態を確認できない |
exit code 1 などの backend 詳細は Brain に見せない。hint により Brain が次の操作を判断できるようにする。また hint には Git 語彙(git push 等)を出さず、Butler の抽象操作語彙で案内する。
Brain 向け MCP と Worker 向け MCP の公開面を分ける。Brain が参照できるツール一覧に git_* / gitea_* が残っていると、LLM は既知のコマンド体系へ引き寄せられるため、Brain 用セッションから低レベルツールを除外することが本命の対策となる。
ファイル構成:
mcp_facade.py
├─ brain_tools.py ← work_* / issue_* のみ公開
└─ worker_tools.py ← git_* / gitea_* を含む内部向けツール公開
Brain が見えるツール:
work_session_start
work_start
work_observe
work_record
work_publish
work_finish
issue_read
issue_create
issue_comment
issue_delete_comment
issue_update_title
issue_update_body
issue_reopen
issue_close
任意の便利ツールとして issue_list を公開してもよい。ただし Phase 1 の完了条件には含めない。
Brain が見えないツール(internal / worker adapter):
git_commit
git_push
git_pull
gitea_get_issue
gitea_add_comment
gitea_update_issue
gitea_close_issue
誘導の多層化:
| 層 | 内容 |
|---|---|
| 本命 | Brain 用セッションから低レベルツールを見えなくする |
| 保険 | MCP Instructions で work_observe から始めるよう誘導する |
| 継続誘導 | work_observe / work_finish の戻り値で required_action を返す |
MCP サーバーは接続時に次の Instructions を Brain へ渡す。
Butler は作業記録システムです。
セッション開始時は work_session_start(project_root) を呼んでください。
作業開始時や状態確認時は、まず work_observe() を呼んでください。
work_observe() は現在の作業状態、変更ファイル一覧、直近の作業記録、active issue、次に必須の操作と任意で選べる操作を返します。
diff を確認したいときは work_diff() を使ってください。
作業履歴を確認したいときは work_history() を使ってください。
作業内容の保存には work_record() を使ってください。
記録済み作業の共有には work_publish() を使ってください。
ユーザーが「確定して」「公開して」「反映して」と依頼した場合は、まず work_observe() で状態を確認し、必要に応じて work_record() を促したうえで work_publish() を実行してください。
issue 操作には issue_read / issue_create / issue_comment / issue_delete_comment / issue_update_title / issue_update_body / issue_reopen / issue_close を使ってください。
issue_create の body は、現在の状態・次にすること・ブロック要因を含む構造化本文にしてください。不足時は Butler が追加情報を求めます。
既存 issue の本文を清書・補完する場合は issue_update_body を使ってください。
低レベル backend 操作は Brain 向けには公開されません。
Phase 1 では deterministic に実装できる範囲を優先する。
主要ツール:
work_session_start(project_root)
work_start(issue_id?)
work_observe()
work_diff(path?, level?, record_id?)
work_history(n?, path?)
work_record(message, issue_ids?)
work_publish()
work_finish()
issue_read(issue_id, last_n_comments?)
issue_create(title, body?, label_names?)
issue_comment(issue_id, body)
issue_delete_comment(issue_id, comment_id, reason?)
issue_update_title(issue_id, title)
issue_update_body(issue_id, body)
issue_reopen(issue_id)
任意の便利ツール:
issue_list
issue_list は issue 番号探索用に公開してもよいが、Phase 1 の完了条件には含めない。
work_status / 汎用 issue_update は Phase 1 では実装しない。
work_history は #69 の raw git log 代替として Phase 1.5 の最小実装に含める。通常のコンテキスト回復は work_observe の recent_records を優先し、直近数件では足りない場合だけ work_history を使う。
既存の git_* / gitea_* ツールを adapter として使う。Brain-facing の description にはこれらの詳細を書かない。
内部実装と description の対比(work_record の例):
悪い説明: git add -A と git commit を実行します。
良い説明: 現在の作業内容を、後から参照できる永続的な作業記録として保存します。
正式な adapter インターフェース化は Phase 2 でよい。しかし work_record → git_commit や issue_read → gitea_get_issue をベタ書きすると後で剥がしにくくなるため、Phase 1 でも次の最小境界を内部 helper として置く。
WorkRecord backend(内部 helper):
observe() ← work_observe の backend 処理
record() ← work_record の backend 処理
publish() ← work_publish の backend 処理
Issue backend(内部 helper):
read() ← issue_read の backend 処理
comment() ← issue_comment の backend 処理
delete_comment() ← issue_delete_comment の backend 処理
update_title() ← issue_update_title の backend 処理
update_body() ← issue_update_body の backend 処理
create() ← issue_create の backend 処理
reopen() ← issue_reopen の backend 処理
抽象クラスは不要。関数またはモジュールとして境界を設けるだけでよい。Brain-facing API はこの境界の内側を呼ぶ形にする。
work_record() のメッセージ自動生成work_finish(auto=True) のような自動実行work_new_line / work_switch_line / work_merge_line)work_session_start(project_root) を追加し、project_root から backend / owner / repo を解決するwork_observe() を追加し、required_action を構造化して返すwork_record(message, issue_ids?) を追加するwork_start(issue_id?) で default issue を設定するissue_read / issue_comment / issue_delete_comment / issue_update_title / issue_update_body / issue_reopen を backend を隠した名前で追加するwork_publish() / work_finish() を追加するwork_observe() の返値を #69 方針に合わせて再設計する
diff_summary を通常返値から外すrecent_records を追加するactive_issue を追加するrequired_action と available_next を分離するwork_diff(path?, level?, record_id?) を追加するwork_history(n?, path?) を #69 の git log 代替として追加するwork_session_start → work_observe → 必要時のみ work_diff / work_history の導線にするgit_equivalents / work_vcs / pre-tool hook helper を追加するgit_* / gitea_* が出ていないwork_* / issue_* が出ているwork_session_start(project_root) でセッションが初期化できるwork_observe() が作業状態と required_action を構造化して返すwork_observe() が changed_files をファイル一覧として返し、diff 本文・stat・行数を通常返値に含めないwork_observe() が recent_records を返すwork_observe() が active_issue を {number, title} 形式で返すwork_observe() が required_action と available_next を分離して返すwork_observe() がセッション未初期化時に required_action: "work_session_start" を返すwork_diff(path?, level?, record_id?) が Brain-facing ツールとして呼び出せるwork_history(n?, path?) が Brain-facing ツールとして呼び出せるgit log が work_history() へ誘導されるwork_vcs(args) が Brain-facing ツールとして呼び出せるwork_vcs(args) が git_equivalents に登録済みの raw git 操作をブロックし、対応する Butler ツールへ誘導するgit コマンド全般をブロックし、git_equivalents 由来の誘導メッセージを返すsudo git ... / env git ... / GIT_PAGER=cat git log / pipe 後段の git など、前置修飾やシェル制御を伴う raw git もブロックするwork_record(message, issue_ids?) で現在の作業を記録できるwork_start(issue_id?) の default issue が work_record に反映されるissue_ids=[] により issue 紐付けなしの記録が可能issue_read(issue_id, last_n_comments?) により最後 N 件コメント取得ができるissue_delete_comment(issue_id, comment_id, reason?) により既存 issue コメントを削除できるissue_update_title(issue_id, title) により既存 issue のタイトルを更新できるissue_update_body(issue_id, body) により既存 issue の本文を更新できるissue_reopen(issue_id) が Brain-facing ツールとして呼び出せるwork_finish() が未記録・未公開・コメント促し・close 提案を順に評価して返す(自動実行しない)issue_close(issue_id) が Brain-facing ツールとして呼び出せるgit_* / gitea_* への直接呼び出しが Brain-facing 層に露出していないwork_session_start → work_observe の導線があるBrain 向け利用ガイド・公開 API 例では、git_* / gitea_* の直接呼び出し例を除去し、work_* / issue_* の抽象インターフェースに統一する。
internal / Worker 向けのリファレンスや adapter 実装仕様では、git_* / gitea_* の説明を引き続き許容する。
work_record() のメッセージ自動生成(diff 要約による候補生成)work_history の高度化
git_equivalents の正式な tool metadata 化
butler2-git-hook と check_git_command を提供する。Claude Code の .claude/settings.json には設定済み。ほかの client への配布や設定テンプレート化は Phase 2 候補とするwork_finish(auto=True) のような自動実行オプション(Phase 1 は提案のみ)work_new_line / work_switch_line / work_merge_line(branch 操作の抽象化)project_root などのセッションコンテキストは MCP connection 単位で保持する。実装前に FastMCP が connection-local state をサポートしているか確認が必要。
サポートしていない場合の代替案として、Brain には見せない「内部 session key」方式を用意する。
代替案(内部 session key):
- work_session_start が内部でセッションキーを生成・保存する
- Brain には session_id を返さない(Brain は意識しなくてよい)
- 各 work_* / issue_* ツールは FastMCP の Context や
接続/リクエスト単位で取得できる識別子でセッションを特定する
実装時の注意: 「接続元 IP + timestamp」のような不安定な識別子は使わない。FastMCP に接続単位またはリクエスト単位で取れる識別子(Context オブジェクト等)がないかを先に調べる。どちらの実装になるかは FastMCP の検証結果で決める。Brain-facing API は変わらない。