Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/specifications/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@
| [test-monitor-env-isolation.md](test-monitor-env-isolation.md) | テストの実行中だけ監視の上限を指す環境変数(接頭辞 `MONITOR_`)をリポジトリの根の共通の前提で外すこと、外す時点と戻す時点、根の設定ファイルで基準のディレクトリを固定すること |
| [ndf-token-waits-and-context-cut.md](ndf-token-waits-and-context-cut.md) | 待つ間の問い合わせ(前景の `sleep` の待ち・変わらないファイルの読み直し)と、文脈が上限を超えた conductor の工程の起動を止める hook(`token-guard.sh`)の判定・記録の形・入出力の契約、引き継ぎの 1 行、4 ランタイムの扱い。規約は `development-workflow` の `references/waiting.md` と `context-window.md` が正 |
| [ndf-worker-agent-and-skill-excerpts.md](ndf-worker-agent-and-skill-excerpts.md) | サブエージェントに Skill 本文を読ませない仕組み。記録のコマンド 1 行(`projects-sync.sh` が issue の本文と盤面へ同時に残す)の契約、worker のエージェント定義 `ndf:worker`(Skill と Agent のツールを外す)、抜粋の形と上限、仕事を分ける器と小さな作業の線引き。規約は `development-workflow` の `references/agent-layers.md` / `work-vessels.md` と `skills/EXCERPTS.md` が正 |
| [ndf-relay-segment-restart.md](ndf-relay-segment-restart.md) | 区間の切れ目で claude を起動し直す中継(`relay.py`)。`ndf-next` のブロックを印へ写す Stop hook、擬似端末の子としての起動と素通しの条件、静まり・上限・空回り・停止の印、作業ディレクトリと記録の形、alias を 1 度だけ足す `install`、中継の下で文脈量の拒否を止め続けること。利用者向けの案内は `development-workflow` の `references/relay.md`、次のコマンドの形は `context-window.md` が正 |

Skill の挙動仕様はここに置かない。Skill に関する詳細は対象 Skill の `SKILL.md` を参照する。
481 changes: 481 additions & 0 deletions docs/specifications/ndf-relay-segment-restart.md

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions docs/specifications/ndf-token-waits-and-context-cut.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Claude Code の PreToolUse hook(`plugins/ndf/scripts/token-guard.sh`)が、
| 途中の通知 | 背景の処理を残したまま応答を終えたサブエージェントについて、親へ届く 1 回目の通知。注記に「background work of its own still running」「may be interim」と出る |
| 報告の写し | worker が起動指示の `置き場所` のファイルの末尾へ書く `## 作業の報告` の節。最後の応答の報告と同じ中身 |
| 完了の目印 | worker が報告の写しを書き終えた後に作る空のファイル `<置き場所>.done` |
| 引き継ぎの 1 行 | 新しい会話の最初に打てば、その工程から再開できるコマンド 1 行。`/ndf:development-workflow #<課題> [#<課題> ...]` |
| 引き継ぎの 1 行 | 新しい会話の最初に打てば、その工程から再開できるコマンド 1 行。`/ndf:development-workflow #<課題> [#<課題> ...]`。情報文字列 `ndf-next` の囲みのコードブロック 1 つで出す |

## 構成要素

Expand Down Expand Up @@ -173,6 +173,10 @@ graph TB
利用者は同じ起動をもう一度行えば続けられる。毎回拒否すると同じ工程をやり直せず、会話ごとに
1 度にすると以後の切れ目で止まらない。案内だけを足す形(`additionalContext`)は、規定が読み
流された実測があるため採らない
- **中継の直接の子の conductor では 1 度の通しをしない。** `NDF_RELAY_DIR` があり、上限を超えていて、
`relay.py is-child` が終了コード 0 なら、上限を超えている限り同じ起動も止め続ける。人の居ない
前提で LLM が「続ける」と決めると、上限を超えたまま進むためである。中継の外では 1 度だけ通す
([ndf-relay-segment-restart.md](ndf-relay-segment-restart.md) の「文脈の上限で切る」)
- **文脈量を読めない(記録が無い・`usage` が無い)ときは通す**

