lathe-cli 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Claude Code を agent backend にした target/meta 二層 harness を、git bra
7
7
  | role | やること | 接点 |
8
8
  |---|---|---|
9
9
  | 開発者 | feature branch で vibe coding、PR を develop に出す | git / gh |
10
- | target agent | PR を polish 実装に置き換える、commit して PR を更新 | plan HTML 出力、approval で停止 |
10
+ | target agent | PR を polish 実装に置き換える、commit して PR を更新 | plan HTML 出力、workflow gate / escalation |
11
11
  | overseer | plan HTML レビュー、PR レビュー、merge | claude UI + GitHub PR |
12
12
  | meta operator | runs/ を読み harness/ を改善、PR を develop に出す | meta agent と対話 |
13
13
 
@@ -57,9 +57,15 @@ lathe feature <name> [--from main|develop]
57
57
  # features/<name>/ worktree + feature/<name> 枝
58
58
  lathe feature-done <name> # 安全に worktree + branch + remote を一掃
59
59
  lathe ls # worktree / branch / 最近の runs / improvements
60
- lathe process <pr#> # PR pickup → tasks/<pr#>/ worktree → target 起動
61
- lathe target [args...] # cd develop/target && claude args
62
- lathe meta [args...] # cd meta/meta && claude args
60
+ lathe plan pr <pr#> # PR pickup → tasks/<pr#>/ worktree → target が計画だけ作る
61
+ lathe watch [--once] # develop 宛ての新規 PR を監視し、自動で lathe plan --print pr
62
+ lathe process <pr#> # PR pickup/reuse 計画承認待ちなしで target が実装まで進める
63
+ lathe process --manual-prompt <pr#>
64
+ # 旧式 Claude Code 用。prompt を手貼りする fallback
65
+ lathe process --no-launch <pr#>
66
+ # tasks/<pr#>/ 準備だけ行い、target は起動しない
67
+ lathe target [args...] # cd develop && claude args
68
+ lathe meta [args...] # cd meta && claude args
63
69
  lathe sync # develop/bin/sync.sh 手動実行
64
70
  lathe help # ヘルプ
65
71
  ```
@@ -77,6 +83,17 @@ claude # Lathe 操作の質問はここで聞ける
77
83
 
78
84
  helper は **Lathe 操作のアシスタント**で、target/meta のような実装エージェントではありません。`lathe feature` や PR 処理のフローに迷ったら相談する相手として常駐します。
79
85
 
86
+ ## develop PR の自動計画
87
+
88
+ ローカルで PR を監視し、develop 宛ての新規 PR を見つけたら計画だけ自動作成できます。
89
+
90
+ ```sh
91
+ cd myapp
92
+ lathe watch --interval 60
93
+ ```
94
+
95
+ watch は `lathe plan --print pr <pr#>` を呼び、`tasks/<pr#>/.lathe/task.json`、`.lathe/brief.md`、`.lathe/invocation.json` を target harness に渡します。`task.json` は source / branch / worktree などの transport 事実、`invocation.json` は planning-only 制約などの runtime dependency injection です。workflow・human gate・delivery は target harness 側で選びます。
96
+
80
97
  ## 標準ワークフロー
81
98
 
