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
36 changes: 25 additions & 11 deletions .claude/skills/apply-and-verify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ allowed-tools: Bash(git add*) Bash(git commit*) Bash(git push*) Bash(git diff*)
- `openspec/changes/<change-id>/` 已有完整 proposal/design/tasks/spec-delta
- `openspec validate <change-id> --strict` 已綠燈
- 已跑過 `gitnexus-blast-radius pre-change`,risk_level 非 CRITICAL
- 已在 `codex/openspec/<change-id>` branch
- 已執行 `opsx-worktree-provision`,取得 manifest,`cwd_hint = <repo>/.worktrees/<change-id>/`,HEAD = `codex/openspec/<change-id>`
- main worktree (`<repo_root>`) 保持唯讀,所有 git/edit/test 動作走 `git -C "<cwd_hint>"` 或 `cd "<cwd_hint>/<service>"`
Comment on lines +16 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run OpenSpec validation from the worktree

When apply-and-verify is invoked after provisioning, the caller can still be in the main worktree while the change artifacts live under manifest.cwd_hint; however Layer 1 still runs openspec validate <change-id> --strict without cd "<cwd_hint>" or an equivalent cwd flag. In that context it validates main's openspec/changes tree instead of the worktree, so a newly created or updated change can fail as missing or, worse, pass against stale main contents while the actual worktree specs are invalid.

Useful? React with 👍 / 👎.


詳細規範見 [docs/agent-tooling/opsx-worktree-provision.md](../../../docs/agent-tooling/opsx-worktree-provision.md)。

## 執行步驟

Expand Down Expand Up @@ -58,36 +61,39 @@ docs/verification/<date>-<change-id>.md # verification evidence

#### Layer 2:focused tests

依 bounded service 跑:
依 bounded service 跑(`<cwd_hint>` 來自 `opsx-worktree-provision` manifest,例:`<repo>/.worktrees/<change-id>`):

```
# _worker
!`cd _worker && python -m pytest tests/ -x`
!`cd "<cwd_hint>/_worker" && python -m pytest tests/ -x`

# _bim-control
!`cd _bim-control && python -m pytest tests/ -x`
!`cd "<cwd_hint>/_bim-control" && python -m pytest tests/ -x`

# bim-review-coordinator
!`cd bim-review-coordinator && python -m pytest tests/ -x`
!`cd "<cwd_hint>/bim-review-coordinator" && python -m pytest tests/ -x`
Comment on lines +68 to +74

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Test commands conflict with the declared tool allowlist.

The doc now uses python -m pytest ..., but allowed-tools only permits Bash(pytest*). That mismatch can make these steps non-executable under policy enforcement.

Suggested doc-aligned fix
-!`cd "<cwd_hint>/_worker" && python -m pytest tests/ -x`
+!`cd "<cwd_hint>/_worker" && pytest tests/ -x`

-!`cd "<cwd_hint>/_bim-control" && python -m pytest tests/ -x`
+!`cd "<cwd_hint>/_bim-control" && pytest tests/ -x`

-!`cd "<cwd_hint>/bim-review-coordinator" && python -m pytest tests/ -x`
+!`cd "<cwd_hint>/bim-review-coordinator" && pytest tests/ -x`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/apply-and-verify/SKILL.md around lines 68 - 74, The test
command lines in SKILL.md use `python -m pytest ...` which conflicts with the
declared allowed-tools pattern `Bash(pytest*)`; either replace the invocations
`python -m pytest tests/ -x` with plain `pytest tests/ -x` (e.g., in the three
entries referencing _worker, _bim-control, bim-review-coordinator) so they match
`Bash(pytest*)`, or update the tool allowlist to permit `python -m pytest`
invocations; modify whichever is appropriate so the command strings and the
allowlist (`Bash(pytest*)` vs `python -m pytest`) are consistent.


# web-viewer-sample
!`cd web-viewer-sample && npm test`
!`cd "<cwd_hint>/web-viewer-sample" && npm test`
```