**上限の既定は 200,000 で、`context-window.md` の「遅くとも 20 万」と `skill-stats.py` の
Expand Down Expand Up @@ -215,7 +219,10 @@ graph TB
Kiro では、それぞれの README が示す Skill の起動の書き方に読み替える。

**conductor は `context-window.md` の 4 つの切れ目と、文脈量の hook が拒否したときにこの 1 行を
出す。** 3 層では supervisor の持ち場の境がこの切れ目に当たるため、conductor が `## 持ち場の報告`
出す。** 出す形は情報文字列 `ndf-next` の囲みのコードブロック 1 つで、3 層(`/goal`)では中身の先頭を
`/goal ` にする(形の定義は `context-window.md` の「新しい会話で戻す」だけに置く)。中継の下では
中継がこのブロックを拾って次の会話を自動で起動し、中継が無ければ人が中身を貼り付ける
([ndf-relay-segment-restart.md](ndf-relay-segment-restart.md))。 3 層では supervisor の持ち場の境がこの切れ目に当たるため、conductor が `## 持ち場の報告`
を受け取った時点で出し、supervisor は出さない。報告が `結果: 関門` のときは、関門の承認と
取り込み(設計 Pull Request のマージなど)が済んだ後に出す。関門の前に会話を切らないためである。

Expand Down Expand Up @@ -348,7 +355,7 @@ worker の 2 回目の通知は、写しを読んだ後に届いても読み直
| --- | --- |
| sleep | 同じ条件の until ループを `run_in_background: true` で起動して完了通知を待つこと。出来事を 1 つずつ受けるなら `Monitor`。規約 `waiting.md`。`NDF_SLEEP_GUARD=0` |
| 連続 Read | 書き終わりを待つなら until ループを `run_in_background: true` で起動するか、背景の処理の完了通知を待つこと。`tasks/*.output` は読まない。規約 `waiting.md`。`NDF_READ_REPEAT_GUARD=0` |
| 文脈量 | 文脈量と上限、利用者へ示す引き継ぎの 1 行(3 層なら新しい会話の `/goal` に渡す)、続けるなら同じ起動をもう一度行うこと。規約 `context-window.md`。`NDF_CONTEXT_GUARD=0` と `NDF_CONTEXT_LIMIT` |
| 文脈量 | 文脈量と上限、次のコマンドを `ndf-next` のブロック 1 つで示すこと(中身は引き継ぎの 1 行、3 層なら先頭に `/goal `)、続けるなら同じ起動をもう一度行うこと。中継の直接の子では、止め続けること・動いている supervisor の報告を待ってから引継ぎ文書を更新してブロックを出すこと。規約 `context-window.md`。`NDF_CONTEXT_GUARD=0` と `NDF_CONTEXT_LIMIT` |

### 4 ランタイム

Expand All @@ -362,7 +369,8 @@ agy の CLI 側の消費を測った後に、登録するかを改めて決め

- **止める:** 環境変数で判定ごとに止める。hook そのものを外すなら `hooks/claude.json` の登録を
1 つ外す。データの移行は無い
- **続ける:** 文脈量の拒否の後、利用者がこのまま続けると決めたら、同じ起動をもう一度行う
- **続ける:** 文脈量の拒否の後、利用者がこのまま続けると決めたら、同じ起動をもう一度行う。
中継の下ではこの手は無く、会話を切る
- **性能:** 1 回の実行は、50 MB の記録でも競合しないとき 1 秒以内、ロックを待つときは 2 秒以内に
終わる。記録は末尾 200 行だけを読み、Bash と Read の判定は記録を読まない。登録の `timeout` は
5 秒で、`continueOnError: true` を付ける
Expand All @@ -384,6 +392,9 @@ agy の CLI 側の消費を測った後に、登録するかを改めて決め
- サブエージェントの中の起動・工程でない Skill・作業の種類の Agent を通すこと
- 拒否の後の同じ起動を 1 度だけ通し(間に Bash と Read が挟まっても)、別の起動を再び拒否すること。
同じ起動の 2 回目を並列に起動しても通るのは 1 本だけであること
- 中継の直接の子の conductor では同じ起動が 2 回続けて止まり、理由の欄が `ndf-next` と supervisor の
報告の待ちを含むこと。直接の子でない・中継が動いていないときは 1 度だけ通ること。中継の外でも理由の
欄が `ndf-next` のブロックを求めること
- 壊れた入力・`jq` の無い `PATH`・書けない控えの場所・取れないロック・読めない記録で、出力なし・
終了コード 0 で通すこと。`guards/` の親が `wf_state_dir` の親と一致すること
- 環境変数で判定ごとに止まり、上限が変わること
Expand All @@ -408,6 +419,7 @@ agy の CLI 側の消費を測った後に、登録するかを改めて決め

