Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cursor SDKで構築した開発ワークフロー

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Cursor SDKで構築した開発ワークフロー

Cursor SDK で構築したワークフローを構築し、1ヶ月運用して得られた知見などの共有

Avatar for kaz toc

kaz toc

June 12, 2026

More Decks by kaz toc

Other Decks in Technology

Transcript

  1. Cursor SDK で構築した 開発workflow 運用の顛末 Osaka — Cursor SDK LT

    ZOE合同会社 栃本和宏 2026-06-10 大阪 / Cursor SDK で workflow を組んで 1 か月運用して見えた 改善点・教訓を local runtime 前提で共有 1
  2. Cursor SDKとは 2026-04-29 公開。 @cursor/sdk で Cursor の agent runtime

    をコードから呼 べる。 公式説明では、Desktop / CLI / Web と同じ harness を TypeScript から 使える 実行先は 2 系統 local : 手元の repo を cwd にして動かす cloud : Cursor の専用 VM 上で動かす 今回共有するのは local で組んだ workflow の運用知見 出典: Cursor 公式ブログ「Build programmatic agents with the Cursor SDK」 3
  3. 構築したワークフロー 一言でいうと GitHub Issue 由来で用意した spec Markdown を入力にして、plan → implement

    → review → verify → report を local runtime で一気通貫に回す workflow を作っ た。 入力 GitHub Issue を元に整えた spec Markdown( --spec ) 必要に応じて PR 文脈も参照 worktree 上のローカル repo 出力 実装されたソースコード(repo 内 の通常ファイル) 各 phase の記録ファイル(後述の artifact フォルダ) プラン・最終レポート ( .cursor/issue-workflow/ 6
  4. workflow 全体像 1 仕様入力 ↓ 2 スナップショット作成 ↓ 3 worktree

    検証 ↓ 4 複雑度判定 ↓ 5 計画作成 6 実装 ↓ 7 レビュー ↓ 8 並列検証 ↓ 9 レポート作成 ↓ 10 成果物化 対象 spec を固定 1 run 分の記録フォルダを作る 編集先と状態を確認 軽量か通常経路かを決める 実装方針を固める 仕様に沿って変更する 合否を機械判定する lint / test / typecheck checkpoint を更新 必要なら PR まで進める 7
  5. 補足: artifact(成果物フォルダ)とは? artifact = workflow を 1 回回すたびに作る記録用フォルダ。 エージェントが書き換えたアプリのコードそのものではなく、 「その

    run で何が起きた か」を残すためのファイル群。 入るもの(例) spec.snapshot.md — 入力 spec のコピー plan-review.md — レビュー文 と *_DECISION 行 verify-attempt-1.md — lint / test のログ workflow-checkpoint.json — 置き場所・性質 既定: .cursor/issue- workflow/sdk-spec-workflow-< 実行時刻>/ プラン・レポートは同階層の sdk- spec-plan-*.md 等 .gitignore 済み → ローカルの 作業ログ 8
  6. Step 2: スナップショット作成 ここでやること この run 専用の artifact フォルダを作成し、パスを固定する 入力

    spec を spec.snapshot.md としてフォルダ内にコピーする resume 時は同じフォルダを開き、スナップショットと元 spec が一致するか 確認する 概要 この step は「準備」ではなく、以後の判断基準を固定する step ここを曖昧にすると、resume 時に別 spec を読んでしまう local workflow では最初の入力固定がかなり重要だった 単に「spec をコピーする」だけではなく、以後の全 step が同じ spec を見るための固定点になっている。 根拠: core/workflow-core.ts の initializeContext 9
  7. Step 3: worktree 検証 ここでやること 今いる場所が main clone ではなく、想定した worktree

    かを先に止める branch / path / marker を突き合わせ、ズレたら即失敗にする 「作った worktree」と「今開いている workspace」が一致するかを見る 概要 worktree を作るだけでは事故は防げなかった local.cwd 依存の編集先ズレは、preflight で締める必要があった local runtime の安全性は SDK ではなく周辺設計で担保した 根拠: core/preflight.ts 。単なる yes/no 判定ではなく、失敗理由も残す。 10
  8. Step 4: 複雑度判定 ここでやること この spec を軽量経路で回せるか、重い経路で回すべきかを先に決める 判定結果で plan を省略するか、通常どおり作るかを分ける

    workflow 全体のコスト配分をここで調整する 概要 判定が壊れても workflow は止めず、安全側の重い経路へ倒す 軽量化の判定は便利だが、壊れたときに軽量側へ倒さないのが重要だった 省略の判断ほど、保守的に扱った方が安定した 根拠: core/complexity-assess.ts 。壊れたら軽量側へは倒さない。 11
  9. Step 10: 成果物化 ここでやること report、checkpoint、差分証跡を残して、人が引き取れる状態にする verify が通ったあとも、最後に「何が起きたか」を成果物化する 必要なら PR 作成までつなぐ

    概要 workflow の出口は「実装完了」ではなく「扱える成果物」だった 自動 commit / PR も入れたが、危険ファイルは止める前提にした 最後の step は便利機能というより、引き渡し設計の話 根拠: core/workflow-core.ts , core/report.ts , core/post-success-pr.ts 。 この step は人に返せる形で終わらせるための出口。 12
  10. 技術仕様 項目 値 補足 @cursor/sdk 1.0.12 vendor/cursor-sdk-spec-workflow で使用 Node.js 22.17.0

    repo の Volta pin。 engines は >=22 TypeScript 5.7.3 workflow package 側の固定 version workflow package cursor-sdk-spec- [email protected] vendor 配下に内包 実行入口 pnpm cursor:sdk:spec- workflow 実体は scripts/run-sdk-spec- workflow.sh 前提だけ補足すると、 worktree 必須、verify は lint / typecheck / test を並列実行。 各 phase のレビュー文・検証ログ・checkpoint は artifact フォルダに、プランと最終レポートは .cursor/issue- workflow/ に保存する。 13
  11. 設計上の留意点1 ループをどこに置くかを先に決める この workflow で置いたループ plan review が落ちたときだけ、phase1 で plan

    修正ループを回す 実装後は scope completion / review / verify で別々に戻し先を持つ どこでも同じ prompt を再実行するのではなく、戻す phase を固定する 主眼 仕様解釈の修正は実装前に閉じる 品質修正は review / verify の後段で閉じる 無人運用では「どこへ戻すか」を曖昧にしない方が安定した 15
  12. 設計上の留意点2 何回まで許容するかを固定する 制御点 この実装の既定値 意図 SDK 呼び出し retry 3 回まで

    一時的な通信揺らぎだけを少数回だけ救う plan re-review loop standard は 1 回、 thorough は 2 回 実装前の仕様修正を無限にしない verify fix loop 2 回まで テスト修正は回すが、直らなければ失敗と して残す 根拠: core/params.ts , core/workflow-core.ts 。 「とりあえず何度でもやり直す」より、直る見込みが高いものだけ少数回に制限する方が扱いやすかった。 16
  13. 設計上の留意点3 retry / diagnostics / resume を混ぜない 分けたもの 一時エラーは retry

    run.wait() が finished 以外 で終わったら diagnostics を残 す 途中再開は checkpoint から resume 主眼 再試行すべき失敗と、調べるべき失 敗は別 resume は retry の延長ではな く、phase 再開の設計 失敗の種類ごとに出口を分けた方が 保守しやすい 17
  14. 設計上の留意点まとめ 検討項目 考慮しないとどうなるか loop を置く phase 実装前の仕様修正と、実装後の品質修正が混ざり、どこへ戻すべき かが曖昧になる retry /

    fix の打ち切り回数 直る見込みが低い失敗まで回し続け、長時間化した末に失敗理由も ぼやけやすい retry / diagnostics / resume の境界 再試行すべき失敗と調査すべき失敗が混ざり、障害時の次の一手を 決めにくくなる plan 省略や軽量化の条件 判定が壊れたときに軽量側へ倒れ、確認不足のまま後続 phase が 進みやすくなる 18
  15. 運用上のポイント1 通信揺らぎと実行崩壊を分けて扱う 症状 / 根本原因 models.list や step 実行が一 時的な通信揺らぎで失敗する

    run.wait() が finished 以外 を返し、そのままだと何が起きたか 分からない 「ネットワーク断」と「agent 実行 崩壊」が同じ失敗に見えていた 対策 / 教訓 retry 可能なエラーだけ指数バック オフで再試行 run.wait() 異常は JSON diagnostics を artifact フォルダ に保存 通信揺らぎへの retry と、 run.wait() 異常時の診断を分け て設計する 20
  16. 技術ポイント: 失敗を 1 種類として扱わない このスライドで言いたいこと 「失敗したらとりあえずリトライ」では足りない。 どの種類の失敗かで、やるべき対処を分ける必要がある。 何が起きたか どう対処するか 具体例

    一時的な通信揺らぎ retry models.list 失敗、接続 timeout run.wait() が finished 以 外で終わる diagnostics を 残す SDK 実行の状態を JSON で残す 途中で落ちて続きからやりたい resume 前回の artifact フォルダを指定して -- resume-from この 3 つを同じ「エラー処理」にまとめると、障害時に何をすべきかが曖昧になる。 local workflow では、再試行する失敗と調べるべき失敗と再開すべき失敗を分けた方が運用しやすかった。 21
  17. 運用上のポイント2 編集先の誤りをどう防ぐか 症状 / 根本原因 worktree を作ったのに、編集が main clone 側へ入る事故が起きた

    local.cwd は「今開いている workspace」に依存する 緊急回避フラグで preflight をバイ パスできる経路もあった 対策 / 教訓 git-dir != git-common-dir 、 marker、basename で多重チェッ ク shell 実行前フックと sessionStart でも警告 worktree 作成と workspace 切替 を別問題として扱う 22
  18. 技術ポイント: local.cwd だけでは安全ではない worktree を作った と その worktree を開いている は別

    だから cwd だけではなく、 preflight shell hook sessionStart reminder の三重で縛った local runtime は便利だが、編集先保証は SDK 任せにしない方がよい。 23
  19. 運用上のポイント3 失敗原因を追える状態を残す 症状 / 根本原因 以前は「失敗した」という事実しか 残らなかった phase 失敗、wait 異常、preflight

    失敗が同じ見え方だった 対策 / 教訓 bootstrap failure report と workflow failure report を分離 wait 異常は専用 JSON を出力 失敗の種類ごとに artifact 内のフ ァイルを分ける(bootstrap / wait / phase 別) 24
  20. 運用上のポイント4 途中再開を前提に checkpoint を持つ やったこと phase 境界ごとに workflow-checkpoint.json を更新し、 --resume-from

    で再 開できるようにした。 phase2 完了 -> workflow-checkpoint.json -> suggestedResumeFrom: phase3-review resume は「エージェントの会話をそのまま続ける」のではなく、前回と同じ artifact フォルダ(spec スナップショ ット・レビュー結果・checkpoint)を読み直して、指定 phase からやり直す仕組み。 25
  21. Harness とは何か 公式の言い方では、Harness = Cursor のエージェント実行基盤。 Desktop / CLI /

    Web / SDK が同じ中身を共有する。 Harness が担うこと(エンジン側) モデル呼び出しとエージェントループ 索引・grep・セマンティック検索 ファイル編集・シェル等のツール実行 Skills / MCP / Hooks / Subagents local / cloud のruntime 出典: Cursor 公式ブログ — *Use the full Cursor harness* 31
  22. SDK と Harness — レイヤー Cursor SDK = Harness を起動・監視する

    API。 Cursor Harness = エージェントを動かす実行エンジン。 SDK は別物ではなく、同じ Harness へのリモコンに近い。 ┌──────────────────────────────────┐ │ workflow(phase・ゲート・resume) │ └───────────────┬──────────────────┘ │ create / send / wait ┌───────────────▼──────────────────┐ │ Cursor SDK(@cursor/sdk) │ └───────────────┬──────────────────┘ │ ┌───────────────▼──────────────────┐ │ Cursor Harness(共通 runtime) │ │ モデル・ツール・Skills・MCP 等 │ └──────────────────────────────────┘ IDE チャットも agent.send() も、下では同じ Harness。 32
  23. Harness が SDK 経由でも効くもの 仕組み Harness 側 SDK から Skills

    .cursor/skills/ cwd の repo から読込 MCP .cursor/mcp.json inline で上書き可 Hooks .cursor/hooks.json ファイル管理(API なし) Subagents .cursor/agents/ Agent ツールで委任 Models frontier モデル群 model.id で切替 今回の workflow で体感したこと .cursor/skills/ や Hooks は SDK local でもそのまま効いた Harness が自動ではやらないのは phase 順・打ち切り・worktree 安全 Harness = 1 回の agent 実行、workflow = その外側 SDK 公式: *same harness that powers Cursor across desktop, CLI, and web app* 33
  24. ソースコード cursor-sdk-spec-workflow 今回紹介した workflow の実装本体(TypeScript / @cursor/sdk ) https://github.com/zoe-llc/cursor-sdk-spec-workflow 項目

    値 コード数 TypeScript 6,734 行(本体) / 9,060 行(テスト含む) ファイル数 40( .git 除く) フォルダ構成 cursor-sdk-spec-workflow/ ├── core/ … phase 実行・verify・preflight 等 ├── shared/ … retry / env 等 ├── __tests__/ … Jest ├── test-fixtures/ ├── .cursor/skills/ … Agent Skill ├── index.ts … エントリ └── connection-check.ts 34