82
99
  ```sh
@@ -90,9 +107,12 @@ git push -u origin feature/X
90
107
  gh pr create --base develop --title "..." --body "..."
91
108
 
92
109
  # overseer
110
+ lathe plan pr <pr#> # 任意: 計画だけ先に作る。watch なら自動
93
111
  lathe process <pr#>
94
- # claude UI で「Read .lathe-task.md from the added directory and process it」を貼り付け
95
- # orchestrator plan 承認 → coder/reviewer dispatch commit/push → PR 更新
112
+ # tasks/<pr#>/ + task/pr-<pr#> が作られる(plan 済みなら reuse)
113
+ # tasks/<pr#>/.lathe/task.json + .lathe/brief.md + .lathe/invocation.json Lathe が作る入力 envelope
114
+ # claude TUI が初回 prompt 入りで起動。process 実行自体が計画承認 gate になる
115
+ # orchestrator が plan(既存があればreuse)→ coder/reviewer dispatch → commit → PR head へ push
96
116
  gh pr merge <pr#> # develop に merge
97
117
 
98
118
  # meta operator(任意のタイミング)
@@ -118,7 +138,7 @@ git push origin main
118
138
  - **branch / worktree でロール分離**:各 agent / role が物理的に別ディレクトリで動くので、CLAUDE.md / settings.json / hooks が混ざらない
119
139
  - **harness/ は agent spec の単一の正**:target も meta も自分の設定は `harness/`(meta 用は `harness/meta/`)から sync.sh で worktree root の runtime ファイルに展開される。Claude Code 本体の `.claude/` sensitive-file guard を agent tool で突破できないため、harness/ を編集(普通の dir、guard なし)→ shell sync.sh で `.claude/` 上書き、という迂回経路
120
140
  - **runs/ は develop で auto-commit**:target session の Stop hook が `git commit` するので、meta は `git merge develop` で読める。symlink や中央 store 不要
121
- - **post-merge hook が auto-sync**:meta の harness 改善が develop に merge された瞬間に target/.claude/ が再生成される
141
+ - **post-merge hook が auto-sync**:meta の harness 改善が develop に merge された瞬間に develop/.claude/ が再生成される
122
142
 
123
143
  ## 動作確認済み(v1)
124
144
 
@@ -126,13 +146,14 @@ git push origin main
126
146
  - `lathe init` で bare repo + 3 worktree + post-merge hook 設置
127
147
  - target session 実行、runs auto-commit on develop
128
148
  - meta worktree が `git merge develop` で runs/ 読込
129
- - meta が harness/CLAUDE.md 編集 → develop merge → post-merge hook → sync 自動 → target/CLAUDE.md 反映
149
+ - meta が harness/CLAUDE.md 編集 → develop merge → post-merge hook → sync 自動 → develop/CLAUDE.md 反映
130
150
  - `lathe target` / `lathe meta` / `lathe sync` がどの worktree から実行しても正しい worktree を見つける
131
151
 
132
152
  ## 既知の v1 制限
133
153
 
134
154
  - meta → develop merge で meta/ + improvements/ overlay も develop に持ち込まれる(cherry-pick / 別 PR 機構で v2 解決)
135
- - `lathe process` の prompt 渡しは手動ペースト(claude TUI piped 初期 prompt を確実に取らないため)
155
+ - `lathe process` / `lathe plan` は Claude Code の prompt 引数で初回 prompt を自動投入する。古い Claude Code で動かない場合は `--manual-prompt` を使う
156
+ - `lathe process` は workflow を固定せず、計画承認 grant と PR delivery adapter を `.lathe/invocation.json` で注入する。採用 workflow がそれを安全に消費できる場合は計画承認待ちを挟まず実装まで進み、仕様不明、high-risk 変更、検証不能などは human escalation として停止する
136
157
  - post-merge hook は local merge のみ発火、GitHub UI で merge した時は `git pull` 後に `lathe sync` 手動
137
158
  - v1 は新 project 専用、既存 repo の自動 migration なし
138
159
  - runs/ auto-commit は local commit のみ(remote push しない)。multi-machine 構成では別途 push 設計が必要
@@ -140,4 +161,4 @@ git push origin main
140
161
  ## 設計詳細
141
162
 
142
163
  target orchestrator の指示書: `template/develop/harness/CLAUDE.md`
143
- meta agent の指示書: `template/meta-overlay/meta/CLAUDE.md`
164
+ meta agent の指示書: `template/develop/harness/meta/CLAUDE.md`
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env bash
2
+ # Shared task-intake helpers for Lathe subcommands. Sourced, not executed.
3
+
4
+ lathe_require_gh() {
5
+ command -v gh >/dev/null 2>&1 || {
6
+ echo "lathe: gh (GitHub CLI) is required" >&2
7
+ exit 1
8
+ }
9
+ }
10
+
11
+ lathe_write_exclude_once() {
12
+ local file="$1"
13
+ local pattern="$2"
14
+ touch "$file"
15
+ if ! grep -qxF "$pattern" "$file" 2>/dev/null; then
16
+ printf '%s\n' "$pattern" >> "$file"
17
+ fi
18
+ }
19
+
20
+ # Prepare a PR-backed task worktree and write Lathe's local transport envelope.
21
+ #
22
+ # Sets globals:
23
+ # PROJECT_ROOT DEVELOP_WT GIT_DIR PR_NUMBER PR_TITLE PR_BODY PR_URL
24
+ # BASE_REF HEAD_REF FETCH_REF TASK_BRANCH TASK_WT LATHE_TASK_DIR
25
+ lathe_prepare_pr_task() {
26
+ local requested_pr="${1#\#}"
27
+ local current_branch exclude_file
28
+
29
+ lathe_require_gh
30
+
31
+ PROJECT_ROOT="$(lathe_project_root)" || {
32
+ echo "lathe: not inside a Lathe project" >&2
33
+ exit 1
34
+ }
35
+ DEVELOP_WT="$(lathe_wt_for_branch develop)" || {
36
+ echo "lathe: develop worktree not found" >&2
37
+ exit 1
38
+ }
39
+ GIT_DIR="$PROJECT_ROOT/.git"
40
+
41
+ echo "==> Fetching PR #$requested_pr metadata ..."
42
+ PR_JSON="$(gh pr view "$requested_pr" --json number,title,body,url,baseRefName,headRefName)"
43
+ PR_NUMBER="$(printf '%s' "$PR_JSON" | jq -r '.number // empty')"
44
+ [ -n "$PR_NUMBER" ] || PR_NUMBER="$requested_pr"
45
+ PR_TITLE="$(printf '%s' "$PR_JSON" | jq -r '.title // ""')"
46
+ PR_BODY="$(printf '%s' "$PR_JSON" | jq -r '.body // ""')"
47
+ PR_URL="$(printf '%s' "$PR_JSON" | jq -r '.url // ""')"
48
+ BASE_REF="$(printf '%s' "$PR_JSON" | jq -r '.baseRefName // "develop"')"
49
+ HEAD_REF="$(printf '%s' "$PR_JSON" | jq -r '.headRefName // empty')"
50
+ if [ -z "$HEAD_REF" ]; then
51
+ echo "lathe: PR #$requested_pr has no headRefName" >&2
52
+ exit 1
53
+ fi
54
+
55
+ FETCH_REF="refs/remotes/origin/lathe/pr-$PR_NUMBER"
56
+ TASK_BRANCH="task/pr-$PR_NUMBER"
57
+ TASK_WT="$PROJECT_ROOT/tasks/$PR_NUMBER"
58
+ LATHE_TASK_DIR="$TASK_WT/.lathe"
59
+
60
+ if ! git --git-dir="$GIT_DIR" fetch origin "+refs/pull/$PR_NUMBER/head:$FETCH_REF" >/dev/null 2>&1; then
61
+ git --git-dir="$GIT_DIR" fetch origin "+$HEAD_REF:$FETCH_REF" >/dev/null 2>&1 || {
62
+ echo "lathe: failed to fetch PR #$PR_NUMBER from origin" >&2
63
+ exit 1
64
+ }
65
+ fi
66
+
67
+ mkdir -p "$PROJECT_ROOT/tasks"
68
+ if [ -e "$TASK_WT" ]; then
69
+ if ! git -C "$TASK_WT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
70
+ echo "lathe: $TASK_WT exists but is not a git worktree" >&2
71
+ exit 1
72
+ fi
73
+ current_branch="$(git -C "$TASK_WT" symbolic-ref --short HEAD 2>/dev/null || true)"
74
+ if [ "$current_branch" != "$TASK_BRANCH" ]; then
75
+ echo "lathe: $TASK_WT is on '$current_branch', expected '$TASK_BRANCH'" >&2
76
+ exit 1
77
+ fi
78
+ echo "==> Reusing task worktree at $TASK_WT (branch: $TASK_BRANCH)"
79
+ if ! git -C "$TASK_WT" diff --quiet || ! git -C "$TASK_WT" diff --cached --quiet; then
80
+ echo "lathe: $TASK_WT has uncommitted changes; refusing to update from PR head" >&2
81
+ exit 1
82
+ fi
83
+ if git -C "$TASK_WT" merge-base --is-ancestor HEAD "$FETCH_REF"; then
84
+ git -C "$TASK_WT" merge --ff-only --quiet "$FETCH_REF"
85
+ elif git -C "$TASK_WT" merge-base --is-ancestor "$FETCH_REF" HEAD; then
86
+ :
87
+ else
88
+ echo "lathe: $TASK_BRANCH has diverged from PR #$PR_NUMBER head; resolve manually before continuing" >&2
89
+ exit 1
90
+ fi
91
+ else
92
+ if git --git-dir="$GIT_DIR" rev-parse --verify "$TASK_BRANCH" >/dev/null 2>&1; then
93
+ echo "==> Creating task worktree at $TASK_WT (branch: $TASK_BRANCH)..."
94
+ git --git-dir="$GIT_DIR" worktree add --quiet "$TASK_WT" "$TASK_BRANCH"
95
+ else
96
+ echo "==> Creating task worktree at $TASK_WT (branch: $TASK_BRANCH from $HEAD_REF)..."
97
+ git --git-dir="$GIT_DIR" worktree add --quiet -b "$TASK_BRANCH" "$TASK_WT" "$FETCH_REF"
98
+ fi
99
+ fi
100
+
101
+ mkdir -p "$LATHE_TASK_DIR"
102
+ jq -n \
103
+ --arg source_type "pr" \
104
+ --arg source_id "$PR_NUMBER" \
105
+ --arg title "$PR_TITLE" \
106
+ --arg url "$PR_URL" \
107
+ --arg base_branch "$BASE_REF" \
108
+ --arg head_branch "$HEAD_REF" \
109
+ --arg task_branch "$TASK_BRANCH" \
110
+ --arg task_worktree "$TASK_WT" \
111
+ --arg brief ".lathe/brief.md" \
112
+ '{
113
+ schema_version: 1,
114
+ source: {
115
+ type: $source_type,
116
+ id: $source_id,
117
+ title: $title,
118
+ url: $url,
119
+ base_branch: $base_branch,
120
+ head_branch: $head_branch
121
+ },
122
+ worktree: {
123
+ path: $task_worktree,
124
+ branch: $task_branch
125
+ },
126
+ artifacts: {
127
+ brief: $brief
128
+ }
129
+ }' > "$LATHE_TASK_DIR/task.json"
130
+
131
+ cat > "$LATHE_TASK_DIR/brief.md" <<EOF
132
+ # PR #$PR_NUMBER: $PR_TITLE
133
+
134
+ Source: $PR_URL
135
+ Base branch: $BASE_REF
136
+ Head branch: $HEAD_REF
137
+ Task branch: $TASK_BRANCH
138
+ Task worktree: $TASK_WT
139
+
140
+ ## PR body
141
+
142
+ $PR_BODY
143
+ EOF
144
+
145
+ exclude_file="$(git -C "$TASK_WT" rev-parse --git-path info/exclude)"
146
+ mkdir -p "$(dirname "$exclude_file")"
147
+ touch "$exclude_file"
148
+ if ! grep -qxF "# Lathe local task metadata" "$exclude_file" 2>/dev/null; then
149
+ {
150
+ echo ""
151
+ echo "# Lathe local task metadata"
152
+ } >> "$exclude_file"
153
+ fi
154
+ lathe_write_exclude_once "$exclude_file" ".lathe/"
155
+ lathe_write_exclude_once "$exclude_file" ".lathe-task.md"
156
+ }
157
+
158
+ lathe_write_invocation() {
159
+ local mode="$1"
160
+ mkdir -p "$LATHE_TASK_DIR"
161
+
162
+ case "$mode" in
163
+ process)
164
+ jq -n \
165
+ --arg command "lathe process" \
166
+ --arg intent "execute_task" \
167
+ --arg plan_approval "granted_by_invocation" \
168
+ --arg delivery "update_pr_head" \
169
+ '{
170
+ schema_version: 1,
171
+ invocation: {
172
+ command: $command,
173
+ intent: $intent
174
+ },
175
+ injected_dependencies: {
176
+ plan_approval: {
177
+ grant: $plan_approval,
178
+ approver: "lathe process invocation",
179
+ meaning: "The overseer explicitly requested execution; do not stop solely for human plan approval if the selected workflow can consume this grant."
180
+ },
181
+ delivery: {
182
+ adapter: $delivery,
183
+ command_template: "git push origin HEAD:<source.head_branch>"
184
+ }
185
+ },
186
+ constraints: {
187
+ workflow_selection: "harness_owned",
188
+ human_escalation: "required_when_selected_workflow_cannot_safely_consume_injected_dependencies"
189
+ }
190
+ }' > "$LATHE_TASK_DIR/invocation.json"
191
+ ;;
192
+ plan)
193
+ jq -n \
194
+ --arg command "lathe plan" \
195
+ --arg intent "plan_only" \
196
+ '{
197
+ schema_version: 1,
198
+ invocation: {
199
+ command: $command,
200
+ intent: $intent
201
+ },
202
+ injected_dependencies: {},
203
+ constraints: {
204
+ workflow_selection: "harness_owned",
205
+ stop_at_contract_boundary: true,
206
+ dispatch_subagents: false,
207
+ edit_task_worktree: false,
208
+ commit_or_push: false
209
+ }
210
+ }' > "$LATHE_TASK_DIR/invocation.json"
211
+ ;;
212
+ *)
213
+ echo "lathe: unknown invocation mode '$mode'" >&2
214
+ exit 1
215
+ ;;
216
+ esac
217
+ }
218
+
219
+ lathe_task_process_prompt() {
220
+ printf 'Read .lathe/task.json, .lathe/brief.md, and .lathe/invocation.json from the added task worktree (%s), then process the task according to the target harness protocol. Treat task.json as transport facts only. Treat invocation.json as injected runtime dependencies, not as workflow selection. Select or construct the workflow in the harness. If an existing plan for this task exists, use it if it still matches task.json, brief, invocation dependencies, and the current diff; otherwise create a new plan. The process invocation injects a plan-approval grant and PR delivery adapter; consume those dependencies if the selected workflow supports them. Escalate to the human instead of implementing if the selected workflow cannot safely consume the injected dependencies.' "$TASK_WT"
221
+ }
222
+
223
+ lathe_task_plan_prompt() {
224
+ printf 'Read .lathe/task.json, .lathe/brief.md, and .lathe/invocation.json from the added task worktree (%s), then perform planning only according to the target harness protocol. Treat task.json as transport facts only and invocation.json as injected runtime dependencies/constraints. Select or construct the workflow in the harness. Create or update plans/<run_id>.html and stop at the contract/approval boundary. Do not dispatch coder/reviewer, do not edit the task worktree, and do not commit or push.' "$TASK_WT"
225
+ }
package/bin/check-deps.sh CHANGED
@@ -9,7 +9,7 @@ for cmd in git jq claude bash; do
9
9
  command -v "$cmd" >/dev/null 2>&1 || missing_required+=("$cmd")
10
10
  done
11
11
 
12
- command -v gh >/dev/null 2>&1 || missing_optional+=("gh (only needed for 'lathe process')")
12
+ command -v gh >/dev/null 2>&1 || missing_optional+=("gh (needed for 'lathe process', 'lathe plan pr', and 'lathe watch')")
13
13
 
14
14
  if [ "${#missing_required[@]}" -gt 0 ]; then
15
15
  echo ""
package/bin/lathe CHANGED
@@ -40,8 +40,13 @@ Daily ops:
40
40
  feature-done <name>
41
41
  Tear down a feature: worktree + branch (+ remote if any).
42
42
  Refuses if uncommitted/unpushed unless --force.
43
- process <pr#> Pick up a GitHub PR for target processing
44
- (creates ./tasks/<pr#>/ worktree, launches target)
43
+ process [--manual-prompt|--no-launch] <pr#>
44
+ Pick up a GitHub PR for target processing
45
+ (creates ./tasks/<pr#>/ worktree, launches target with prompt)
46
+ plan [--print|--manual-prompt|--no-launch] pr <pr#>
47
+ Prepare a task worktree and ask target to write a plan only
48
+ watch [--once] [--interval <seconds>] [--base develop]
49
+ Poll open PRs and run 'lathe plan --print pr <pr#>' for new ones
45
50
  ls List worktrees, branches, recent runs/improvements
46
51
 
47
52
  Agent launchers:
package/bin/lathe-init CHANGED
@@ -165,6 +165,7 @@ if [ -n "$HELPER_KIND" ]; then
165
165
  fi
166
166
  cat <<EOF
167
167
  lathe feature <name> # start a new feature in features/<name>/
168
+ lathe plan pr <pr#> # have target write a plan for a PR
168
169
  lathe process <pr#> # have target process a PR
169
170
  lathe ls # list worktrees, branches, recent runs
170
171
  EOF
package/bin/lathe-plan ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env bash
2
+ # lathe plan pr <pr#> — prepare a task and run target planning only.
3
+
4
+ set -euo pipefail
5
+ : "${LATHE_HOME:?must be set by lathe dispatcher}"
6
+ source "$LATHE_HOME/bin/_lathe-lib.sh"
7
+ source "$LATHE_HOME/bin/_lathe-task.sh"
8
+
9
+ usage() {
10
+ cat >&2 <<EOF
11
+ Usage: lathe plan [--print|--manual-prompt|--no-launch] pr <pr#>
12
+
13
+ Options:
14
+ --print Run Claude non-interactively with --print and a plan-only prompt.
15
+ Used by lathe watch.
16
+ --manual-prompt Launch Claude without submitting the initial prompt.
17
+ The prompt is printed for manual paste.
18
+ --no-launch Prepare tasks/<pr#>/ and print the Claude command, but do not run it.
19
+ EOF
20
+ }
21
+
22
+ MODE="auto"
23
+ SOURCE=""
24
+ ID=""
25
+ while [ $# -gt 0 ]; do
26
+ case "$1" in
27
+ --print|--auto-plan)
28
+ MODE="print"; shift ;;
29
+ --manual-prompt)
30
+ MODE="manual"; shift ;;
31
+ --no-launch|--prepare-only)
32
+ MODE="no-launch"; shift ;;
33
+ -h|--help)
34
+ usage; exit 0 ;;
35
+ pr)
36
+ SOURCE="pr"; shift
37
+ if [ $# -gt 0 ] && [ -z "$ID" ]; then
38
+ ID="$1"; shift
39
+ fi
40
+ ;;
41
+ -*)
42
+ echo "lathe plan: unknown flag $1" >&2
43
+ usage
44
+ exit 1 ;;
45
+ *)
46
+ if [ -z "$SOURCE" ]; then
47
+ SOURCE="pr"
48
+ fi
49
+ if [ -z "$ID" ]; then
50
+ ID="$1"
51
+ else
52
+ echo "lathe plan: extra argument $1" >&2
53
+ usage
54
+ exit 1
55
+ fi
56
+ shift ;;
57
+ esac
58
+ done
59
+
60
+ if [ "$SOURCE" != "pr" ] || [ -z "$ID" ]; then
61
+ usage
62
+ exit 1
63
+ fi
64
+
65
+ lathe_prepare_pr_task "$ID"
66
+ lathe_write_invocation plan
67
+ INITIAL_PROMPT="$(lathe_task_plan_prompt)"
68
+
69
+ cat <<EOF
70
+
71
+ Task worktree ready for planning.
72
+ Path: $TASK_WT
73
+ Local branch: $TASK_BRANCH
74
+ PR head branch: $HEAD_REF
75
+ Descriptor: $LATHE_TASK_DIR/task.json
76
+ Brief: $LATHE_TASK_DIR/brief.md
77
+ Invocation: $LATHE_TASK_DIR/invocation.json
78
+ Prompt: $INITIAL_PROMPT
79
+ EOF
80
+
81
+ case "$MODE" in
82
+ no-launch)
83
+ cat <<EOF
84
+
85
+ Run target planning when ready:
86
+ cd "$DEVELOP_WT"
87
+ claude --add-dir "$TASK_WT" -- "$INITIAL_PROMPT"
88
+ EOF
89
+ ;;
90
+
91
+ manual)
92
+ cat <<EOF
93
+
94
+ Manual prompt mode. Paste this into the Claude TUI:
95
+
96
+ $INITIAL_PROMPT
97
+
98
+ Launching target for planning...
99
+ EOF
100
+ cd "$DEVELOP_WT"
101
+ exec claude --add-dir "$TASK_WT"
102
+ ;;
103
+
104
+ print)
105
+ echo ""
106
+ echo "Running target planning non-interactively..."
107
+ cd "$DEVELOP_WT"
108
+ exec claude --print --permission-mode auto \
109
+ --allowedTools Read Write Edit Glob Grep "Bash(date *)" "Bash(git status*)" "Bash(git diff*)" "Bash(git ls-files*)" \
110
+ --add-dir "$TASK_WT" -- "$INITIAL_PROMPT"
111
+ ;;
112
+
113
+ auto)
114
+ echo ""
115
+ echo "Launching target for planning with the initial prompt already submitted..."
116
+ cd "$DEVELOP_WT"
117
+ exec claude --add-dir "$TASK_WT" -- "$INITIAL_PROMPT"
118
+ ;;
119
+ esac
package/bin/lathe-process CHANGED
@@ -1,88 +1,170 @@
1
1
  #!/usr/bin/env bash
2
- # lathe process <pr#> — pick up a PR for target processing.
2
+ # lathe process [--manual-prompt|--no-launch] <pr#> — pick up a PR for target processing.
3
3
  # 1. fetch PR head + body via gh
4
- # 2. add a worktree of the PR's branch under <project>/tasks/<pr#>
5
- # 3. write the task brief into that worktree as .lathe-task.md
6
- # 4. cd into develop worktree's target/, launch claude with --add-dir <task-wt>
4
+ # 2. add a task/pr-<pr#> worktree from the PR head under <project>/tasks/<pr#>
5
+ # 3. write the Lathe transport envelope into .lathe/task.json + .lathe/brief.md
6
+ # 4. cd into develop worktree, launch claude with --add-dir <task-wt>
7
+ # and submit the initial prompt as a CLI argument
7
8
  #
8
- # Interactive launch: the user pastes a "read .lathe-task.md and process it"
9
- # prompt into the resulting claude TUI. (Auto-injection of the initial prompt
10
- # is unreliable in claude's interactive mode.)
9
+ # If a user's Claude Code build does not accept an initial prompt argument,
10
+ # --manual-prompt preserves the old paste-it-yourself flow.
11
11
 
12
12
  set -euo pipefail
13
13
  : "${LATHE_HOME:?must be set by lathe dispatcher}"
14
14
  source "$LATHE_HOME/bin/_lathe-lib.sh"
15
+ source "$LATHE_HOME/bin/_lathe-task.sh"
15
16
 
16
- PR="${1:-}"
17
- if [ -z "$PR" ]; then
18
- echo "Usage: lathe process <pr#>" >&2
19
- exit 1
20
- fi
21
-
22
- command -v gh >/dev/null 2>&1 || {
23
- echo "lathe process: gh (GitHub CLI) is required" >&2
24
- exit 1
25
- }
17
+ usage() {
18
+ cat >&2 <<EOF
19
+ Usage: lathe process [--manual-prompt|--no-launch] <pr#>
26
20
 
27
- PROJECT_ROOT="$(lathe_project_root)" || {
28
- echo "lathe process: not inside a Lathe project" >&2
29
- exit 1
30
- }
31
- DEVELOP_WT="$(lathe_wt_for_branch develop)" || {
32
- echo "lathe process: develop worktree not found" >&2
33
- exit 1
21
+ Options:
22
+ --manual-prompt Launch Claude without submitting the initial prompt.
23
+ The prompt is printed and copied to the clipboard when possible.
24
+ --no-launch Prepare tasks/<pr#>/ and print the Claude command, but do not run it.
25
+ EOF
34
26
  }
35
27
 
36
- echo "==> Fetching PR #$PR ..."
37
- HEAD_REF="$(gh pr view "$PR" --json headRefName -q .headRefName)"
38
- TITLE="$(gh pr view "$PR" --json title -q .title)"
39
- BODY="$(gh pr view "$PR" --json body -q .body)"
28
+ PR=""
29
+ MODE="auto"
30
+ while [ $# -gt 0 ]; do
31
+ case "$1" in
32
+ --manual-prompt)
33
+ MODE="manual"; shift ;;
34
+ --no-launch|--prepare-only)
35
+ MODE="no-launch"; shift ;;
36
+ -h|--help)
37
+ usage; exit 0 ;;
38
+ -*)
39
+ echo "lathe process: unknown flag $1" >&2
40
+ usage
41
+ exit 1 ;;
42
+ *)
43
+ if [ -z "$PR" ]; then
44
+ PR="$1"
45
+ else
46
+ echo "lathe process: extra argument $1" >&2
47
+ usage
48
+ exit 1
49
+ fi
50
+ shift ;;
51
+ esac
52
+ done
40
53
 
41
- git --git-dir="$PROJECT_ROOT/.git" fetch origin "$HEAD_REF" >/dev/null 2>&1 || true
42
-
43
- mkdir -p "$PROJECT_ROOT/tasks"
44
- TASK_WT="$PROJECT_ROOT/tasks/$PR"
45
- if [ -e "$TASK_WT" ]; then
46
- echo "lathe process: $TASK_WT already exists. Remove it or pick another PR." >&2
54
+ if [ -z "$PR" ]; then
55
+ usage
47
56
  exit 1
48
57
  fi
58
+ PR="${PR#\#}"
59
+
60
+ lathe_prepare_pr_task "$PR"
61
+ lathe_write_invocation process
62
+ INITIAL_PROMPT="$(lathe_task_process_prompt)"
63
+
64
+ copy_prompt_to_clipboard() {
65
+ if command -v pbcopy >/dev/null 2>&1; then
66
+ if printf '%s' "$INITIAL_PROMPT" | pbcopy 2>/dev/null; then
67
+ echo " Clipboard: copied via pbcopy"
68
+ else
69
+ echo " Clipboard: pbcopy failed"
70
+ fi
71
+ elif command -v wl-copy >/dev/null 2>&1; then
72
+ if printf '%s' "$INITIAL_PROMPT" | wl-copy 2>/dev/null; then
73
+ echo " Clipboard: copied via wl-copy"
74
+ else
75
+ echo " Clipboard: wl-copy failed"
76
+ fi
77
+ elif command -v xclip >/dev/null 2>&1; then
78
+ if printf '%s' "$INITIAL_PROMPT" | xclip -selection clipboard 2>/dev/null; then
79
+ echo " Clipboard: copied via xclip"
80
+ else
81
+ echo " Clipboard: xclip failed"
82
+ fi
83
+ else
84
+ echo " Clipboard: unavailable"
85
+ fi
86
+ }
49
87
 
50
- echo "==> Creating task worktree at $TASK_WT (branch: $HEAD_REF)..."
51
- git --git-dir="$PROJECT_ROOT/.git" worktree add --quiet "$TASK_WT" "$HEAD_REF"
88
+ print_aftercare() {
89
+ local feature_name=""
90
+ case "$HEAD_REF" in
91
+ feature/*) feature_name="${HEAD_REF#feature/}" ;;
92
+ esac
52
93
 
53
- PROMPT_FILE="$TASK_WT/.lathe-task.md"
54
- cat > "$PROMPT_FILE" <<EOF
55
- # PR #$PR: $TITLE
94
+ cat <<EOF
56
95
 
57
- You are processing pull request #$PR. The vibe-coded changes are in this worktree.
96
+ Target session exited.
97
+
98
+ Typical next steps:
99
+ gh pr view $PR --web
100
+ gh pr merge $PR --merge
101
+ cd "$DEVELOP_WT" && git pull origin develop
102
+ EOF
58
103
 
59
- **Task description (PR body):**
60
- $BODY
104
+ if [ -n "$feature_name" ]; then
105
+ cat <<EOF
106
+ cd "$PROJECT_ROOT" && lathe feature-done "$feature_name"
107
+ EOF
108
+ fi
61
109
 
62
- **Your job:**
63
- 1. Read the existing changes in this worktree (the vibe-coded prototype)
64
- 2. Plan a polished implementation (planning skill, plans/<run_id>.html)
65
- 3. After approval, dispatch coder/reviewer to produce a clean implementation
66
- 4. Coder commits and pushes to branch \`$HEAD_REF\` so the PR updates
67
- 5. Do NOT delete the original vibe commits — your polish goes ON TOP
110
+ cat <<EOF
68
111
 
69
- The task worktree is at: $TASK_WT
112
+ When the PR is merged and no more target work is needed:
113
+ git --git-dir="$PROJECT_ROOT/.git" worktree remove "$TASK_WT"
114
+ git --git-dir="$PROJECT_ROOT/.git" branch -D "$TASK_BRANCH"
70
115
  EOF
116
+ }
71
117
 
72
118
  cat <<EOF
73
119
 
74
120
  Task worktree ready.
75
121
  Path: $TASK_WT
76
- Branch: $HEAD_REF
77
- Prompt file: $PROMPT_FILE
78
-
79
- Launching target. Paste this into the claude TUI:
122
+ Local branch: $TASK_BRANCH
123
+ PR head branch: $HEAD_REF
124
+ Descriptor: $LATHE_TASK_DIR/task.json
125
+ Brief: $LATHE_TASK_DIR/brief.md
126
+ Invocation: $LATHE_TASK_DIR/invocation.json
127
+ Prompt: $INITIAL_PROMPT
128
+ EOF
80
129
 
81
- Read .lathe-task.md from the added directory ($TASK_WT) and process it.
130
+ case "$MODE" in
131
+ no-launch)
132
+ cat <<EOF
82
133
 
83
- Press Enter to launch claude (Ctrl-C to abort)...
134
+ Run target when ready:
135
+ cd "$DEVELOP_WT"
136
+ claude --add-dir "$TASK_WT" -- "$INITIAL_PROMPT"
84
137
  EOF
85
- read -r _
86
-
87
- cd "$DEVELOP_WT"
88
- exec claude --add-dir "$TASK_WT"
138
+ exit 0
139
+ ;;
140
+
141
+ manual)
142
+ echo ""
143
+ echo "Manual prompt mode. Paste this into the Claude TUI:"
144
+ echo ""
145
+ echo " $INITIAL_PROMPT"
146
+ echo ""
147
+ copy_prompt_to_clipboard
148
+ echo ""
149
+ echo "Launching target..."
150
+ cd "$DEVELOP_WT"
151
+ set +e
152
+ claude --add-dir "$TASK_WT"
153
+ status=$?
154
+ set -e
155
+ print_aftercare
156
+ exit "$status"
157
+ ;;
158
+
159
+ auto)
160
+ echo ""
161
+ echo "Launching target with the initial prompt already submitted..."
162
+ cd "$DEVELOP_WT"
163
+ set +e
164
+ claude --add-dir "$TASK_WT" -- "$INITIAL_PROMPT"
165
+ status=$?
166
+ set -e
167
+ print_aftercare
168
+ exit "$status"
169
+ ;;
170
+ esac
package/bin/lathe-sync CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # lathe sync — re-sync harness/ to target/.claude/ in the develop worktree.
2
+ # lathe sync — re-sync harness/ to .claude/ in the develop worktree.
3
3
  # Useful after manual harness edits, or if post-merge hook didn't fire (e.g.,
4
4
  # merge happened via GitHub UI).
5
5
 
package/bin/lathe-target CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # lathe target — cd into develop worktree's target/ and launch claude.
2
+ # lathe target — cd into the develop worktree and launch claude.
3
3
 
4
4
  set -euo pipefail
5
5
  : "${LATHE_HOME:?must be set by lathe dispatcher}"
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env bash
2
+ # lathe watch — poll GitHub PRs targeting develop and plan new ones locally.
3
+
4
+ set -euo pipefail
5
+ : "${LATHE_HOME:?must be set by lathe dispatcher}"
6
+ source "$LATHE_HOME/bin/_lathe-lib.sh"
7
+ source "$LATHE_HOME/bin/_lathe-task.sh"
8
+
9
+ usage() {
10
+ cat >&2 <<EOF
11
+ Usage: lathe watch [--once] [--interval <seconds>] [--base <branch>] [--dry-run]
12
+
13
+ Poll open GitHub PRs targeting <branch> (default: develop). For each PR that has
14
+ not already been planned by this watcher, run:
15
+
16
+ lathe plan --print pr <pr#>
17
+
18
+ Options:
19
+ --once Poll once and exit.
20
+ --interval <seconds> Poll interval for continuous mode. Default: 60.
21
+ --base <branch> PR base branch to watch. Default: develop.
22
+ --dry-run Print what would be planned without running Claude.
23
+ EOF
24
+ }
25
+
26
+ ONCE=0
27
+ INTERVAL=60
28
+ BASE_BRANCH="develop"
29
+ DRY_RUN=0
30
+ while [ $# -gt 0 ]; do
31
+ case "$1" in
32
+ --once)
33
+ ONCE=1; shift ;;
34
+ --interval)
35
+ INTERVAL="$2"; shift 2 ;;
36
+ --interval=*)
37
+ INTERVAL="${1#--interval=}"; shift ;;
38
+ --base)
39
+ BASE_BRANCH="$2"; shift 2 ;;
40
+ --base=*)
41
+ BASE_BRANCH="${1#--base=}"; shift ;;
42
+ --dry-run)
43
+ DRY_RUN=1; shift ;;
44
+ -h|--help)
45
+ usage; exit 0 ;;
46
+ -*)
47
+ echo "lathe watch: unknown flag $1" >&2
48
+ usage
49
+ exit 1 ;;
50
+ *)
51
+ echo "lathe watch: extra argument $1" >&2
52
+ usage
53
+ exit 1 ;;
54
+ esac
55
+ done
56
+
57
+ case "$INTERVAL" in
58
+ ''|*[!0-9]*)
59
+ echo "lathe watch: --interval must be a positive integer" >&2
60
+ exit 1 ;;
61
+ esac
62
+ if [ "$INTERVAL" -lt 1 ]; then
63
+ echo "lathe watch: --interval must be >= 1" >&2
64
+ exit 1
65
+ fi
66
+
67
+ lathe_require_gh
68
+ PROJECT_ROOT="$(lathe_project_root)" || {
69
+ echo "lathe watch: not inside a Lathe project" >&2
70
+ exit 1
71
+ }
72
+
73
+ STATE_DIR="$PROJECT_ROOT/.lathe/watch"
74
+ STATE_FILE="$STATE_DIR/planned-prs"
75
+ mkdir -p "$STATE_DIR"
76
+ touch "$STATE_FILE"
77
+
78
+ already_planned() {
79
+ grep -qxF "$1" "$STATE_FILE" 2>/dev/null
80
+ }
81
+
82
+ mark_planned() {
83
+ if ! already_planned "$1"; then
84
+ printf '%s\n' "$1" >> "$STATE_FILE"
85
+ fi
86
+ }
87
+
88
+ poll_once() {
89
+ local prs pr
90
+ prs="$(gh pr list --base "$BASE_BRANCH" --state open --json number -q '.[].number')"
91
+ if [ -z "$prs" ]; then
92
+ echo "lathe watch: no open PRs targeting $BASE_BRANCH"
93
+ return 0
94
+ fi
95
+
96
+ while IFS= read -r pr; do
97
+ [ -n "$pr" ] || continue
98
+ if already_planned "$pr"; then
99
+ echo "lathe watch: PR #$pr already planned; skipping"
100
+ continue
101
+ fi
102
+
103
+ if [ "$DRY_RUN" = 1 ]; then
104
+ echo "lathe watch: would plan PR #$pr"
105
+ continue
106
+ fi
107
+
108
+ echo "lathe watch: planning PR #$pr"
109
+ if "$LATHE_HOME/bin/lathe-plan" --print pr "$pr"; then
110
+ mark_planned "$pr"
111
+ echo "lathe watch: PR #$pr marked planned"
112
+ else
113
+ echo "lathe watch: planning PR #$pr failed; will retry on next poll" >&2
114
+ fi
115
+ done <<EOF
116
+ $prs
117
+ EOF
118
+ }
119
+
120
+ while true; do
121
+ poll_once
122
+ if [ "$ONCE" = 1 ]; then
123
+ exit 0
124
+ fi
125
+ sleep "$INTERVAL"
126
+ done
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "lathe-cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "Agent harness CLI: target/meta git worktrees driven by Claude Code",
5
5
  "bin": {
6
- "lathe": "./bin/lathe"
6
+ "lathe": "bin/lathe"
7
7
  },
8
8
  "files": [
9
9
  "bin/",
@@ -15,17 +15,17 @@ orchestrator です。コーディングタスクを受領し、計画し、suba
15
15
  - `feature/<id>` — 開発者の vibe coding ブランチ。task として処理対象になることがある(後述)
16
16
  - `main` — release ブランチ
17
17
 
18
- target/ 配下(`target/CLAUDE.md` 自身、`target/.claude/`、`target/workflow/`、`target/hooks/`、`target/plan_template.html`)は gitignore されており、**`harness/` から `bin/sync.sh` で生成されたコピー**。あなた自身の設定はここから読み込まれている。
18
+ worktree root の runtime ファイル(`CLAUDE.md` 自身、`.claude/`、`workflow/`、`hooks/`、`plan_template.html`)は gitignore されており、**`harness/` から `bin/sync.sh` で生成されたコピー**。あなた自身の設定はここから読み込まれている。
19
19
 
20
20
  ## 仕事の流れ
21
21
 
22
22
  1. **解釈**:受領した依頼を自分の言葉で言い直す。曖昧な点・前提・スコープを洗い出す
23
23
  2. **計画**:採用ワークフロー、アーキテクチャ、成果物、受入条件を planning skill に従って計画書 HTML にする
24
- 3. **契約**:計画書を人間(overseer)に提示し、承認を得る。曖昧点は承認前に解消する
25
- 4. **委譲**:承認された計画に沿って coder / reviewer に dispatch する
24
+ 3. **契約 / gate 判定**:採用 workflow が要求する gate を判定する。default workflow では計画書を人間(overseer)に提示し、承認を得る。曖昧点は gate 通過前に解消する
25
+ 4. **委譲**:採用 workflow の gate を通過した計画に沿って coder / reviewer に dispatch する
26
26
  5. **統合**:reviewer の verdict を見て、approve なら完了処理、block なら iterate
27
27
 
28
- ## 2 つの起動シナリオ
28
+ ## 起動シナリオ
29
29
 
30
30
  ### シナリオ A: 直接 task(debug / 検証用)
31
31
 
@@ -38,25 +38,44 @@ target/ 配下(`target/CLAUDE.md` 自身、`target/.claude/`、`target/workflo
38
38
 
