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
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ Codex / Claude 向けの agent、skill、設定、プロンプトを管理し、

## ブランチ運用

- worktree で作業するブランチには、`worktrees/<番号>/` prefix を付けます(例: `worktrees/1/feat/refine-ui`)。
- worktree 以外で作業するブランチには、`chore/`、`fix/`、`feat/`、`docs/`、`refactor/` のいずれかの prefix を付けます。
- 作業ブランチをデフォルトブランチの最新状態へ追従させるときは、merge や `git rebase` ではなく `grape rebase` を使用します。

## 配布時の確認
Expand Down
14 changes: 6 additions & 8 deletions codex/skills/internal/cmd-start-branch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ description: Git リポジトリで新しい作業を始める前に、最新の
- ローカル差分や競合リスクがある場合は止めて、ブランチ作成前に状況を報告する。
4. タスク内容からブランチ名を作る。
- 「ブランチ種別の選び方」の表から、指示内容に最も合う種別を選ぶ。
- 形式は `<type>/<short-task>` にする。
- `git rev-parse --show-toplevel` で、現在地が `.worktrees/<番号>` の worktree か確認する。
- worktree では `worktrees/<番号>/<type>/<short-task>`、それ以外では `<type>/<short-task>` の形式にする。
- worktree の番号を特定できない場合は推測せず、ユーザーへ確認する。
- 英小文字、数字、ハイフンを使う。
- 例: `feat/add-start-branch-skill`, `fix/login-timeout`, `refactor/split-auth-service`
- 例: `worktrees/1/feat/add-start-branch-skill`, `fix/login-timeout`, `refactor/split-auth-service`
5. `git checkout -b <branch-name>` で作業ブランチを作成する。
- 同名ブランチがある場合は、既存ブランチの位置と状態を確認し、上書きせず別名を提案する。
6. `$cmd-dispatch-agent` を使って、別 agent に `$cmd-rmbranch` を依頼する。
Expand All @@ -55,7 +57,7 @@ description: Git リポジトリで新しい作業を始める前に、最新の
## ブランチ名の判断

- ユーザーがタスク名や Issue 番号を示している場合は、それを優先する。
- Issue 番号がある場合は `feat/123-short-task` のように先頭へ入れる
- Issue 番号がある場合は `feat/123-short-task` のようにタスク名の先頭へ入れる。worktree では `worktrees/1/feat/123-short-task` のようにする
- まだ内容が薄い場合は `chore/start-task-branch` のような仮名にし、後で必要なら rename を提案する。
- 既存ブランチと衝突する場合は末尾に短い識別子を足す。

Expand All @@ -70,12 +72,8 @@ description: Git リポジトリで新しい作業を始める前に、最新の
| `feat` | 新機能、既存機能へのユーザー向け能力追加 | `feat/report-filter`, `feat/42-export-csv` |
| `fix` | バグ修正、不具合回避、期待と違う挙動の修正 | `fix/login-timeout`, `fix/price-rounding` |
| `refactor` | 挙動を変えない構造整理、責務分割、命名整理 | `refactor/split-auth-service`, `refactor/repository-contract` |
| `test` | テスト追加、テスト修正、fixture や検証手順の整備 | `test/add-order-cases`, `test/stabilize-api-spec` |
| `perf` | 性能改善、メモリ削減、クエリ最適化 | `perf/cache-rate-lookup`, `perf/reduce-render-cost` |
| `style` | フォーマット、lint、見た目だけのコード整形。UI 見た目変更は `feat` または `fix` を優先する | `style/format-go-files`, `style/lint-imports` |
| `ci` | CI、ワークフロー、ビルドパイプライン、リリース自動化 | `ci/add-test-workflow`, `ci/cache-go-build` |
| `docs` | README、設計メモ、Runbook など文書だけの変更 | `docs/update-runbook`, `docs/add-skill-guide` |
| `chore` | 依存更新、設定整理、生成物更新、運用上の雑務。上記に当てはまるならそちらを優先する | `chore/update-deps`, `chore/start-task-branch` |
| `chore` | テスト、性能、整形、CI、依存更新、設定整理、生成物更新など、他の種別に当てはまらない保守作業 | `chore/add-order-tests`, `chore/add-test-workflow` |

## 報告に含めること