**重要**:必須在各自服務目錄執行([CLAUDE.md](CLAUDE.md) 規範:避免多個 FastAPI 服務共用 `app` package name 時污染 import cache)。
**重要**:
- 必須在各自服務目錄執行([CLAUDE.md](CLAUDE.md) 規範:避免多個 FastAPI 服務共用 `app` package name 時污染 import cache)
- 必須走 `<cwd_hint>`(worktree 路徑),不在 main worktree 跑測試
- 首次 apply 時各服務 `.venv` 需在 worktree 內自建(`venv_strategy: per-service-self-bootstrap`)

#### Layer 3:diff 衛生檢查

```
!`git diff --check`
!`git -C "<cwd_hint>" diff --check`
```

阻擋 whitespace / formatting 問題。

#### Layer 4:GitNexus scope drift 驗證

```
!`gitnexus detect-changes --scope staged`
!`gitnexus detect-changes --scope staged --cwd "<cwd_hint>"`
```

呼叫 `gitnexus-blast-radius post-change` skill,比對 `affected_symbols` 是否 ⊆ tasks.md 預期 scope。
Expand All @@ -114,7 +120,7 @@ Commit message 用 Conventional Commits(PR #31/#33/#35 已成熟格式):
### Step 5:Push 與開 PR

```
!`git push -u origin codex/openspec/<change-id>`
!`git -C "<cwd_hint>" push -u origin codex/openspec/<change-id>`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Permit the new git -C commands

The skill now tells the agent to run commands that start with git -C, but the frontmatter still only whitelists prefixes such as Bash(git push*) and Bash(git diff*). In Claude Code's allowed-tools matching this means the new worktree-aware push/diff/status/add/commit commands are not covered by the declared permissions, so the apply flow can be blocked exactly when it tries to operate inside cwd_hint; add the appropriate Bash(git -C*) entries or use an allowed cd "<cwd_hint>" && git ... form consistently.

Useful? React with 👍 / 👎.

```

```
Expand All @@ -125,6 +131,8 @@ Commit message 用 Conventional Commits(PR #31/#33/#35 已成熟格式):
--body-file <generated PR body>`
```

> `gh pr create` 認 branch 不認 cwd,可從 main worktree 或 `<cwd_hint>` 任一處呼叫。

PR body 固定使用:

```markdown
Expand Down Expand Up @@ -163,6 +171,7 @@ PR body 固定使用:
change_id: <id>
implementation_pr: <pr-number>
branch: codex/openspec/<change-id>
worktree_path: <cwd_hint>
validation:
openspec_strict: passed
focused_tests:
Expand All @@ -173,14 +182,19 @@ validation:
affected_scope: [<list>]
drift: []
commit_sha: <sha>
cleanup_hint:
- "git worktree remove \"<cwd_hint>\""
- "git branch -d codex/openspec/<change-id>"
```

## 安全條款

- 四層驗證任一失敗 → 不 commit,回到對應 Step
- 不跑 `git add -A`,逐 file 確認
- 所有 git/edit/test 動作走 `<cwd_hint>`,**不在 main worktree** 內改檔或 commit
- 不跑 `git -C "<cwd_hint>" add -A`,逐 file 確認
- 不在 commit message 寫「fix everything」這種模糊摘要
- 不在 implementation PR 內偷塞 archive 動作
- apply 結束**不自動清** worktree;印 `cleanup_hint`,由使用者人工執行

## 參考

Expand Down
32 changes: 28 additions & 4 deletions .claude/skills/closed-loop-orchestrator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: closed-loop-orchestrator
description: 串接 AI-BIM-governance / OpenSpec / GitNexus 三技能完整 14-step 閉環。當使用者要「開始新 change」、「跑完整閉環」、「自動化 OpenSpec 流程」時使用。本技能不會自動執行 merge / archive,所有不可逆 phase 都會停下來等使用者確認。
disable-model-invocation: true
allowed-tools: Bash(git status*) Bash(git fetch*) Bash(git switch*) Bash(git rev-parse*) Bash(gh pr list*) Bash(gh pr view*) Read Grep Glob Skill
allowed-tools: Bash(git status*) Bash(git fetch*) Bash(git rev-parse*) Bash(git worktree*) Bash(gh pr list*) Bash(gh pr view*) Read Grep Glob Skill
---

# Closed-Loop Orchestrator
Expand All @@ -20,7 +20,9 @@ allowed-tools: Bash(git status*) Bash(git fetch*) Bash(git switch*) Bash(git rev

### Phase A:起點判定(Step 1–3)

呼叫 `change-id-resolve` skill:
依 [docs/agent-tooling/opsx-worktree-provision.md](docs/agent-tooling/opsx-worktree-provision.md) 規範,Phase A 改採 git worktree 隔離 — main worktree 保持唯讀。

#### A.1:呼叫 `change-id-resolve`

```
/change-id-resolve
Expand All @@ -30,8 +32,29 @@ allowed-tools: Bash(git status*) Bash(git fetch*) Bash(git switch*) Bash(git rev

**Gate**:
- `blockers` 非空 → STOP 並回報
- 若 `branch_plan == "new"` → `git switch -c codex/openspec/<change-id>`
- 若 `branch_plan == "continue-existing"` → `git switch <branch>` 並 pull rebase

#### A.2:呼叫 `opsx-worktree-provision`

```
/opsx-worktree-provision <change-id> --branch-plan <new|continue-existing>
```

取得 manifest:

```yaml
worktree_path: <abs>
branch: codex/openspec/<id>
created_new: <bool>
cwd_hint: <abs>
env_copied: {...}
warnings: [...]
```

**Gate**:
- skill 回報任一 `cwd-not-main` / `main-dirty` / `branch-bound-elsewhere` / `worktree-dirty` → STOP
- 後續所有 Phase 必須用 `manifest.cwd_hint` 作為 `git -C` / `cd` 目標

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass cwd_hint into spec exploration

This gate says every later phase must use manifest.cwd_hint, but Phase B still invokes openspec-explore-twice without passing or changing cwd, and that skill writes openspec/changes/<change-id>/... using relative paths. Under the new design assumption that the agent process stays in the main worktree, starting a new change will create or edit the OpenSpec artifacts in main before apply, making main dirty and bypassing the intended worktree isolation.

Useful? React with 👍 / 👎.

- **不**在 main worktree (`<repo_root>`) 內做任何 edit / commit
- continue-existing 不自動 `pull --rebase`,由使用者明確介入

### Phase B:規格收斂(Step 4)

Expand Down Expand Up @@ -110,6 +133,7 @@ allowed-tools: Bash(git status*) Bash(git fetch*) Bash(git switch*) Bash(git rev

| 條款 | 規則 |
|---|---|
| Worktree isolation | Phase A 起改採 `opsx-worktree-provision`,main worktree 唯讀;所有後續操作走 `manifest.cwd_hint` |
| Branch isolation | 永遠不在 `main` 直接 commit |
| NoSuccessorWhilePredecessorOpen | predecessor 未完整 closeout 前,不開 successor 的 active change |
| Two-PR policy | implementation PR 與 archive PR 必須分開,archive 不得搭便車 |
Expand Down
151 changes: 151 additions & 0 deletions .claude/skills/opsx-worktree-provision/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
name: opsx-worktree-provision
description: OpenSpec apply 前置——把 `codex/openspec/<change-id>` 分支放進 `<repo>/.worktrees/<change-id>/` 並回傳 manifest。當 `change-id-resolve` 已給出 change-id、要進入 `apply-and-verify` 之前使用。
allowed-tools: Bash(git worktree*) Bash(git fetch*) Bash(git rev-parse*) Bash(git status*) Bash(git branch*) Bash(git worktree list*) Bash(cp*) Bash(test*) Bash(mkdir*) Bash(stat*) Read Glob
---

# opsx-worktree-provision

依 [docs/agent-tooling/opsx-worktree-provision.md](../../../docs/agent-tooling/opsx-worktree-provision.md) 規範執行 worktree provisioning。**本文件只列 skill 互動規則,完整設計留底在上述 doc。**

## 觸發前提

- 由 `closed-loop-orchestrator` Phase A 或 `/opsx:apply` Step 0 呼叫
- 上游已執行 `change-id-resolve`,輸入 `{ change_id, branch_plan }` 可用
- 當前 cwd = main worktree(top-level)

## 輸入

```yaml
change_id: <required>
branch_plan: new | continue-existing # 來自 change-id-resolve
```

## 七步流程

### Step 1:cwd 驗證

```
!`git rev-parse --show-toplevel`
!`git rev-parse --git-common-dir`
```

若 cwd 不是 main worktree(top-level path 與 git-common-dir 不對應)→ STOP `cwd-not-main`。

### Step 2:同步 origin

```
!`git fetch origin --prune`
```

### Step 3:解析目標

```yaml
repo_root: <git rev-parse --show-toplevel 結果>
target_path: <repo_root>/.worktrees/<change_id>
branch: codex/openspec/<change_id>
```

### Step 4:衝突偵測(任一觸發即 STOP)

| Gate | 偵測 | 失敗 reason |
|---|---|---|
| main-dirty | `git status --porcelain` 非空 | `main-dirty` |
| branch-bound-elsewhere | `git worktree list --porcelain` 顯示 branch 在另一 path | `branch-bound-elsewhere` |
| worktree-dirty | target_path 存在且 `git -C <target_path> status --porcelain` 非空 | `worktree-dirty` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Permit provisioning's git -C status check

The worktree-dirty gate requires git -C <target_path> status --porcelain when a target path already exists, but this skill's allowed tools only cover prefixes like Bash(git status*), not commands that start with git -C. In a reuse/dirty-check scenario the skill can be blocked before it can inspect the existing worktree, so either whitelist Bash(git -C*) here or express the check as an allowed cd <target_path> && git status ... command.

Useful? React with 👍 / 👎.


### Step 5:建立或重用

```
!`git rev-parse --verify --quiet refs/heads/<branch>` # local_exists
!`git rev-parse --verify --quiet refs/remotes/origin/<branch>` # remote_exists
```

| target_path 存在? | local_exists | remote_exists | 動作 |
|---|---|---|---|
| ✓ | * | * | 重用,`created_new = false` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify the reused worktree branch

When <repo>/.worktrees/<change_id> already exists but is a clean worktree for a different branch or detached HEAD, this rule reuses it solely because the path exists. The manifest then advertises codex/openspec/<id>, so downstream edits and commits can land on the wrong branch; check target_path's current HEAD/branch against the desired branch before reusing it, and stop or recreate if it differs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require target_path to be a registered worktree

If <repo>/.worktrees/<change_id> exists as a leftover plain directory rather than a Git worktree, this branch reuses it without checking git worktree list for that exact path. Because the directory is inside the main repo, git -C <target_path> ... can resolve to the parent repository while files under .worktrees/ remain ignored, so downstream edits may not be committed to codex/openspec/<id> at all; only reuse paths that are registered worktrees for the target branch.

Useful? React with 👍 / 👎.

| ✗ | ✓ | * | `git worktree add <target_path> <branch>` |
Comment on lines +64 to +67
| ✗ | ✗ | ✓ | `git worktree add <target_path> -b <branch> origin/<branch>` |
| ✗ | ✗ | ✗ | `git worktree add <target_path> -b <branch> main` |

`base_ref` 對應記在 manifest。

### Step 6:env copy

掃描清單:

```
.env
_bim-control/.env
_worker/.env
bim-review-coordinator/.env
bim-streaming-server/.env
web-viewer-sample/.env
```

對每個來源(main worktree):

- 來源不存在 → 跳過。
- 目標已存在於 worktree → 加進 `skipped`,**不覆蓋**。
- 否則 `cp "<repo_root>/<path>" "<target_path>/<path>"`,加進 `copied`。
Comment on lines +88 to +90

**絕不**:
- echo 任何 `.env` 內容到 log
- `git add` `.env`
- 建 symlink(用 hard copy)

### Step 7:輸出 manifest

把以下 YAML 印到工作流程輸出,供 `apply-and-verify` 與 `closed-loop-orchestrator` 後續 Phase 讀取:

```yaml
change_id: <id>
worktree_path: <abs>
branch: codex/openspec/<id>
base_ref: main | origin/codex/openspec/<id> | reused
created_new: <bool>
cwd_hint: <abs>
env_copied:
copied: [<list>]
skipped: [<list>]
venv_strategy: per-service-self-bootstrap
warnings:
- ".env 是 main 快照,main 後續變動不會同步"
- "首次 apply 需在 worktree 內各服務自建 venv"
- ".claude / .codex 不在 worktree 內 (預期)"
```

## 後續使用約定

下游 skill(如 `apply-and-verify`)必須遵守:

- 所有 git 動作用 `git -C "<cwd_hint>" ...` 或 `cd "<cwd_hint>" && ...`
- 各服務測試 `cd "<cwd_hint>/<service>" && <test cmd>`
- 不在 main worktree (`<repo_root>`) 內做任何 edit / commit
- gh 指令認 branch 不認 cwd,可在任何位置呼叫

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does gh pr createrequire being run inside a local git repository (or using--repo)? Please cite GitHub CLI docs.

💡 Result:

No, gh pr create does not strictly require being run inside a local git repository if using the --repo flag to specify the target repository explicitly. The official GitHub CLI manual documents the -R, --repo &lt;[HOST/]OWNER/REPO&gt; flag, which allows selecting another repository, enabling the command to work outside a local git repo as long as required flags like --title, --body, --head, and --base are provided (since features like --fill rely on local git commits and will fail without a repo) [1][2]. A merged pull request specifically enabled gh pr create --repo from outside a local git repository [2]. Without --repo (or a default repo set via gh repo set-default), it requires a local git repo to determine the repository from remotes [3].

Citations:


Clarify conditions for gh invocation from arbitrary locations.

"可在任何位置呼叫" (can be called from any location) is misleading without context. gh pr create requires either a local git repository context OR the --repo flag. Calling it from arbitrary directories without --repo will fail. Revise to specify: "可使用 --repo 指令在任何位置呼叫" (can be called from any location using --repo flag) or document the repo/worktree path requirement explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/opsx-worktree-provision/SKILL.md at line 125, 將原本描述 "gh 指令認
branch 不認 cwd,可在任何位置呼叫" 改為明確說明 gh pr create 的條件:指出若在非 Git 工作目錄呼叫,必須加上 --repo
<owner/repo>(或指定工作樹路徑)才能成功,否則需在含 .git 的本地倉庫或 worktree
中執行;具體修改目標為該行文字,將「可在任何位置呼叫」改為「可在任何位置呼叫(需搭配 --repo 指定倉庫),或在本地 git 倉庫 / worktree
中直接執行」以避免誤導。


## apply 結束後

不自動清。在工作流程結尾印 `cleanup_hint`:

```bash
git worktree remove "<worktree_path>"
git branch -d codex/openspec/<change_id>
```

由使用者人工執行。

## 安全條款

- 四個 Gate 任一觸發 → STOP,回報 reason,**不嘗試自動修復**
- 不修改 main worktree 內任何檔案(包括 `.gitignore`、tracked code)
- continue-existing 不自動 `pull --rebase`;由使用者決定
- 不偵測或清理 `.codex/worktrees/*` 殘留(屬於獨立 follow-up change)

## 參考

- [docs/agent-tooling/opsx-worktree-provision.md](../../../docs/agent-tooling/opsx-worktree-provision.md):完整設計留底
- [AGENTS.md](../../../AGENTS.md):repo 邊界與 source-of-truth 順序
- [CLAUDE.md](../../../CLAUDE.md) §Git 與本機 agent 產物:branch / PR 政策
- [.claude/skills/change-id-resolve/SKILL.md](../change-id-resolve/SKILL.md):上游 skill
- [.claude/skills/apply-and-verify/SKILL.md](../apply-and-verify/SKILL.md):下游 skill
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Thumbs.db
!.claude/skills/apply-and-verify/
!.claude/skills/pr-review-gate/
!.claude/skills/archive-and-closeout/
!.claude/skills/opsx-worktree-provision/
.codex/
.vscode/
.gitnexus/
Expand Down Expand Up @@ -108,3 +109,8 @@ _s3_storage/static/projects/
!_fixtures/**/*.usda
!_fixtures/**/*.usdc
!_fixtures/**/*.json

# ----------------------------
# OpenSpec apply worktrees (opsx-worktree-provision)
# ----------------------------
.worktrees/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore copied local .env files

Step 6 copies service .env files into the linked worktree, but this ignore rule only hides the .worktrees/ directory from the main worktree; inside the linked worktree the copied paths such as _worker/.env or _bim-control/.env are still unignored. When those local files exist, the new worktree becomes dirty with untracked secrets and they can be accidentally staged by explicit git add, so add ignore patterns for the copied .env targets before relying on the copy step.

Useful? React with 👍 / 👎.

Loading