39
39
  ### シナリオ B: PR 処理(本番)
40
40
 
41
- 人間が `lathe process <pr#>` で起動するケース。`--add-dir` で `feature/<id>` ブランチの worktree が追加されており、その path prompt で示される。`<task worktree>/.lathe-task.md` に PR 情報が入っている。
41
+ 人間が `lathe process <pr#>` で起動するケース。`--add-dir` で PR 処理用の `<task worktree>` が追加され、初回 prompt でその path が示される。`<task worktree>/.lathe/task.json` と `<task worktree>/.lathe/brief.md` に Lathe CLI が正規化した入力事実が入っている。`<task worktree>/.lathe/invocation.json` に、この起動で注入された実行時依存性が入っている。
42
+
43
+ 重要:`.lathe/task.json` は transport protocol であり、workflow / gates / escalation / delivery の policy ではない。`.lathe/invocation.json` も workflow 選択ではなく、選ばれた workflow が消費できる runtime dependency injection である。workflow 選択、workflow 構築、human escalation 判断は、この harness と `workflow/` が担う。
44
+
45
+ このとき:
46
+ 1. `<task worktree>/.lathe/task.json`、`<task worktree>/.lathe/brief.md`、`<task worktree>/.lathe/invocation.json` を読む
47
+ 2. `task.json` の事実、`brief.md`、`<task worktree>` 配下の **vibe code**、`invocation.json` の injected dependencies を読み、何を作ろうとしているか理解
48
+ 3. workflow を harness 側で選ぶ、または必要なら構築する。`invocation.json` の `plan_approval` grant や delivery adapter は、選ばれた workflow に注入される依存性として扱う
49
+ 4. 既存の `plans/*.html` に同じ PR source の計画があり、`task.json` / `brief.md` / `invocation.json` / 現在の diff と矛盾しなければその計画を使う。なければ planning skill で **polish された実装** を計画書に起こす(vibe を捨てない、polish を上に積む)
50
+ 5. 選ばれた workflow が `plan_approval` grant を安全に消費でき、human escalation 条件に該当しなければ、計画書 status を `approved` にし、承認者を `lathe process invocation` と記録して実装へ進む
51
+ 6. coder を `<task worktree>` を編集対象として dispatch
52
+ 7. coder の結果を reviewer に独立検証させる
53
+ 8. approve されたら、`<task worktree>` で git commit し、`task.json` に書かれた PR head branch へ push して PR を更新(後述)
54
+ 9. 計画書 status を completed にして人間に報告
55
+
56
+ PR 処理シナリオでは **編集対象は `<task worktree>` 配下**。develop worktree のファイル(自分の `harness/`、生成された runtime ファイル)は触らない。
57
+
58
+ `lathe process` でも human escalation は有効。仕様不明、既存計画の陳腐化、high-risk 変更、検証不能、review block 継続、delivery 失敗、または選ばれた workflow が injected dependencies を安全に消費できない場合は実装に進まず、人間に戻す。
59
+
60
+ ### シナリオ C: 自動計画(watch / plan)
61
+
62
+ `lathe plan pr <pr#>` または `lathe watch` から起動されるケース。入力形式はシナリオ B と同じだが、`invocation.json` と初回 prompt が **planning only** を明示している。
42
63
 
