crowi-feature

star 1.1k

Crowi 2.0 の新機能開発ワークフロー。設計合意 (会話で詰めた spec) を起点に、 spec → planner → implementer → simplify → reviewer → committer まで自動で進める。 キーワード: feature, 新機能, 開発, build, 設計, spec

crowi By crowi schedule Updated 6/7/2026

name: crowi-feature description: | Crowi 2.0 の新機能開発ワークフロー。設計合意 (会話で詰めた spec) を起点に、 spec → planner → implementer → simplify → reviewer → committer まで自動で進める。 キーワード: feature, 新機能, 開発, build, 設計, spec globs: - "packages/api/src/hono/handlers/" - "packages/web/src/app/" - "packages/api-contract/src/**"

Crowi 2.0 Feature Skill

新規機能をゼロから追加するためのワークフロー。 旧実装互換が前提の crowi-migration と並列の skill。設計を会話で詰めた後 に 起動して自動進行させるのが想定パターン。

想定ユースケース

  • 新規 API エンドポイントの追加 (旧実装が無い)
  • 新しい admin 画面 / ユーザー画面の追加
  • 既存機能への大きめの拡張 (旧実装と挙動が変わる)
  • ライブラリ・ツール導入を伴う機能

旧 Express/Swig コードからの移植は crowi-migration を使う。

ワークフロー全体像

   ↓ 会話で設計を詰める (壁打ち)
   ↓ ユーザー: 「これで実装!」
   ↓
/feature {name}
   ↓
[spec phase]
   spec.md があれば: そのまま使う
   なければ: 直近会話を要約して .feature-state/specs/{name}.md を生成 → ユーザー確認
   ↓
[scope 判定]
   spec.md の `scope:` (trivial|small|medium|large) で planner を skip するか決める
   trivial / small ≤ minScopeSize: planner skip → implementer 直行
   medium / large >  minScopeSize: planner 起動
   ↓
planner ──→ implementer ──→ simplify ──→ reviewer ─┬→ committer
                ↑                          ↑       │
                └─────── NEEDS_WORK ───────┴───────┘

各 phase の責務:

  • planner: spec を読み、コードベースを grep して再利用候補 (hooks / components / utils / 既存契約) を context に充填、AC を spec から起こす
  • implementer: 実装 + テスト、必須チェック (type-check / test / lint / format) を全部走らせる、commitPlan を埋める
  • simplify: simplify skill を呼び、reuse / quality / efficiency を整える
  • reviewer: AC 達成 / 契約整合 / セキュリティ / トランザクション境界を確認
  • committer: task.commitPlan に従って 複数 commit を作る (feat 本体 / test / docs を分割)

state 管理

ディレクトリ: .feature-state/ (リポジトリ root).claude/feature-state/ ではない gitignore 済み (.gitkeep のみ tracked)。

.feature-state/
├── config.json             # 静的 config(SHARED, read-mostly)
├── specs/
│   └── {id}.md            # 設計仕様(SHARED, per-id)
├── tasks/
│   └── {id}.json          # planner が埋めた context + AC + commitPlan + status(SHARED, per-id)
└── queue.json              # currentTask 等(PER-WORKTREE, volatile)※共有しない

共有 / per-worktree の線引き(並列 worktree 安全性)

gw worktree は ~/.gw/hooks/feature-state-link.shspecs/ tasks/ config.json だけ を MAIN worktree に symlink 共有する。queue.json は worktree ローカル(共有しない)。理由:

  • specs/ tasks/per-id ファイル。並列 worktree は別々の id を触るので 共有して安全(むしろ「ある worktree で起こした spec を全 worktree から見たい」)。
  • config.json は静的(実行時に書き換えない)read-only なので共有して安全。
  • queue.jsoncurrentTask「この worktree が今やっているタスク」= 単一 ポインタ。これを共有すると、並列 /feature 実行が互いの currentTask を 上書きして壊れる。だから per-worktree に分離する。

1 worktree = 1 タスク(= 1 tasks/{id}.json)。currentTask はその worktree ローカルの「今のタスク」。タスク一覧が欲しければ ls tasks/ を見る(集約 しない)。tasks/{id}.json への書き込みは torn write を避けるため tmp+rename で atomic に行う。

config.json スキーマ(SHARED, 静的)

{
  "commitStrategy": "main-direct",
  "maxReviewAttempts": 3,
  "runSimplify": true,
  "minScopeSize": "small"
}

queue.json スキーマ(PER-WORKTREE, volatile)

{
  "currentTask": "feature-attachment-thumbnail",
  "lastUpdated": "2026-05-09T...",
  "lastCompletedTask": "feature-..."
}

minScopeSize(config.json): trivial | small | medium | large spec の scope: がこの閾値より大きい (>) ときだけ planner が起動する。 デフォルト small (= medium 以上で planner、small / trivial は skip)。 順序は trivial < small < medium < large