Expand Down
9 changes: 8 additions & 1 deletion codex/skills/internal/cmd-start-branch/evals/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@
{
"id": 4,
"prompt": "GitHub Actions の Go テスト CI を追加する作業ブランチを作って",
"expected_output": "CI ワークフロー変更として ci を選び、Go テスト CI 用のブランチを最新デフォルトブランチから作成して、不要ブランチ整理を非同期 agent に依頼する。",
"expected_output": "他の種別に当てはまらない CI の保守作業として chore を選び、Go テスト CI 用のブランチを最新デフォルトブランチから作成して、不要ブランチ整理を非同期 agent に依頼する。",
"files": [],
"should_fire": true
},
{
"id": 5,
"prompt": ".worktrees/3 で Issue 42 のレポート画面改善を始めるのでブランチを作って",
"expected_output": "worktree のスロット番号 3 とユーザー向け能力追加の feat を使い、worktrees/3/feat/42-report-improvement のような形式でブランチを作成して、不要ブランチ整理を非同期 agent に依頼する。",
"files": [],
"should_fire": true
}
Expand Down
2 changes: 1 addition & 1 deletion docs/skill-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ skill 間の明示的な併用・優先関係は [docs/skill-dependency-map.md](
| `cmd-create-pr` | GitHub Pull Request を安全な手順で作成または更新する。 | PR 作成、PR 提出、pull request 作成を依頼されたとき。差分確認、検証、commit、role-reviewer による PR 前レビュー、High 指摘の自動対応、grape push、PR description 作成、gh pr create / edit の順序を整理する。 |
| `cmd-dispatch-agent` | 指定された agent を起動し、結果を待たずにタスクを投げる。 | ユーザーが agent 起動、worker への委譲、投げっぱなし実行を明示したとき。明示がなくても、単純で不明瞭な点がない自己完結タスクを任せたいとき。 |
| `cmd-rmbranch` | `main` と `develop` を残し、不要なローカルブランチを安全に削除する。 | ローカルブランチ整理を依頼されたとき。未マージブランチは確認してから扱う。 |
| `cmd-start-branch` | 最新のデフォルトブランチから作業ブランチを作り、不要ブランチ整理を非同期に依頼する。 | 新しい作業を始める前に「ブランチ切って」「作業開始用ブランチを作って」などを依頼されたとき。ブランチ名を報告してタスク詳細を待つ。 |
| `cmd-start-branch` | 最新のデフォルトブランチから許可された prefix の作業ブランチを作り、不要ブランチ整理を非同期に依頼する。 | 新しい作業を始める前に「ブランチ切って」「作業開始用ブランチを作って」などを依頼されたとき。ブランチ名を報告してタスク詳細を待つ。 |
| `beautify-commit` | ベースブランチまたは基準 commit との差分を、意味のある変更単位の commit へ安全に整理する。 | commit 分割、履歴整理、大きすぎる差分の再 commit、ベースブランチや commit hash を基準にした差分整理を依頼されたとき。interactive rebase が必要な整理は grape の対応まで実行しない。 |
| `ci-fix` | GitHub Actions / CI の失敗を調査し、原因切り分けから修正、再検証まで進める。 | CI、GitHub Actions、checks、workflow、test / lint / build failure の修正を依頼されたとき。 |
| `code-refactor` | 挙動を変えずにコードを簡略化、リファクタリングする。 | レビュー指摘、quality report、diff、指定ファイルをもとに可読性、保守性、テスト容易性を改善するとき。 |
Expand Down
2 changes: 1 addition & 1 deletion external-skills.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
{
"name": "grilling",
"url": "https://github.com/mattpocock/skills/blob/main/skills/productivity/grilling/SKILL.md",
"url": "https://github.com/mattpocock/skills/blob/697d4ce9742da558fd1ba6697c8e9775e2e302dd/skills/productivity/grilling/SKILL.md",
"type": "git",
"treeHash": "10b0db61f9b3869243db8a1a0ee84f862139b94e",
"destination": [
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ make build-deploy
]
```

`type` は現在 `git` のみ対応します。`url` は `https://github.com/<owner>/<repo>/tree/<ref>/<path>` 形式、または `https://github.com/<owner>/<repo>/blob/<ref>/<path>/SKILL.md` 形式を受け付けます。`treeHash` は必須で、`url` が指す skill ディレクトリの Git tree hash と照合する 40 文字の hex hash を指定します。dry-run でも取得、tree hash 照合、`SKILL.md` の存在確認を行うため、URL が不正、取得できない、tree hash が一致しない、または取得先に `SKILL.md` がない場合はエラーになります。
`type` は現在 `git` のみ対応します。`url` は `https://github.com/<owner>/<repo>/tree/<ref>/<path>` 形式、または `https://github.com/<owner>/<repo>/blob/<ref>/<path>/SKILL.md` 形式を受け付けます。`<ref>` には branch、tag、40 文字の commit SHA を指定できます。`treeHash` は必須で、`url` が指す skill ディレクトリの Git tree hash と照合する 40 文字の hex hash を指定します。dry-run でも取得、tree hash 照合、`SKILL.md` の存在確認を行うため、URL が不正、取得できない、tree hash が一致しない、または取得先に `SKILL.md` がない場合はエラーになります。

対象ディレクトリの tree hash は次のように確認できます。

Expand Down
18 changes: 17 additions & 1 deletion scripts/deploy/internal/external/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ func (f GitFetcher) Fetch(skill Skill, workDir string) (string, error) {

repoDir := filepath.Join(workDir, safePathName(skill.Name))
cloneURL := fmt.Sprintf("https://github.com/%s/%s.git", skillURL.owner, skillURL.repo)
if _, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--branch", skillURL.ref, cloneURL, repoDir); err != nil {
if err := f.clone(skillURL.ref, cloneURL, repoDir); err != nil {
return "", err
}
if err := f.verifyTreeHash(skill, skillURL, repoDir); err != nil {
Expand All @@ -266,6 +266,22 @@ func (f GitFetcher) Fetch(skill Skill, workDir string) (string, error) {
return filepath.Join(repoDir, filepath.FromSlash(skillURL.path)), nil
}

func (f GitFetcher) clone(ref, cloneURL, repoDir string) error {
if !gitObjectHashPattern.MatchString(ref) {
_, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--branch", ref, cloneURL, repoDir)
return err
}

if _, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--no-checkout", cloneURL, repoDir); err != nil {
return err
}
if _, err := f.run("-C", repoDir, "fetch", "--depth", "1", "origin", ref); err != nil {
return err
}
_, err := f.run("-C", repoDir, "checkout", "--detach", "FETCH_HEAD")
return err
}

func (f GitFetcher) verifyTreeHash(skill Skill, skillURL githubSkillURL, repoDir string) error {
actual, err := f.run("-C", repoDir, "rev-parse", "HEAD:"+skillURL.path)
if err != nil {
Expand Down
29 changes: 29 additions & 0 deletions scripts/deploy/internal/external/external_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,35 @@ func TestGitFetcherFetchUsesParentDirectoryForSkillBlobURL(t *testing.T) {
}
}

func TestGitFetcherFetchChecksOutCommitRef(t *testing.T) {
var calls []string
skill := testSkill("grilling")
skill.URL = "https://github.com/owner/repo/blob/697d4ce9742da558fd1ba6697c8e9775e2e302dd/skills/productivity/grilling/SKILL.md"
fetcher := GitFetcher{runGit: func(args ...string) (string, error) {
calls = append(calls, strings.Join(args, " "))
if isRevParseTree(args, "skills/productivity/grilling") {
return testTreeHash + "\n", nil
}
return "", nil
}}

if _, err := fetcher.Fetch(skill, t.TempDir()); err != nil {
t.Fatal(err)
}
if len(calls) != 5 {
t.Fatalf("expected clone, fetch, checkout, rev-parse, sparse-checkout calls, got %v", calls)
}
if !strings.Contains(calls[0], "--no-checkout") || strings.Contains(calls[0], "--branch") {
t.Fatalf("commit ref clone should not use --branch: %v", calls)
}
if !strings.HasSuffix(calls[1], "fetch --depth 1 origin 697d4ce9742da558fd1ba6697c8e9775e2e302dd") {
t.Fatalf("unexpected commit fetch call: %v", calls)
}
if !strings.HasSuffix(calls[2], "checkout --detach FETCH_HEAD") {
t.Fatalf("unexpected commit checkout call: %v", calls)
}
}

func TestGitFetcherFetchRejectsTreeHashMismatch(t *testing.T) {
actual := "abcdef0123456789abcdef0123456789abcdef01"
fetcher := GitFetcher{runGit: func(args ...string) (string, error) {
Expand Down
Loading