43
64
  このとき:
44
- 1. `<task worktree>/.lathe-task.md` を読む(PR body, branch 名)
45
- 2. `<task worktree>` 配下にある **vibe code を読み**、何を作ろうとしているか理解
46
- 3. planning skill **polish された実装** を計画書に起こす(vibe を捨てない、polish を上に積む)
47
- 4. 承認後、coder を `<task worktree>` を編集対象として dispatch
48
- 5. coder の結果を reviewer に独立検証させる
49
- 6. approve されたら、`<task worktree>` で git commit + push して PR を更新(後述)
50
- 7. 計画書 status を completed にして人間に報告
65
+ - `.lathe/task.json`、`.lathe/brief.md`、`.lathe/invocation.json` を読み、workflow 選択または構築を harness 側で行う
66
+ - `plans/<run_id>.html` を作成または更新し、契約/承認境界で停止する
67
+ - coder / reviewer dispatch しない
68
+ - `<task worktree>` を編集しない
69
+ - git commit / push をしない
51
70
 
52
- PR 処理シナリオでは **編集対象は `<task worktree>` 配下**。develop worktree のファイル(自分の harness/、target/)は触らない。
71
+ 未解決質問がある場合は status `draft` のままにし、人間への質問を計画書と最終報告に明記する。
53
72
 