- [#829](https://github.com/devbasex/ai-plugins/issues/829) / [#830](https://github.com/devbasex/ai-plugins/issues/830)(親は [#827](https://github.com/devbasex/ai-plugins/issues/827))
- [#901](https://github.com/devbasex/ai-plugins/issues/901) — supervisor が worker の途中の通知で止まる(実装は [PR #910](https://github.com/devbasex/ai-plugins/pull/910))
- [#895](https://github.com/devbasex/ai-plugins/issues/895) — 引き継ぎの 1 行を `ndf-next` のブロックにし、中継の下では文脈量の拒否を止め続ける([ndf-relay-segment-restart.md](ndf-relay-segment-restart.md))
- [#731](https://github.com/devbasex/ai-plugins/issues/731) — 待ちの道具(`bg-wait.sh`)を共通層へ移す
- [ndf-context-window-metrics.md](ndf-context-window-metrics.md) — 会話の記録から文脈量を測る部品
- [ndf-agent-layers-unattended-run.md](ndf-agent-layers-unattended-run.md) — 3 層の運転
1 change: 1 addition & 0 deletions issues/old/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
| [#829](https://github.com/devbasex/ai-plugins/issues/829) / [#830](https://github.com/devbasex/ai-plugins/issues/830) | 待つ間の問い合わせを止め、conductor の会話を工程の切れ目で切る(マイルストーン 26「17 トークン消費の削減」のまとまり 1)。確定仕様は [ndf-token-waits-and-context-cut.md](../../docs/specifications/ndf-token-waits-and-context-cut.md) | [milestone-26-token-waits/](milestone-26-token-waits/issue-829-830-requirements.md)(要求・設計・決定・計画の 4 本) |
| [#828](https://github.com/devbasex/ai-plugins/issues/828) / [#680](https://github.com/devbasex/ai-plugins/issues/680) | サブエージェントに Skill 本文を丸ごと読ませず、仕事を分ける器を比べて選ぶ(マイルストーン 26「17 トークン消費の削減」)。確定仕様は [ndf-worker-agent-and-skill-excerpts.md](../../docs/specifications/ndf-worker-agent-and-skill-excerpts.md) | [milestone-26-worker-agent/](milestone-26-worker-agent/issue-828-680-requirements.md)(要求・設計・決定・計画の 4 本) |
| [#892](https://github.com/devbasex/ai-plugins/issues/892) / [#901](https://github.com/devbasex/ai-plugins/issues/901) | cross-review の母集合にホストを入れ、supervisor が worker の途中の通知で止まらないようにする(マイルストーン 26「17 トークン消費の削減」)。確定仕様は [cross-review-participants-and-seats.md](../../docs/specifications/cross-review-participants-and-seats.md) / [ndf-token-waits-and-context-cut.md](../../docs/specifications/ndf-token-waits-and-context-cut.md) | [milestone-26-review-pool-and-interim-wait/](milestone-26-review-pool-and-interim-wait/issue-892-901-requirements.md)(要求・設計・決定・計画の 4 本) |
| [#895](https://github.com/devbasex/ai-plugins/issues/895) | 区間の切れ目の再起動と次のコマンドの入力を前景の中継で自動にする(マイルストーン 26「17 トークン消費の削減」)。確定仕様は [ndf-relay-segment-restart.md](../../docs/specifications/ndf-relay-segment-restart.md) / [ndf-token-waits-and-context-cut.md](../../docs/specifications/ndf-token-waits-and-context-cut.md) | [milestone-26-relay-restart/](milestone-26-relay-restart/issue-895-requirements.md)(要求・設計・決定・計画の 4 本) |

## 計画と調査資料

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,49 @@ SessionStart hook は起動した版のパスで動くので、`claude plugin up

Stop hook で上限を見て応答を続けさせる形は採らない。関門を `AskUserQuestion` でなく文で尋ねて止まった
応答まで、承認の前に切らせることになる。

## 実装で決めたこと(2026-09-23、Claude Code 2.1.280・`--model haiku` で実測)

設計の「未確認のまま残ること」のうち、実装で決めるとした 3 件を実測で決めた。

### 決定 21: 次の区間の中身は `/goal` を含めたまま位置引数 1 つで渡す

擬似端末の子として `claude --model haiku "/goal <条件>"` を起動すると、目標が設定されて応答が
始まった。1 行目が `/goal ...` の複数行の位置引数でも、改行ごと 1 つの条件として設定された。
そのため設計どおり `<本物の claude> <印の中身>` で起動する。`/goal` を 2 つ目の入力として子の端末へ
書き込む代わりの形は作らない。

### 決定 22: 背景の処理の判定は `background_tasks` の `status: running` だけで行う

背景で起動したサブエージェントは、主会話の Stop hook の `background_tasks` に
`{"id", "type": "subagent", "status": "running", "description", "agent_type"}` の形で載った。
サブエージェントが終わると、人の入力なしに Stop がもう一度起き、`background_tasks` は空の配列に
戻った。背景の Bash(`type: shell`)と同じ判定で足りるため、`type` を問わず `running` の有無だけを
見る。会話の記録から背景の Agent の未完了を数える代わりの形は作らない。

### 決定 23: 目標の有無と判定は、記録の `goal_status` の attachment の行で読む

`/goal` の目標の設定と判定は、会話の記録の `type: "attachment"` の行の
`attachment.type: "goal_status"` に書かれた。設定は `sentinel: true` と `met: false`、判定は
`met`(未達で止めを拒んだら `false` と `reason`、達成なら `true` と `reason`・`iterations` など)を持つ。
`stop_hook_summary` の `preventedContinuation` は未達でも `false` のままで、拒否の検出には使えない。

中継は、最後の `sentinel` の行より後に目標が続いていて(`met: true` の判定が無い)、印の
`written_at` より後の判定の行(`timestamp`)が無ければ、`/exit` を入力せずに待つ。`met: true` の
判定の後は目標が終わったものとして待たない。

### 決定 24: 文脈量の hook は `relay.py is-child` で中継の直接の子かを見る

文脈量の hook(`token-guard.sh`)は bash で書かれていて、`mark` の判定 4 と同じ親のたどりを持たない。
同じ判定を bash に写すと、2 つの実装が食い違う。そこで `relay.py` に内部の副命令 `is-child`
(中継が動いていて、hook を呼んだ claude が `child.pid` と一致すれば終了コード 0)を置き、hook は
上限を超えたときだけそれを呼ぶ。利用者が打つ副命令ではないため、`relay.md` には載せない。

### 決定 25: 待ちの秒数は環境変数で短くできるようにし、試験で使う

静まり(`NDF_RELAY_QUIET`)のほかに、印の確認の間隔(`NDF_RELAY_POLL`、既定 2)・`/exit` と改行の
間(`NDF_RELAY_EXIT_GAP`、既定 1)・`/exit` の後の待ち(`NDF_RELAY_EXIT_WAIT`、既定 30)・SIGTERM の
後の待ち(`NDF_RELAY_TERM_WAIT`、既定 10)・空回りの秒数(`NDF_RELAY_SPIN`、既定 120)・
`plugin list` と `plugin update` の打ち切り(`NDF_RELAY_LIST_TIMEOUT` / `NDF_RELAY_UPDATE_TIMEOUT`)を
環境変数で受ける。既定の値は設計のとおりで、試験では 1 秒未満へ縮めて擬似端末の上の単体テストを
数十秒で終える。
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ stateDiagram-v2

## 決定の記録

[issue-895-design-decisions.md](issue-895-design-decisions.md) にある(決定 20 件)。
[issue-895-design-decisions.md](issue-895-design-decisions.md) にある(設計の決定 20 件と、実装で決めた 5 件)。

## テスト設計

Expand Down
Loading
Loading