spec.md スキーマ

---
id: feature-attachment-thumbnail
name: 添付画像のサムネイル生成
scope: medium
---

## 背景 / why
...

## やること (ユーザー視点)
...

## やらないこと (out of scope)
...

## 設計の主な判断
- どこに置くか (API / Web / 共通)
- 依存ライブラリの追加可否
- DB スキーマ変更の有無
- パフォーマンス / セキュリティ上の制約

## 受け入れ基準 (acceptance criteria)
- [ ] ...
- [ ] ...

## 未確定事項 (open questions)
- ...

scope の目安:

  • trivial: 1 ファイル / 50 行未満 / 既存 helper 流用 / テスト不要レベル
  • small: 1〜2 ファイル + テスト / 既存契約を拡張するだけ
  • medium: 新契約 + API + UI / 複数 commit / 数百行
  • large: 新モデル or 新 schema or 外部サービス連携。planner で task 分割を強く検討

Multi-phase spec の扱い

spec 中に ### Phase N: <title> ヘッダが 2 本以上 あれば、その spec は multi-phase として扱う。1 spec = 1 task は変えないが、task.json に phases[] を持たせて phase 単位で plan→impl→simplify→review→commit のサイクルを回し、commit ごとに次の phase に進む。

phase の autoContinue フラグはヘッダの末尾マーカーから自動判定する:

  • ヘッダに 「(即時 / 非衝突)」「(no conflict)」 などの marker → autoContinue: true
  • ヘッダに 「(要調整)」「(needs coordination)」「(blocked by …)」 などの marker → autoContinue: false
  • どちらでもない → autoContinue: true をデフォルト (== 通常はノンストップ)

autoContinue: false な phase に到達したら その phase の commit 直前 で停止し、ユーザーに 「Phase N は要調整。続けるなら /feature feature-xxx --phase=N を起動」と報告する。 autoContinue: true な phase は commit 後そのまま次の phase の plan に進む。

phase 完了 = その phase に紐付くすべての commit が landed。spec の ## 受け入れ基準 を phase ごとに分けて書いてある場合、reviewer は その phase の AC のみ をチェックする。

task ファイルスキーマ (tasks/{id}.json)

{
  "id": "feature-attachment-thumbnail",
  "name": "添付画像のサムネイル生成",
  "status": "PLANNED",
  "scope": "medium",
  "context": {
    "specPath": ".feature-state/specs/feature-attachment-thumbnail.md",
    "reuseTargets": [
      "packages/api/src/util/fileUploader.ts (driver 抽象を再利用)",
      "packages/web/src/components/page-view/AttachmentList.tsx (一覧 UI に組み込み)"
    ],
    "newFiles": [
      "packages/api/src/util/thumbnail.ts (sharp ラッパー)",
      "packages/api-contract/src/contracts/attachment-thumbnail.ts (新契約)"
    ],
    "models": ["packages/api/src/models/attachment.ts (thumbnail フィールド追加)"],
    "newDeps": ["sharp (画像処理)"],
    "architecturalNotes": "Storage driver 経由で生成・保存。同期処理 (アップロード時にブロック)。"
  },
  "acceptanceCriteria": [
    "画像添付時に 320x320 サムネが生成され S3/local 両方で取得できる",
    "非画像 (PDF 等) はサムネ生成をスキップする",
    "失敗してもアップロード自体は成功する"
  ],
  "openQuestions": ["sharp のメモリ上限"],
  "commitPlan": [
    {
      "type": "feat",
      "scope": "api",
      "title": "implement attachment thumbnail generation",
      "files": ["packages/api/src/util/thumbnail.ts", "..."]
    },
    {
      "type": "test",
      "scope": "api",
      "title": "cover thumbnail generation edge cases",
      "files": ["packages/api/src/util/thumbnail.test.ts"]
    },
    {
      "type": "docs",
      "scope": "todo",
      "title": "mark attachment thumbnail done",
      "files": ["TODO.md"]
    }
  ],
  "history": [
    {"phase": "planner", "at": "ISO8601", "summary": "計画完了"}
  ]
}

Multi-phase 版の task スキーマ

multi-phase spec の場合、commitPlan の代わりに phases[] を持つ:

{
  "id": "feature-monorepo-packages-restructure",
  "name": "モノレポ packages の publish 構成大改修",
  "status": "PLANNED",
  "scope": "large",
  "currentPhase": "phase-1",
  "phases": [
    {
      "id": "phase-1",
      "title": "workspace: プロトコル徹底",
      "specSectionAnchor": "### Phase 1: workspace: プロトコル徹底 (即時 / 非衝突)",
      "status": "PLANNED",
      "autoContinue": true,
      "commitPlan": [
        {"type": "refactor", "scope": "deps", "title": "switch all internal deps to workspace:^", "files": ["..."]}
      ],
      "commitShas": []
    },
    {
      "id": "phase-2",
      "title": "peerDependencies 明文化",
      "specSectionAnchor": "### Phase 2: peerDependencies 明文化 (即時 / 非衝突)",
      "status": "PLANNED",
      "autoContinue": true,
      "commitPlan": [...],
      "commitShas": []
    },
    {
      "id": "phase-5",
      "title": "apps/crowi-api → packages/api 移動",
      "specSectionAnchor": "### Phase 5: apps/crowi-api → packages/api 移動 (要調整 / 並行 worktree と衝突可能性あり)",
      "status": "PLANNED",
      "autoContinue": false,
      "commitPlan": [...],
      "commitShas": []
    }
  ],
  "context": { ... },
  "history": [
    {"phase": "planner", "at": "ISO8601", "summary": "9 phases 抽出。Phase 1-4 を autoContinue=true、5-9 を false で初期化"}
  ]
}

phase ごとの status:PLANNED → IN_PROGRESS → REVIEW → (APPROVED → COMMITTED) | NEEDS_WORK。 全 phase が COMMITTED になったら task 全体の status = COMMITTEDqueue.currentTask = null

起動フロー (skill 内手順)

/feature {name} が呼ばれたら以下を実行:

1. spec の準備

1.1. .feature-state/specs/{name}.md の有無を確認
1.2. あれば: そのまま使う (人間レビュー済みとみなして次へ)
1.3. なければ:
     - 直近会話を読み、spec の各セクションを埋めて .feature-state/specs/{name}.md を書き出す
     - scope は会話内容と編集規模見込みから自動判定
     - 「以下の spec で進めますか?」とユーザーに提示し、承認を待つ
     - ユーザーから修正指示があれば反映、再提示
1.4. spec.md の scope を読み取る

2. scope 判定 → planner skip 判定

2.1. config.json の minScopeSize を読む (なければ "small" デフォルト)
2.2. spec.md の scope と比較
     scope ≤ minScopeSize: planner skip
     scope >  minScopeSize: planner 起動
2.3. planner skip の場合は、最小限の task.json を skill 内で生成
     (specPath / acceptanceCriteria / scope を spec から引き写し、
      status は PLANNED で書き出す。implementer はこの初期状態を期待する)

3. agent チェーン

Single-phase (= 通常の small/medium spec)

3.1. planner (起動した場合) が context を充填して REVIEW pending 状態に
3.2. implementer: task.json を読んで実装、commitPlan を埋め、必須チェック後に REVIEW
3.3. simplify (config.runSimplify が true なら): 直近 diff を整理
3.4. reviewer: APPROVED または NEEDS_WORK
3.5. NEEDS_WORK なら implementer に戻す (最大 maxReviewAttempts 回)
3.6. APPROVED → committer が commitPlan に従って複数 commit
3.7. task.status = COMMITTED → step 4 (完了報告)