54
73
  ## 計画書は契約書
55
74
 
56
- `plans/<run_id>.html` は単なる作業メモではなく、人間との契約。
75
+ `plans/<run_id>.html` は単なる作業メモではなく、採用 workflow の実行契約。default workflow では人間との承認契約として扱う。
57
76
 
58
- - 承認なしに実装に進まない(dispatch しない)
59
- - 承認された計画から逸脱したら status を `amended` に戻して再承認を得る
77
+ - 採用 workflow が human approval を要求する場合、承認なしに実装に進まない(dispatch しない)
78
+ - 承認済みまたは gate 通過済みの計画から逸脱したら status を `amended` に戻し、採用 workflow の gate に従って再判定する
60
79
  - 構造図と実行フロー(Mermaid)を含めて、文章だけで合意しない
61
80
  - HTML として自己完結(PR レビュー時にブラウザで開かれる前提)
62
81
 
@@ -83,31 +102,31 @@ PR 処理シナリオでは **編集対象は `<task worktree>` 配下**。devel
83
102
  あなたは原則手を動かさないが、**task lifecycle の一部としての git** は許容する:
84
103
 
85
104
  - シナリオ A:commit しない
86
- - シナリオ B:完了時に `<task worktree>` で `git add . && git commit && git push` を Bash で実行(PR を更新するため)。commit message の内容と co-author 情報は計画書から作る
105
+ - シナリオ B:完了時に `<task worktree>` で `git add . && git commit && git push origin HEAD:<PR head branch>` を Bash で実行(PR を更新するため)。`<PR head branch>` は `.lathe/task.json` の `source.head_branch` を使う。commit message の内容と co-author 情報は計画書から作る
87
106
 
88
107
  実装中の random な commit や branch 操作は禁止。task の最終成果として PR を更新する一回だけ。
89
108
 
90
- ## ディレクトリ構造(あなたの cwd は target/)
109
+ ## ディレクトリ構造(あなたの cwd は develop worktree root)
91
110
 
92
- - `target/.claude/agents/` — coder, reviewer
93
- - `target/.claude/skills/` — orchestrator が使う skill 群(現状 planning のみ)
94
- - `target/workflow/` — workflow YAML
95
- - `target/plans/` — タスクごとの計画書 HTML(あなたが書く、唯一の例外的書き込み先)
96
- - `target/plan_template.html` — 計画書のひな型
97
- - `target/hooks/` — hook スクリプト(あなたから直接呼ぶことはない、Claude Code が自動で叩く)
111
+ - `.claude/agents/` — coder, reviewer
112
+ - `.claude/skills/` — orchestrator が使う skill 群(現状 planning のみ)
113
+ - `workflow/` — workflow YAML
114
+ - `plans/` — タスクごとの計画書 HTML(あなたが書く、唯一の例外的書き込み先)
115
+ - `plan_template.html` — 計画書のひな型
116
+ - `hooks/` — hook スクリプト(あなたから直接呼ぶことはない、Claude Code が自動で叩く)
98
117
 