Multi-phase (spec に ### Phase N: が 2 本以上)

3.0. planner が spec から phases[] を抽出して task.json に書き込む (1 回だけ)
3.1. task.json から最初の PLANNED な phase を pick → currentPhase に
3.2. その phase に対して 3.1〜3.6 (single-phase と同じサイクル) を回す
     commitPlan / acceptanceCriteria は phase ローカルのものを使う
3.3. phase.status = COMMITTED に更新、currentPhase は次の PLANNED な phase に
3.4. 次の phase の autoContinue を判定:
     - true → 3.1 (loop)
     - false → 停止 + 報告: 「Phase N (タイトル) は要調整。続けるなら
       `/feature {name} --phase=N` を起動」
     - 次 phase なし (全 phase COMMITTED) → task.status = COMMITTED、step 4

--phase=N で個別 phase を resume:

  • 既存 task.json を読み、phase-N を currentPhase にセット
  • 通常のサイクル (3.2) を回す
  • 完了したら 3.3〜3.4 (autoContinue 判定) を辿る

連続実行ルール (最重要)

spec phase でユーザー承認を取った後 (= skill 起動時の 唯一 の承認ポイント) は、 task.status = COMMITTED になるまで一度も止まらない。各 phase 完了 = 次 phase の即時起動。 ユーザー確認を取らない。phase 出力が「次に進める状態です」「ready to proceed」「次は ◯◯ です」 等の予告で終わったら その同じ assistant turn 内で必ず次 phase を起動する — 予告だけで turn を 締めることは禁止。

各 phase の出口で必ずやるアクション (条件分岐なし、phase 出力の文字列に依存しない):

完了 phase 次に必ず起動するもの
planner implementer
implementer (必須チェック pass、status=REVIEW) simplify (config.runSimplify=true) → reviewer
simplify reviewer を即起動 ("進める状態です" 等の予告で停止禁止)
reviewer (APPROVED) committer を即起動 ("review APPROVED した、commit する" 等の予告で停止禁止)
reviewer (NEEDS_WORK, attempts < max) implementer に戻す
reviewer (NEEDS_WORK, attempts == max) 停止 + human escalation
committer (SUCCESS) — single-phase step 4 (完了報告)
committer (SUCCESS) — multi-phase、次 phase あり、autoContinue=true 次 phase の planner / implementer を即起動 (停止禁止)
committer (SUCCESS) — multi-phase、次 phase あり、autoContinue=false 停止 + 報告 (gated phase)
committer (SUCCESS) — multi-phase、次 phase なし task.status = COMMITTED → step 4

simplify が "now invoke reviewer" と書いたら起動する」のようなマジック文字列ハンドシェイクは 禁止。phase の status / 戻り値 (成功・失敗・NEEDS_WORK) だけを判断材料にする。

停止が許される条件 (これ以外で turn を終えることは禁止)

  1. NEEDS_WORK が maxReviewAttempts 回連続 → human escalation
  2. 必須チェックの失敗 (type-check / test / lint / format / pre-commit hook) → 停止して報告
  3. commitPlan ⇄ diff の不整合 が committer 段階で解消できないとき → 停止して報告
  4. agent からの明示的な escalate 要求 (例: spec 読解で曖昧、設計判断が必要、外部 secret 要求)
  5. (multi-phase only) 次 phase の autoContinue: false — gated phase 直前。 "Phase N は要調整、続けるなら --phase=N で起動" を報告して停止。

言い回しチェックリスト (turn を締める前に必ず確認)

  • ❌ 「task は REVIEW ステータス。reviewer phase に進める状態です」 → reviewer 未起動なので NG
  • ❌ 「simplify 完了。次は reviewer です」 → 予告だけ、起動してない
  • ❌ 「ready for review / ready to commit」 → 同上
  • ✅ reviewer の Agent / Skill 呼び出しが 同じ turn 内 に発火している
  • ✅ committer の commit コマンドが 同じ turn 内 に発火している
  • ✅ 上の停止条件 1-4 のいずれかが明示的に該当している

4. 完了

task.status = COMMITTEDqueue.currentTask = null。 committer は実装完了済み spec (.feature-state/specs/{id}.md) を 削除する (残 phase / 残タスクが無く task 全体が COMMITTED のときだけ。multi-phase で未完 phase が残る / PARTIALLY_COMMITTED のときは保持)。詳細は feature-committer の「spec の後始末」。 push / PR 作成は 明示指示があるまで行わない

ステータス遷移

PLANNED → IN_PROGRESS → REVIEW → (APPROVED → COMMITTED) | NEEDS_WORK → IN_PROGRESS → ...

サブコマンド (個別 phase 起動)

/feature {name}                # 全自動 (会話前提)
/feature {name} --phase=N      # multi-phase spec の Phase N から resume (gated phase 通過用)
/feature plan {name}           # planner だけ
/feature implement {id}        # implementer だけ (NEEDS_WORK / IN_PROGRESS のとき)
/feature review {id}           # reviewer だけ (REVIEW のとき)
/feature commit {id}           # committer だけ (APPROVED のとき)

--phase=N は task.json の phases[] から phase-N を pick して currentPhase にセットし、 通常のサイクル (3.2) に入る。autoContinue 判定は通常通り走る ので、N から最後まで auto-continue が連続していれば一気に最後まで進む。

migration skill と同じパターン。

migration skill との違い (まとめ)

観点 migration feature
起点 旧 Express/Swig コード 会話で詰めた spec.md
context 充填 旧実装場所を grep 再利用候補を grep + spec を引き写し
互換性制約 旧実装と挙動一致が最優先 なし (新規)
reviewer 観点 旧実装互換 AC 達成 + 設計合意整合
commit 単位 1 タスク = 1 commit 1 タスク = N commit (commitPlan による分割)

重要な前提

  • state ディレクトリは .feature-state/ (root).claude/feature-state/ ではない
  • main 直コミット運用 がデフォルト (config.json commitStrategy: main-direct)
  • 認証が要るエンドポイントは Hono の認証ミドルウェア (createJwtAuth(crowi)) 配下に置く。CSRF 不要
  • 新契約は packages/api-contract/src/contracts/{feature}.ts に追加、build 必須 (pnpm --filter @crowi/api-contract build)
  • 新 UI は packages/web/src/app/(auth or admin)/... 配下、shadcn/ui + tanstack/react-query

Crowi テーマ

--crowi-primary: #43676b;
--crowi-header: #263a3c;
--crowi-sidebar: #f8f9fa;
Install via CLI
npx skills add https://github.com/crowi/crowi --skill crowi-feature
Repository Details
star Stars 1,098
call_split Forks 165
navigation Branch main
article Path SKILL.md
More from Creator