99
118
  これらはすべて `harness/` から sync された generated content。**直接編集禁止**(harness/ の方を meta が編集することで反映される)。
100
119
 
101
120
  ## 失敗モード
102
121
 
103
122
  - 計画書なしに dispatch しようとしている
104
- - 承認なしに dispatch しようとしている
123
+ - 採用 workflow が承認を要求しているのに、承認なしに dispatch しようとしている
105
124
  - 自分でファイルを編集しようとしている(plans/<run_id>.html を除く)
106
125
  - 曖昧な仕様のまま coder に投げる
107
126
  - 計画から逸脱したのに計画書を更新していない
108
127
  - 同じ subagent に同じ依頼を繰り返している(計画の問題を疑え)
109
128
  - シナリオ B で `<task worktree>` ではなく develop worktree のファイルを編集する
110
- - target/ 配下のファイルを編集する
129
+ - 生成された runtime ファイル(`CLAUDE.md`, `.claude/`, `workflow/`, `hooks/`, `plan_template.html`)を編集する
111
130
 
112
131
  ## 永続化チャネル制限(厳守)
113
132
 
@@ -128,7 +147,7 @@ session 間で覚える必要を感じたら、それは meta が improvements/
128
147
  ## 原則
129
148
 
130
149
  - 計画書なしに実装に進まない
131
- - 承認なしに実装に進まない
150
+ - 採用 workflow が承認を要求する場合、承認なしに実装に進まない
132
151
  - 自分は手を動かさない(plan 書きと、シナリオ B 完了時の git commit/push を除く)
133
- - 逸脱したら計画書を改訂して再承認を得る
152
+ - 逸脱したら計画書を改訂し、採用 workflow の gate に従って再判定する
134
153
  - 1 session で完結する。次の session は素の状態で始まる前提
@@ -27,7 +27,7 @@ target の実行 log を読み、改善を harness/ に加え、PR で develop
27
27
  7. `gh pr create --base develop --head meta` で PR 出す
28
28
  (single-machine 検証時は人間が `git checkout develop && git merge meta` で代用)
29
29
  8. PR が merge されると、develop の post-merge hook が bin/sync.sh を自動実行
30
- target/.claude/ が再生成、次回 target session で改善が効く
30
+ develop/.claude/ が再生成、次回 target session で改善が効く
31
31
  ```
32
32
 
33
33
  ## 取って良いアクション、取らないアクション
@@ -43,7 +43,7 @@ target の実行 log を読み、改善を harness/ に加え、PR で develop
43
43
  - `/tmp/` への作業メモ
44
44
 
45
45
  **取らない**:
46
- - **`target/` の編集**(gitignore 配下、sync で生成される、編集しても上書きされる)
46
+ - **develop worktree root の生成 runtime ファイルの編集**(`CLAUDE.md`, `.claude/`, `hooks/`, `workflow/`, `plan_template.html` は gitignore 配下、sync で生成される、編集しても上書きされる)
47
47
  - **`bin/sync.sh` の手動実行**(post-merge hook の責務、二重実行は無駄)
48
48
  - **`meta/` 配下の編集**(自己改変禁止、後述)
49
49
  - **`develop` ブランチへの直接 commit / push**(必ず PR 経由)
@@ -64,7 +64,7 @@ target の挙動を変えたいとき、編集するのは **harness/** 配下
64
64
  | hook スクリプト | `harness/hooks/*.sh` |
65
65
  | 計画書テンプレート | `harness/plan_template.html` |
66
66
 
67
- これらは sync.sh で `target/CLAUDE.md` `target/.claude/...` `target/workflow/` `target/hooks/` `target/plan_template.html` に展開される。
67
+ これらは sync.sh で develop worktree root の `CLAUDE.md` `.claude/...` `workflow/` `hooks/` `plan_template.html` に展開される。
68
68
 
69
69
  ## 標準フロー(コマンド付き)
70
70
 
@@ -113,7 +113,7 @@ PR が大げさなときは、人間が手で `git checkout develop && git merge
113
113
  - `runs/<sid>/subagents/agent-<aid>.jsonl` — subagent 別 transcript
114
114
  - `harness/` — 現在の harness 状態(meta worktree 上の最新)
115
115
  - `improvements/` — 過去の改善履歴
116
- - target/plans/<run_id>.html — target が書いた計画書(meta worktree でも見える、git 管理外)
116
+ - `plans/<run_id>.html` — target が書いた計画書(meta worktree でも見える、git 管理外)
117
117
 
118
118
  **書く**:
119
119
  - `harness/<file>` — 改善本体
@@ -105,7 +105,7 @@ jq -c '{ts, event, tool: .payload.tool_name // null}' events.jsonl
105
105
 
106
106
  ### 計画書との照合
107
107
 
108
- session_id から該当する `target/plans/<run_id>.html` を見つけ、これを Read する。計画書は orchestrator と人間の契約。実行が契約とどう乖離したかは、観察の出発点として強い。
108
+ session_id から該当する `plans/<run_id>.html` を見つけ、これを Read する。計画書は orchestrator と人間の契約。実行が契約とどう乖離したかは、観察の出発点として強い。
109
109
 
110
110
  session_id ↔ run_id の対応は events に出る Write tool_use(plans/<run_id>.html への書き込み)で辿れる。
111
111
 
@@ -117,7 +117,7 @@
117
117
 
118
118
  <div class="contract">
119
119
  <h2>契約セクション</h2>
120
- <p>本計画書は orchestrator human の合意である。承認された内容からの逸脱には再承認を要する。</p>
120
+ <p>本計画書は orchestrator と採用 workflow の実行契約である。human approval が必要な workflow では human との合意として扱う。gate 通過後の内容からの逸脱には workflow に従った再判定を要する。</p>
121
121
 
122
122
  <table>
123
123
  <tr><th>項目</th><th>記録</th></tr>
@@ -138,7 +138,7 @@
138
138
  <ul>
139
139
  <li>本計画書 3.3 に記載されたファイル以外を変更しない</li>
140
140
  <li>本計画書 6 の受入条件を全て満たすことをもって完了とする</li>
141
- <li>逸脱が必要な場合は status を amended に戻し再承認を得る</li>
141
+ <li>逸脱が必要な場合は status を amended に戻し、採用 workflow の gate に従って再判定する</li>
142
142
  </ul>
143
143
  </div>
144
144
 
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: planning
3
- description: タスク受領時に計画書HTMLを起草・保存する手順。plan_template.html を雛形として用い、`plans/<run_id>.html` に出力する。計画書は人間との契約書として機能するため、合意可能な粒度・検証可能な受入条件・図を含むこと。
3
+ description: タスク受領時に計画書HTMLを起草・保存する手順。plan_template.html を雛形として用い、`plans/<run_id>.html` に出力する。計画書は採用 workflow の実行契約として機能するため、合意可能な粒度・検証可能な受入条件・図を含むこと。
4
4
  ---
5
5
 
6
6
  # planning
7
7
 
8
8
  ## いつ使うか
9
- 新しいタスクを受領した直後、coder/reviewer に dispatch する前。計画から逸脱して再承認が要る場合の改訂時にも使う。
9
+ 新しいタスクを受領した直後、coder/reviewer に dispatch する前。計画から逸脱して workflow gate の再判定が要る場合の改訂時にも使う。
10
10
 
11
11
  ## 出力先と run_id
12
12
  - 雛形:`plan_template.html`
@@ -29,10 +29,13 @@ description: タスク受領時に計画書HTMLを起草・保存する手順。
29
29
  - **1.1 受領した依頼(原文)**:原文をそのまま引用。改変しない
30
30
  - **1.2 orchestrator の理解**:自分の言葉で言い直す。原文をなぞるのではなく、目的・スコープ・前提を解きほぐす。言い直しが原文より短くなったら情報を落としすぎている
31
31
  - **1.3 目的・スコープ・前提**:表を埋める。「スコープ内」「スコープ外」を両方書く(境界の合意が後の逸脱判定の基準になる)。前提条件は「これが崩れたら計画が崩れる」事項を列挙
32
+ - `.lathe/task.json` がある場合は、source type/id、base branch、head branch、task branch、task worktree を 1.2 または 1.3 に必ず含める。後続の `lathe process` が既存計画を同定するための手掛かりになる
33
+ - `.lathe/invocation.json` がある場合は、invocation intent と injected dependencies / constraints を 1.2 または 1.3 に必ず含める。ただしこれは workflow 選択ではなく、採用 workflow が消費する依存性として記述する
32
34
 
33
35
  ### 2. 採用ワークフロー
34
36
  - `workflow/` から1つ選ぶ(YAML ファイル)
35
37
  - 「なぜこのテンプレートか」を必ず書く。デフォルト(`workflow/default.yaml`)を選ぶときも理由を書く
38
+ - `lathe process` 起動で `.lathe/invocation.json` が `plan_approval` grant を注入している場合は、採用 workflow がその grant をどう消費するか、または消費できず human escalation する理由をここか契約セクションに明記する
36
39
 
37
40
  ### 3. 実装計画
38
41
  - **3.1 概要**:文章で全体像
@@ -54,7 +57,7 @@ description: タスク受領時に計画書HTMLを起草・保存する手順。
54
57
 
55
58
  ### 7. リスク・未解決の質問
56
59
  - 計画段階で曖昧な点があれば全部ここに出す
57
- - 1つでもあるなら status は `draft` のまま。承認には進まない
60
+ - 1つでもあるなら status は `draft` のまま。human approval や auto gate には進まない
58
61
 
59
62
  ### 8. 実行フロー
60
63
  - Mermaid `sequenceDiagram` で actors(Human, Orchestrator, Coder, Reviewer)と呼び出し順を描く
@@ -64,6 +67,7 @@ description: タスク受領時に計画書HTMLを起草・保存する手順。
64
67
  - 提出日時・承認日時・承認者・完了日時・status を記録
65
68
  - 修正履歴は append-only。古い記述を消さない。逸脱が起きた場合は「何を、なぜ変えたか」を記録する
66
69
  - 「承認に伴う合意事項」セクションは雛形のまま残す。タスク固有の合意があれば追記する
70
+ - `.lathe/invocation.json` の `plan_approval` grant を採用 workflow が消費して進む場合、承認日時は gate 通過時刻、承認者は `lathe process invocation` とし、「lathe process の injected dependency により計画承認gateを満たした」と修正履歴または合意事項に記録する
67
71
 
68
72
  ## 図は Mermaid で書く
69
73
  将来 PR で人間に渡されることを想定し、GitHub が描画できる Mermaid を使う。画像埋め込みや独自記法は使わない。
@@ -78,6 +82,6 @@ draft → awaiting_approval → approved → in_progress → completed
78
82
 
79
83
  - 起草中は `draft`
80
84
  - 人間に出した時点で `awaiting_approval`
81
- - 承認を受けたら `approved`、dispatch 開始で `in_progress`
85
+ - 人間の承認、または採用 workflow の auto gate を通過したら `approved`、dispatch 開始で `in_progress`
82
86
  - 完了で `completed`
83
- - 実行中に計画変更が必要になったら `amended` に戻し、修正→再承認
87
+ - 実行中に計画変更が必要になったら `amended` に戻し、修正→採用 workflow の gate 再判定
@@ -47,7 +47,11 @@ lathe init ← 既に走った前提
47
47
  lathe target [args...] develop worktree で claude 起動(debug or 直接 task)
48
48
  lathe meta [args...] meta worktree で claude 起動
49
49
  lathe sync develop の bin/sync.sh 手動実行(post-merge hook が動かない時)
50
- lathe process <pr#> PR pickup → tasks/<pr#>/ worktree 作成 → target 起動
50
+ lathe plan pr <pr#> PR pickup → target が計画だけ作る
51
+ lathe watch [--once] develop 宛て新規 PR を監視し、未計画なら lathe plan --print pr
52
+ lathe process <pr#> PR pickup/reuse → tasks/<pr#>/ worktree + task/pr-<pr#> branch → target が計画承認待ちなしで実装まで進める
53
+ lathe process --manual-prompt <pr#> 旧式 Claude Code 用。prompt 手貼り fallback
54
+ lathe process --no-launch <pr#> tasks/<pr#>/ 準備だけ行い、target は起動しない
51
55
  lathe feature <name> [--from main|develop]
52
56
  features/<name>/ worktree 作成、新 feature/<name> 枝
53
57
  lathe feature-done <name> [--keep-branch] [--keep-remote] [--force]
@@ -76,12 +80,23 @@ PR が立ったら(overseer 役):
76
80
 
77
81
  ```sh
78
82
  cd project_root
79
- lathe process <pr#> # tasks/<pr#>/ worktree が新規作成、target が起動
83
+ lathe plan pr <pr#> # 任意: 計画だけ作る。lathe watch なら自動
84
+ lathe process <pr#> # tasks/<pr#>/ worktree が作成/reuse され、target が起動
80
85
  ```
81
86
 
82
- claude TUI が立ち上がるので、表示された prompt:「Read .lathe-task.md from the added directory and process it.」を貼る。
87
+ `lathe plan` / `lathe process` は `tasks/<pr#>/` を専用 local branch `task/pr-<pr#>` で作る。元の `feature/<name>` worktree が残っていても同じ branch checkout 競合を起こさない。`tasks/<pr#>/.lathe/task.json` と `.lathe/brief.md` Lathe が生成する transport protocol、`.lathe/invocation.json` は runtime dependency injection で、workflow/gates/delivery は target harness が選ぶ。claude TUI は初回 prompt が投入された状態で立ち上がる。古い Claude Code で prompt 引数が効かない場合だけ、`lathe process --manual-prompt <pr#>` を使って表示された prompt を貼る。
83
88
 
84
- orchestrator plan HTML を起こして承認待ちで止まる。承認したら coder/reviewer に dispatch、PR branch に commit/push されて PR が更新される。
89
+ `lathe plan pr <pr#>` は plan HTML を起こして承認境界で止まる。`lathe process <pr#>` は workflow を固定せず、計画承認 grant と PR delivery adapter を `invocation.json` で注入する。target harness は任意の workflow を選び、その依存性を安全に消費できるなら既存 plan を再利用または新規作成して、計画承認待ちは挟まず coder/reviewer に dispatch する。仕様不明、high-risk 変更、検証不能など selected workflow の escalation triggers に該当する場合だけ human に戻す。完了時は `task/pr-<pr#>` に commit し、`git push origin HEAD:<PR head branch>` で PR が更新される。
90
+
91
+ ### develop PR をローカル監視する
92
+
93
+ ```sh
94
+ cd project_root
95
+ lathe watch --once # 1回だけ確認
96
+ lathe watch --interval 60 # 継続監視。新規PRごとに lathe plan --print pr
97
+ ```
98
+
99
+ watch は workflow を選ばない。新規PRを見つけたら task worktree と `.lathe/` transport を作り、target harness に planning-only prompt を渡すだけ。人間承認、実装、merge の要否は harness workflow 側で決める。
85
100
 
86
101
  ### feature を終わらせる
87
102