[{"data":1,"prerenderedAt":6496},["ShallowReactive",2],{"category-data-テック解説":3},[4,4177],{"id":5,"title":6,"body":7,"description":4163,"extension":4164,"meta":4165,"navigation":431,"ogImage":4167,"path":4173,"seo":4174,"stem":4175,"__hash__":4176},"content/blogs/15-ai-agent-organization-1000-hours.md","AIエージェントを「組織」として回す設計思想：12体のサブエージェントとNeon × Prismaタスクボードで作る一人会社のアーキテクチャ | Running AI Agents as an Organization: A 12-Subagent, Neon-Backed Postgres Task Board Architecture for a One-Person Company",{"type":8,"value":9,"toc":4116},"minimark",[10,2194,2196,4112],[11,12,14,19,39,46,49,54,130,132,136,139,142,148,157,163,170,172,176,179,246,253,255,259,266,276,299,317,327,345,347,351,362,367,370,480,483,487,490,542,545,549,559,818,825,829,832,835,837,841,852,926,929,935,942,944,947,950,1126,1133,1135,1139,1154,1452,1455,1594,1605,1717,1727,1729,1733,1742,1748,1758,1763,1787,1794,1796,1800,1807,1812,1834,1839,1879,1884,1920,1930,1956,1963,1965,1969,1972,1976,1987,1991,1998,2009,2013,2020,2027,2029,2033,2036,2042,2060,2089,2095,2121,2123,2126,2129,2163,2170,2181,2183],"lang-block",{"lang":13},"ja",[15,16,18],"h1",{"id":17},"aiエージェントを組織として回す設計思想12体のサブエージェントとneon-prismaタスクボードで作る一人会社のアーキテクチャ","AIエージェントを「組織」として回す設計思想：12体のサブエージェントとNeon × Prismaタスクボードで作る一人会社のアーキテクチャ",[20,21,22],"blockquote",{},[23,24,25,29,30,33,34,38],"p",{},[26,27,28],"strong",{},"バージョン注記",": 本記事は2026年5月時点の運用ログを基にしている。Claude Code v2系、Claude Sonnet 4.6 / Haiku 4.5、Next.js 14・Prisma 5・",[26,31,32],{},"Neon serverless Postgres + pgvector 0.7","、Vercel runtime を前提としている。",[35,36,37],"code",{},".claude/agents/"," のサブエージェント機能と SessionStart / PreToolUse の2つのフックを使う構成だ。モデル仕様、Claude Code のフック仕様、Neon の料金プランは変動するので、最新は公式ドキュメントを参照してほしい。",[23,40,41,42,45],{},"私はもともと半導体プロセス開発のエンジニアで、その後CVCのキャピタリストに転身した。投資チームに加わって最初にぶつかったのは「DDの品質基準が人によってバラバラ」という問題で、これを3ヶ月で標準化したときに痛感したのは「品質は個人の頑張りではなく仕組みで担保するもの」という当たり前の事実だ。",[26,43,44],{},"この同じ実感が、Claude Code のサブエージェントを 500 時間ぶん回した結果、ほぼそのまま再現された。"," 今回はその運用設計を、コード・スキーマ・Neon の活用箇所まで隠さずに書く。",[47,48],"hr",{},[50,51,53],"h2",{"id":52},"tldrこの記事でわかること","TL;DR：この記事でわかること",[55,56,57,70],"table",{},[58,59,60],"thead",{},[61,62,63,67],"tr",{},[64,65,66],"th",{},"テーマ",[64,68,69],{},"学べること",[71,72,73,82,90,98,114,122],"tbody",{},[61,74,75,79],{},[76,77,78],"td",{},"一人AI vs 組織化AI",[76,80,81],{},"なぜチャット1画面の運用には天井が来るのか、構造的な3つの理由",[61,83,84,87],{},[76,85,86],{},"組織の4要素",[76,88,89],{},"投資チーム運営から借りた「専門化・レビュー・書き物・責任明示」のサブエージェントへの応用",[61,91,92,95],{},[76,93,94],{},"12体の役割分担",[76,96,97],{},"Leadership / Engineering / Quality / Content・Strategy・Legal の4グループの境界",[61,99,100,103],{},[76,101,102],{},"実装スタック",[76,104,105,106,109,110,113],{},"Next.js + Prisma + ",[26,107,108],{},"Neon（serverless Postgres + pgvector）"," + ",[35,111,112],{},"pnpm task"," CLI + knowledge/ Obsidian互換vault",[61,115,116,119],{},[76,117,118],{},"Neon活用の核",[76,120,121],{},"ブランチでDBレベルのgit、PITRでInbox削除事件の保険、pgvectorで意味検索、suspend-on-idleで24/7運用の経済成立",[61,123,124,127],{},[76,125,126],{},"落とし穴",[76,128,129],{},"Inboxノートを勝手に削除された事故と、Decision Boundariesによる回避策、Vercel + Neon でのコネクション管理",[47,131],{},[50,133,135],{"id":134},"一つのaiに全部やらせる運用の天井","一つのAIに全部やらせる運用の天井",[23,137,138],{},"最初に断っておくと、AIエージェントの議論はいまだに**「もっと賢いモデルが出れば解決する」という発想に引きずられすぎている**ように見える。Claudeがいい、いやGPTのほうが、Codexのコーディング性能が——という比較は健全だが、その全部が「一つのAIに全部やらせる」前提で語られている点に問題がある。",[23,140,141],{},"実際に私が1日6時間以上、3ヶ月にわたってClaude Codeをぶん回した結果、この前提には3つの構造的な天井が見えた。",[23,143,144,147],{},[26,145,146],{},"1. 文脈が混ざると出力がブレる。"," プロジェクトAの仕様、クライアントBの要件、先週の会議メモ、今日の買い物リストを同じセッションに突っ込むと、関係ない情報がノイズとなって回答が歪む。これは半導体プロセスのTCADシミュレーションで「境界条件を一つ間違えるだけで結果が桁単位でズレる」のと構造的に同じだ。",[23,149,150,153,154],{},[26,151,152],{},"2. ハルシネーションが増える。"," 文脈が散らかっていると、AIは「先週こう決まりましたよね」と決まってもいないことを断言する。投資先のDDで現場担当者が「装置の問題」と自信満々に報告してきた収率不良が、実はTCADで再シミュレーションすると製造プロセス側の境界条件にあった、というのと似ている。",[26,155,156],{},"自信満々の誤報告は、複数のレンズを通さないと検出できない。",[23,158,159,162],{},[26,160,161],{},"3. レビュアーがいない。"," 一つのAIだけだと、出力をチェックする責任は人間（=私）一人に集中する。プロンプトを書き、結果を読み、判断する——これは投資委員会を経ない単独投資判断と同じで、まともな現場ではあり得ない動かし方だ。Googleでもどこのまともな現場でも、デザインレビュー・コードレビュー・ローンチレビューがあって、品質は仕組みで担保されている。",[23,164,165,166,169],{},"問題は、",[26,167,168],{},"この3つを「組織化」で同時に解く方法","が、まだあまり共有されていないことだ。",[47,171],{},[50,173,175],{"id":174},"投資チーム運営から借りた組織の4要素","投資チーム運営から借りた「組織の4要素」",[23,177,178],{},"私が3ヶ月で投資チームのDD標準化を回したとき、出来上がった仕組みには4つの柱があった。これがそのまま、Claude Codeサブエージェントの組織設計に転用できると気づいた瞬間が、この運用の起点になっている。",[55,180,181,194],{},[58,182,183],{},[61,184,185,188,191],{},[64,186,187],{},"要素",[64,189,190],{},"投資チームでの実装",[64,192,193],{},"サブエージェントでの実装",[71,195,196,207,218,232],{},[61,197,198,201,204],{},[76,199,200],{},"専門化",[76,202,203],{},"市場/技術/財務/法務でDD領域を分担",[76,205,206],{},"12体を4グループに分割（後述）",[61,208,209,212,215],{},[76,210,211],{},"レビュー文化",[76,213,214],{},"投資委員会で複数のレンズを通す",[76,216,217],{},"qa-reviewer / brand-voice-reviewer / anti-ai-slop-reviewer の三段レビュー",[61,219,220,223,226],{},[76,221,222],{},"書き物で引き継ぐ",[76,224,225],{},"投資メモ・ADR・PRD",[76,227,228,231],{},[35,229,230],{},"knowledge/handoffs/"," への必須ハンドオフノート",[61,233,234,237,240],{},[76,235,236],{},"責任の所在を明示",[76,238,239],{},"担当者裁量 / マネージャー裁量 / 委員会裁量",[76,241,242,245],{},[35,243,244],{},"decision-boundaries.md"," で「Agentが決めていいこと/エスカレートすべきこと/Hard Stop」を明文化",[23,247,248,249,252],{},"正直、最初は「こんなの当たり前じゃないか」と自分でも思っていた。でも実際にサブエージェントに当てはめてみると、",[26,250,251],{},"人間の組織が数千年かけて試行錯誤で辿り着いた答えが、ほぼそのまま効く","ことがわかった。情報の共有・判断の分散・質の担保・決裁の経路——複数のサブエージェントを走らせると、この4つの問題がそっくり再発する。だったら歴史の答えを借りるのが合理的、というのが私の現時点の結論だ。",[47,254],{},[50,256,258],{"id":257},"アーキテクチャ俯瞰nextjs-prisma-neon-12体のサブエージェント","アーキテクチャ俯瞰：Next.js + Prisma + Neon + 12体のサブエージェント",[23,260,261,262,265],{},"ここからは私が実際に運用しているシステムを、できる範囲で正直に書く。動画やデモのために作ったモックではなく、",[26,263,264],{},"ZYL0 Labの実業務（ブログ執筆・コード開発・投資分析・契約書一次レビュー）を実際に回している現役のシステム","だ。スタックはあえて贅沢にせず、一人で保守できる範囲に絞っている。",[267,268,274],"pre",{"className":269,"code":271,"language":272,"meta":273},[270],"language-text","                 ┌────────────────────────────────────┐\n                 │       knowledge/  (Markdown vault) │\n                 │   context, projects, decisions,    │\n                 │   handoffs, playbooks, inbox       │\n                 └────────────────────────────────────┘\n                         ▲                       ▲\n              read/write │                       │ read/write\n                         │                       │\n┌───────────┐   ┌────────┴────────┐    ┌─────────┴────────┐\n│  Browser  │ ◄►│  Next.js (App)  │    │  Claude Code     │\n│ /board    │   │  src/app/       │    │   12 subagents   │\n│ /knowledge│   │  server actions │    │   skills + hooks │\n└───────────┘   └────────┬────────┘    └────────┬─────────┘\n                         │ Prisma               │ Bash → CLI\n                         ▼                      ▼\n                 ┌────────────────┐    ┌──────────────────┐\n                 │  src/lib/      │ ◄──│  scripts/cli/    │\n                 │   tasks.ts     │    │   task.ts        │\n                 │   views.ts     │    │   note.ts        │\n                 │   embeddings.ts│    │                  │\n                 └────────┬───────┘    └──────────────────┘\n                          ▼\n                 ┌────────────────────────────────────┐\n                 │  Neon (serverless Postgres)        │\n                 │  branches: main / preview-* /      │\n                 │  recover-*  +  pgvector for        │\n                 │  handoff embeddings                │\n                 └────────────────────────────────────┘\n","text","",[35,275,271],{"__ignoreMap":273},[23,277,278,279,282,283,286,287,290,291,294,295,298],{},"設計上の重要な選択は4つある。",[26,280,281],{},"まず、CLIがHTTPを介さずPrismaクライアントを直接共有している","点。サブエージェントは ",[35,284,285],{},"pnpm task add ..."," を Bash で叩いてボードを操作するが、UI のサーバーアクション・REST ルート・CLI のすべてが ",[35,288,289],{},"src/lib/tasks.ts"," の ",[35,292,293],{},"validateTaskCreate"," / ",[35,296,297],{},"validateTaskUpdate"," を通る。検証面は1つだけ、というのは半導体プロセスでも同じで、「同じ検査仕様を複数の経路で持つと必ず仕様乖離が起きる」という教訓がある。",[23,300,301,308,309,312,313,316],{},[26,302,303,304,307],{},"次に、Markdown vault が ",[35,305,306],{},"knowledge/"," という repo ルート直下にあること。"," これは Obsidian でリポジトリをそのまま vault として開けるようにするための配置だ。サブエージェントは ",[35,310,311],{},"src/lib/knowledge.ts"," 経由で読み書きし、",[35,314,315],{},"KNOWLEDGE_ROOT"," の外に escape できないようパスを sandbox している。",[23,318,319,326],{},[26,320,321,322,325],{},"3つ目に、Claude Code の hooks を ",[35,323,324],{},".claude/settings.json"," に直書きせず TS スクリプトで持っている。"," SessionStart で P0 タスク・Blocked・Stale を取得して標準出力に流し込み、PreToolUse（matcher: Task）でサブエージェントごとのロールリマインダーを差し込む。フック本体が TypeScript なので Prisma クライアントと UI 用 view 関数をそのまま使えるのが効いた。",[23,328,329,332,333,336,337,340,341,344],{},[26,330,331],{},"そして4つ目が、DBを Neon の serverless Postgres に固定し、ローカル開発も SQLite ではなく Neon の dev ブランチを使う","こと。SQLite ローカル＋本番 Postgres という構成は便利に見えて、列の挙動・JSONBのインデックス・トランザクション分離レベルがズレるので、結局本番でしか出ない不具合を生む。「検証面は1つだけ」の原則を DB にも適用した格好だ。",[35,334,335],{},"DATABASE_URL"," は Neon の pooled endpoint、",[35,338,339],{},"DIRECT_URL"," は direct endpoint で、後者は ",[35,342,343],{},"prisma migrate"," 専用に分けている。",[47,346],{},[50,348,350],{"id":349},"neonを使う4つの理由","Neonを使う4つの理由",[23,352,353,354,357,358,361],{},"ここからが今回の追加分だ。SQLite から Neon serverless Postgres に切り替えたのは、見栄えのためではなく、",[26,355,356],{},"サブエージェント運用の弱点をピンポイントで埋める4つの具体的な理由","があった。正直に言うと、一人会社にDB分岐は過剰だろうと最初は思っていた。",[26,359,360],{},"Neon のブランチ機能は、結果的にこのスタックで一番使う安全装置になった","——これは運用してみて初めて腹落ちした感覚だ。",[363,364,366],"h3",{"id":365},"_1-branching-dbレベルのgit","1. Branching = DBレベルのgit",[23,368,369],{},"サブエージェントがスキーマを触る系のタスク（マイグレーション、列追加、インデックス調整）を実行するとき、本番DBに直接触らせるのは怖い。Neon の branch は数秒で生成できる完全独立のDBで、本番のデータ形を持ったまま実験できる。",[267,371,375],{"className":372,"code":373,"language":374,"meta":273,"style":273},"language-bash shiki shiki-themes dracula","# 本番(main)から派生したブランチを作り、そのDATABASE_URLをエージェントに渡す\nneonctl branches create --name preview/agent-add-tags-col --parent main\nneonctl connection-string preview/agent-add-tags-col --pooled\n\n# エージェントはブランチ側で migrate\nprisma migrate dev --name add_tags_col\n\n# レビューOKならmainに再apply、NGならブランチを破棄して終了\nneonctl branches delete preview/agent-add-tags-col\n","bash",[35,376,377,386,413,426,433,439,456,461,467],{"__ignoreMap":273},[378,379,382],"span",{"class":380,"line":381},"line",1,[378,383,385],{"class":384},"shSDL","# 本番(main)から派生したブランチを作り、そのDATABASE_URLをエージェントに渡す\n",[378,387,389,393,397,400,404,407,410],{"class":380,"line":388},2,[378,390,392],{"class":391},"sAOxA","neonctl",[378,394,396],{"class":395},"s-mGx"," branches",[378,398,399],{"class":395}," create",[378,401,403],{"class":402},"sIQBb"," --name",[378,405,406],{"class":395}," preview/agent-add-tags-col",[378,408,409],{"class":402}," --parent",[378,411,412],{"class":395}," main\n",[378,414,416,418,421,423],{"class":380,"line":415},3,[378,417,392],{"class":391},[378,419,420],{"class":395}," connection-string",[378,422,406],{"class":395},[378,424,425],{"class":402}," --pooled\n",[378,427,429],{"class":380,"line":428},4,[378,430,432],{"emptyLinePlaceholder":431},true,"\n",[378,434,436],{"class":380,"line":435},5,[378,437,438],{"class":384},"# エージェントはブランチ側で migrate\n",[378,440,442,445,448,451,453],{"class":380,"line":441},6,[378,443,444],{"class":391},"prisma",[378,446,447],{"class":395}," migrate",[378,449,450],{"class":395}," dev",[378,452,403],{"class":402},[378,454,455],{"class":395}," add_tags_col\n",[378,457,459],{"class":380,"line":458},7,[378,460,432],{"emptyLinePlaceholder":431},[378,462,464],{"class":380,"line":463},8,[378,465,466],{"class":384},"# レビューOKならmainに再apply、NGならブランチを破棄して終了\n",[378,468,470,472,474,477],{"class":380,"line":469},9,[378,471,392],{"class":391},[378,473,396],{"class":395},[378,475,476],{"class":395}," delete",[378,478,479],{"class":395}," preview/agent-add-tags-col\n",[23,481,482],{},"backend-engineer の Decision Boundaries には「prod ブランチへ直接 schema push 禁止、必ず preview ブランチ経由」と書いてある。これは git の「main への直 push 禁止」と構造的に同じ規律で、AI に裁量を渡すときの最低ラインになる。",[363,484,486],{"id":485},"_2-pitr-がinbox削除事件の保険になる","2. PITR が「Inbox削除事件」の保険になる",[23,488,489],{},"教訓2で書いた Inbox の一括削除事件、当時は SQLite のスナップショットを手動で取っていただけだった。Neon の Point-in-Time Restore は秒単位で過去に戻れる（プランによるが最大30日保持）。事故の5分前から新しいブランチを切って、消された行だけ戻せばいい。",[267,491,493],{"className":372,"code":492,"language":374,"meta":273,"style":273},"neonctl branches create \\\n  --name recover/inbox-2026-05-03 \\\n  --parent main \\\n  --timestamp \"2026-05-03T03:14:00Z\"\n",[35,494,495,507,517,527],{"__ignoreMap":273},[378,496,497,499,501,503],{"class":380,"line":381},[378,498,392],{"class":391},[378,500,396],{"class":395},[378,502,399],{"class":395},[378,504,506],{"class":505},"s0Tla"," \\\n",[378,508,509,512,515],{"class":380,"line":388},[378,510,511],{"class":402},"  --name",[378,513,514],{"class":395}," recover/inbox-2026-05-03",[378,516,506],{"class":505},[378,518,519,522,525],{"class":380,"line":415},[378,520,521],{"class":402},"  --parent",[378,523,524],{"class":395}," main",[378,526,506],{"class":505},[378,528,529,532,536,539],{"class":380,"line":428},[378,530,531],{"class":402},"  --timestamp",[378,533,535],{"class":534},"seVfx"," \"",[378,537,538],{"class":395},"2026-05-03T03:14:00Z",[378,540,541],{"class":534},"\"\n",[23,543,544],{},"「不可逆なミス」が「5分のロールバック」に変わると、エージェントに任せられる作業の心理的閾値が一段下がる。これは数字で測りにくい効果で、運用してみて初めてわかった。",[363,546,548],{"id":547},"_3-pgvector-で-knowledge-を意味検索","3. pgvector で knowledge/ を意味検索",[23,550,551,554,555,558],{},[35,552,553],{},"handoffs/"," や ",[35,556,557],{},"decisions/"," が増えてくると、ファイル名検索だけでは「あの時のADR、どこだっけ」が引き出せなくなる。Neon は pgvector 拡張をネイティブで動かせるので、handoff/ADR のテキストを Embedding して同じDBに置いている。",[267,560,564],{"className":561,"code":562,"language":563,"meta":273,"style":273},"language-ts shiki shiki-themes dracula","// src/lib/embeddings.ts\nimport { prisma } from './db'\nimport { embed } from './embedder'\n\nexport async function searchHandoffs(query: string, k = 5) {\n  const [{ embedding }] = await embed([query])\n  // pgvector のコサイン距離で近傍検索\n  return prisma.$queryRaw\u003C\n    Array\u003C{\n      taskId: string\n      slug: string\n      similarity: number\n    }>\n  >`\n    SELECT \"taskId\", \"slug\",\n           1 - (\"embedding\" \u003C=> ${embedding}::vector) AS similarity\n    FROM \"HandoffEmbedding\"\n    ORDER BY \"embedding\" \u003C=> ${embedding}::vector\n    LIMIT ${k};\n  `\n}\n","ts",[35,565,566,571,592,608,612,655,675,680,691,699,710,720,731,737,746,752,770,776,791,806,812],{"__ignoreMap":273},[378,567,568],{"class":380,"line":381},[378,569,570],{"class":384},"// src/lib/embeddings.ts\n",[378,572,573,576,580,583,586,589],{"class":380,"line":388},[378,574,575],{"class":505},"import",[378,577,579],{"class":578},"sCdxs"," { prisma } ",[378,581,582],{"class":505},"from",[378,584,585],{"class":534}," '",[378,587,588],{"class":395},"./db",[378,590,591],{"class":534},"'\n",[378,593,594,596,599,601,603,606],{"class":380,"line":415},[378,595,575],{"class":505},[378,597,598],{"class":578}," { embed } ",[378,600,582],{"class":505},[378,602,585],{"class":534},[378,604,605],{"class":395},"./embedder",[378,607,591],{"class":534},[378,609,610],{"class":380,"line":428},[378,611,432],{"emptyLinePlaceholder":431},[378,613,614,617,620,623,626,629,633,636,640,643,646,649,652],{"class":380,"line":435},[378,615,616],{"class":505},"export",[378,618,619],{"class":505}," async",[378,621,622],{"class":505}," function",[378,624,625],{"class":391}," searchHandoffs",[378,627,628],{"class":578},"(",[378,630,632],{"class":631},"sGEwX","query",[378,634,635],{"class":505},":",[378,637,639],{"class":638},"sCp4m"," string",[378,641,642],{"class":578},", ",[378,644,645],{"class":631},"k",[378,647,648],{"class":505}," =",[378,650,651],{"class":402}," 5",[378,653,654],{"class":578},") {\n",[378,656,657,660,663,666,669,672],{"class":380,"line":441},[378,658,659],{"class":505},"  const",[378,661,662],{"class":578}," [{ embedding }] ",[378,664,665],{"class":505},"=",[378,667,668],{"class":505}," await",[378,670,671],{"class":391}," embed",[378,673,674],{"class":578},"([query])\n",[378,676,677],{"class":380,"line":458},[378,678,679],{"class":384},"  // pgvector のコサイン距離で近傍検索\n",[378,681,682,685,688],{"class":380,"line":463},[378,683,684],{"class":505},"  return",[378,686,687],{"class":578}," prisma.$queryRaw",[378,689,690],{"class":505},"\u003C\n",[378,692,693,696],{"class":380,"line":469},[378,694,695],{"class":391},"    Array",[378,697,698],{"class":578},"\u003C{\n",[378,700,702,705,707],{"class":380,"line":701},10,[378,703,704],{"class":578},"      taskId",[378,706,635],{"class":505},[378,708,709],{"class":638}," string\n",[378,711,713,716,718],{"class":380,"line":712},11,[378,714,715],{"class":578},"      slug",[378,717,635],{"class":505},[378,719,709],{"class":638},[378,721,723,726,728],{"class":380,"line":722},12,[378,724,725],{"class":578},"      similarity",[378,727,635],{"class":505},[378,729,730],{"class":638}," number\n",[378,732,734],{"class":380,"line":733},13,[378,735,736],{"class":578},"    }>\n",[378,738,740,743],{"class":380,"line":739},14,[378,741,742],{"class":505},"  >",[378,744,745],{"class":395},"`\n",[378,747,749],{"class":380,"line":748},15,[378,750,751],{"class":395},"    SELECT \"taskId\", \"slug\",\n",[378,753,755,758,761,764,767],{"class":380,"line":754},16,[378,756,757],{"class":395},"           1 - (\"embedding\" \u003C=> ",[378,759,760],{"class":505},"${",[378,762,763],{"class":578},"embedding",[378,765,766],{"class":505},"}",[378,768,769],{"class":395},"::vector) AS similarity\n",[378,771,773],{"class":380,"line":772},17,[378,774,775],{"class":395},"    FROM \"HandoffEmbedding\"\n",[378,777,779,782,784,786,788],{"class":380,"line":778},18,[378,780,781],{"class":395},"    ORDER BY \"embedding\" \u003C=> ",[378,783,760],{"class":505},[378,785,763],{"class":578},[378,787,766],{"class":505},[378,789,790],{"class":395},"::vector\n",[378,792,794,797,799,801,803],{"class":380,"line":793},19,[378,795,796],{"class":395},"    LIMIT ",[378,798,760],{"class":505},[378,800,645],{"class":578},[378,802,766],{"class":505},[378,804,805],{"class":395},";\n",[378,807,809],{"class":380,"line":808},20,[378,810,811],{"class":395},"  `\n",[378,813,815],{"class":380,"line":814},21,[378,816,817],{"class":578},"}\n",[23,819,820,821,824],{},"ファイル名引きは既知IDが分かっているとき用、pgvector は「なんとなく似た過去案件」を引きずり出すとき用、と役割を分けている。サブエージェントが",[35,822,823],{},"searchHandoffs(\"似た意思決定の前例\")"," を呼ぶだけで意味的に近いノートが返ってくるので、ハンドオフが「書きっぱなし」にならない。",[363,826,828],{"id":827},"_4-suspend-on-idle-が一人会社の経済を成立させる","4. Suspend-on-idle が一人会社の経済を成立させる",[23,830,831],{},"教訓1の「不可能だった仕事の経済的成立」と直接つながる話だ。Neon の compute は一定時間アイドルだと自動的に suspend し、課金が止まる。実際、夜間 QA は1時間あたり2〜3分しか走らないので、24/7 体制でも月額は数ドルレベルに収まっている。",[23,833,834],{},"24時間動く組織を、サーバ代を気にせず一人で持てる——これが Vercel + Neon の組み合わせで一番効いた箇所だった。",[47,836],{},[50,838,840],{"id":839},"_12体の内訳4グループに分けた理由","12体の内訳：4グループに分けた理由",[23,842,843,844,847,848,851],{},"サブエージェントは現在12体で、",[35,845,846],{},".claude/agents/\u003Crole>.md"," に YAML frontmatter で description を書いている。ここの ",[35,849,850],{},"description"," 文が Claude Code のルーターを兼ねるので、「Use when…」「Do not invoke for…」を具体的に書くのが肝になる。",[55,853,854,870],{},[58,855,856],{},[61,857,858,861,864,867],{},[64,859,860],{},"グループ",[64,862,863],{},"エージェント",[64,865,866],{},"モデル",[64,868,869],{},"主な責務",[71,871,872,886,899,913],{},[61,873,874,877,880,883],{},[76,875,876],{},"Leadership / Routing",[76,878,879],{},"engineering-lead / business-director / task-dispatcher",[76,881,882],{},"sonnet / sonnet / haiku",[76,884,885],{},"仕事の分解とルーティング、優先順位付け",[61,887,888,891,894,896],{},[76,889,890],{},"Engineering",[76,892,893],{},"frontend-engineer / backend-engineer / infra-ops",[76,895,882],{},[76,897,898],{},"UI実装 / スキーマ・API・CLI / ボード衛生・夜間ジョブ",[61,900,901,904,907,910],{},[76,902,903],{},"Quality",[76,905,906],{},"qa-reviewer / brand-voice-reviewer / anti-ai-slop-reviewer",[76,908,909],{},"sonnet / haiku / haiku",[76,911,912],{},"受け入れ基準検証 / ブランド準拠 / AIっぽさ検出",[61,914,915,918,921,923],{},[76,916,917],{},"Content / Strategy / Legal",[76,919,920],{},"content-director / legal-first-pass / morning-standup-writer",[76,922,882],{},[76,924,925],{},"長文構成 / 契約書一次レビュー / 朝のブリーフ",[23,927,928],{},"ルーティングの基本動作はこうなる。",[267,930,933],{"className":931,"code":932,"language":272},[270],"operator note → task-dispatcher → specialist\n                                ↘ engineering-lead (engineering, complex)\n                                ↘ business-director (strategy)\n\nengineer finishes → qa-reviewer → Done\n                              ↘ back to engineer (FAIL)\n\ncontent draft → content-director → brand-voice-reviewer\n                                ↘ anti-ai-slop-reviewer\n\ncontract → legal-first-pass → operator (always)\n",[35,934,932],{"__ignoreMap":273},[23,936,937,938,941],{},"モデル選択は単純で、複数ファイル文脈で判断するロール（エンジニアリング・コンテンツ・QA・法務）はSonnet、プロンプトが思考の大半を担うルール検出系（slopチェック・voiceチェック・dispatcher・infra衛生・morning brief）はHaikuにしている。",[26,939,940],{},"Opusはあえて常設していない。"," 戦略判断が必要な場面はオペレーター（私）が拾うか、ADR を起こす運用に倒したほうが、コストも責任所在もクリーンになった。",[47,943],{},[50,945,946],{"id":946},"エージェント定義の最小例",[23,948,949],{},"backend-engineer の定義はこんな感じだ。description を「ルーターのスイッチ」として書くのが一番大事で、ここが曖昧だと task-dispatcher がどこに振っていいかわからなくなる。",[267,951,955],{"className":952,"code":953,"language":954,"meta":273,"style":273},"language-markdown shiki shiki-themes dracula","---\nname: backend-engineer\ndescription: >\n  Use when the task touches src/lib/, prisma/schema.prisma, server actions,\n  API routes under src/app/api/, scripts/jobs/, or scripts/cli/. Do not\n  invoke for UI changes (use frontend-engineer) or stale-board hygiene\n  (use infra-ops).\nmodel: sonnet\ntools: [Read, Write, Edit, Bash, Glob, Grep]\n---\n\n# Backend Engineer\n\n## Scope\n\n- Prisma schema and migrations (always on a Neon preview branch first)\n- Validation helpers in src/lib/tasks.ts\n- Server actions and API routes\n- Job scripts in scripts/jobs/\n\n## Workflow\n\n1. Read the task and acceptanceCriteria from the board\n2. Implement minimum viable change; do not refactor unrelated code\n3. Add a regression test or CLI invocation that proves the change\n4. Move task to Review with a one-line summary in handoffNote\n\n## Don'ts\n\n- Never run prisma migrate reset\n- Never push schema directly to the Neon prod branch (use a preview branch)\n- Never add a dependency without an ADR\n- Never edit .claude/agents/\\* — escalate to operator\n","markdown",[35,956,957,962,967,972,977,982,987,992,997,1002,1006,1010,1015,1019,1024,1028,1033,1038,1043,1048,1052,1057,1062,1068,1074,1080,1086,1091,1097,1102,1108,1114,1120],{"__ignoreMap":273},[378,958,959],{"class":380,"line":381},[378,960,961],{},"---\n",[378,963,964],{"class":380,"line":388},[378,965,966],{},"name: backend-engineer\n",[378,968,969],{"class":380,"line":415},[378,970,971],{},"description: >\n",[378,973,974],{"class":380,"line":428},[378,975,976],{},"  Use when the task touches src/lib/, prisma/schema.prisma, server actions,\n",[378,978,979],{"class":380,"line":435},[378,980,981],{},"  API routes under src/app/api/, scripts/jobs/, or scripts/cli/. Do not\n",[378,983,984],{"class":380,"line":441},[378,985,986],{},"  invoke for UI changes (use frontend-engineer) or stale-board hygiene\n",[378,988,989],{"class":380,"line":458},[378,990,991],{},"  (use infra-ops).\n",[378,993,994],{"class":380,"line":463},[378,995,996],{},"model: sonnet\n",[378,998,999],{"class":380,"line":469},[378,1000,1001],{},"tools: [Read, Write, Edit, Bash, Glob, Grep]\n",[378,1003,1004],{"class":380,"line":701},[378,1005,961],{},[378,1007,1008],{"class":380,"line":712},[378,1009,432],{"emptyLinePlaceholder":431},[378,1011,1012],{"class":380,"line":722},[378,1013,1014],{},"# Backend Engineer\n",[378,1016,1017],{"class":380,"line":733},[378,1018,432],{"emptyLinePlaceholder":431},[378,1020,1021],{"class":380,"line":739},[378,1022,1023],{},"## Scope\n",[378,1025,1026],{"class":380,"line":748},[378,1027,432],{"emptyLinePlaceholder":431},[378,1029,1030],{"class":380,"line":754},[378,1031,1032],{},"- Prisma schema and migrations (always on a Neon preview branch first)\n",[378,1034,1035],{"class":380,"line":772},[378,1036,1037],{},"- Validation helpers in src/lib/tasks.ts\n",[378,1039,1040],{"class":380,"line":778},[378,1041,1042],{},"- Server actions and API routes\n",[378,1044,1045],{"class":380,"line":793},[378,1046,1047],{},"- Job scripts in scripts/jobs/\n",[378,1049,1050],{"class":380,"line":808},[378,1051,432],{"emptyLinePlaceholder":431},[378,1053,1054],{"class":380,"line":814},[378,1055,1056],{},"## Workflow\n",[378,1058,1060],{"class":380,"line":1059},22,[378,1061,432],{"emptyLinePlaceholder":431},[378,1063,1065],{"class":380,"line":1064},23,[378,1066,1067],{},"1. Read the task and acceptanceCriteria from the board\n",[378,1069,1071],{"class":380,"line":1070},24,[378,1072,1073],{},"2. Implement minimum viable change; do not refactor unrelated code\n",[378,1075,1077],{"class":380,"line":1076},25,[378,1078,1079],{},"3. Add a regression test or CLI invocation that proves the change\n",[378,1081,1083],{"class":380,"line":1082},26,[378,1084,1085],{},"4. Move task to Review with a one-line summary in handoffNote\n",[378,1087,1089],{"class":380,"line":1088},27,[378,1090,432],{"emptyLinePlaceholder":431},[378,1092,1094],{"class":380,"line":1093},28,[378,1095,1096],{},"## Don'ts\n",[378,1098,1100],{"class":380,"line":1099},29,[378,1101,432],{"emptyLinePlaceholder":431},[378,1103,1105],{"class":380,"line":1104},30,[378,1106,1107],{},"- Never run prisma migrate reset\n",[378,1109,1111],{"class":380,"line":1110},31,[378,1112,1113],{},"- Never push schema directly to the Neon prod branch (use a preview branch)\n",[378,1115,1117],{"class":380,"line":1116},32,[378,1118,1119],{},"- Never add a dependency without an ADR\n",[378,1121,1123],{"class":380,"line":1122},33,[378,1124,1125],{},"- Never edit .claude/agents/\\* — escalate to operator\n",[23,1127,1128,1129,1132],{},"ポイントは description 末尾の「Do not invoke for…」だ。これがないと task-dispatcher が UI 関連まで backend-engineer に振ってしまうことが現実に起きる。",[26,1130,1131],{},"「やってはいけないこと」を裁量境界として明文化する","——これは投資チームのDD標準化で口酸っぱく言ってきたことと完全に同じだ。",[47,1134],{},[50,1136,1138],{"id":1137},"タスクボードのスキーマ状態と検証","タスクボードのスキーマ：状態と検証",[23,1140,1141,1142,1145,1146,1149,1150,1153],{},"ボードのコアは Prisma の単一 ",[35,1143,1144],{},"Task"," テーブルで、Neon Postgres の上に乗っている。列挙型は Postgres の native enum に上げず、ローカルのモック・テストで扱いやすい string のままにしている。",[35,1147,1148],{},"auditTrail"," は Postgres ネイティブの JSONB に置けるので、SQLite 時代のように JSON 文字列としてシリアライズせず、",[35,1151,1152],{},"auditTrail @> '[{\"event\":\"deleted\"}]'::jsonb"," のような部分一致クエリが直接書ける。",[267,1155,1157],{"className":561,"code":1156,"language":563,"meta":273,"style":273},"// src/lib/types.ts\nexport const STATUSES = [\n  'Inbox',\n  'Unassigned',\n  'InProgress',\n  'Blocked',\n  'Review',\n  'Done',\n  'Archived',\n] as const\nexport const PRIORITIES = ['P0', 'P1', 'P2', 'P3'] as const\nexport const TEAMS = ['engineering', 'content', 'business', 'infra', 'human'] as const\n\nexport type AuditEntry = {\n  ts: string\n  actor: string // \"agent:backend-engineer\" or \"human:operator\"\n  event: string // e.g. \"status:InProgress->Review\"\n  detail?: string\n}\n",[35,1158,1159,1164,1179,1193,1204,1215,1226,1237,1248,1259,1270,1324,1386,1390,1405,1414,1426,1438,1448],{"__ignoreMap":273},[378,1160,1161],{"class":380,"line":381},[378,1162,1163],{"class":384},"// src/lib/types.ts\n",[378,1165,1166,1168,1171,1174,1176],{"class":380,"line":388},[378,1167,616],{"class":505},[378,1169,1170],{"class":505}," const",[378,1172,1173],{"class":578}," STATUSES ",[378,1175,665],{"class":505},[378,1177,1178],{"class":578}," [\n",[378,1180,1181,1184,1187,1190],{"class":380,"line":415},[378,1182,1183],{"class":534},"  '",[378,1185,1186],{"class":395},"Inbox",[378,1188,1189],{"class":534},"'",[378,1191,1192],{"class":578},",\n",[378,1194,1195,1197,1200,1202],{"class":380,"line":428},[378,1196,1183],{"class":534},[378,1198,1199],{"class":395},"Unassigned",[378,1201,1189],{"class":534},[378,1203,1192],{"class":578},[378,1205,1206,1208,1211,1213],{"class":380,"line":435},[378,1207,1183],{"class":534},[378,1209,1210],{"class":395},"InProgress",[378,1212,1189],{"class":534},[378,1214,1192],{"class":578},[378,1216,1217,1219,1222,1224],{"class":380,"line":441},[378,1218,1183],{"class":534},[378,1220,1221],{"class":395},"Blocked",[378,1223,1189],{"class":534},[378,1225,1192],{"class":578},[378,1227,1228,1230,1233,1235],{"class":380,"line":458},[378,1229,1183],{"class":534},[378,1231,1232],{"class":395},"Review",[378,1234,1189],{"class":534},[378,1236,1192],{"class":578},[378,1238,1239,1241,1244,1246],{"class":380,"line":463},[378,1240,1183],{"class":534},[378,1242,1243],{"class":395},"Done",[378,1245,1189],{"class":534},[378,1247,1192],{"class":578},[378,1249,1250,1252,1255,1257],{"class":380,"line":469},[378,1251,1183],{"class":534},[378,1253,1254],{"class":395},"Archived",[378,1256,1189],{"class":534},[378,1258,1192],{"class":578},[378,1260,1261,1264,1267],{"class":380,"line":701},[378,1262,1263],{"class":578},"] ",[378,1265,1266],{"class":505},"as",[378,1268,1269],{"class":505}," const\n",[378,1271,1272,1274,1276,1279,1281,1284,1286,1289,1291,1293,1295,1298,1300,1302,1304,1307,1309,1311,1313,1316,1318,1320,1322],{"class":380,"line":712},[378,1273,616],{"class":505},[378,1275,1170],{"class":505},[378,1277,1278],{"class":578}," PRIORITIES ",[378,1280,665],{"class":505},[378,1282,1283],{"class":578}," [",[378,1285,1189],{"class":534},[378,1287,1288],{"class":395},"P0",[378,1290,1189],{"class":534},[378,1292,642],{"class":578},[378,1294,1189],{"class":534},[378,1296,1297],{"class":395},"P1",[378,1299,1189],{"class":534},[378,1301,642],{"class":578},[378,1303,1189],{"class":534},[378,1305,1306],{"class":395},"P2",[378,1308,1189],{"class":534},[378,1310,642],{"class":578},[378,1312,1189],{"class":534},[378,1314,1315],{"class":395},"P3",[378,1317,1189],{"class":534},[378,1319,1263],{"class":578},[378,1321,1266],{"class":505},[378,1323,1269],{"class":505},[378,1325,1326,1328,1330,1333,1335,1337,1339,1342,1344,1346,1348,1351,1353,1355,1357,1360,1362,1364,1366,1369,1371,1373,1375,1378,1380,1382,1384],{"class":380,"line":722},[378,1327,616],{"class":505},[378,1329,1170],{"class":505},[378,1331,1332],{"class":578}," TEAMS ",[378,1334,665],{"class":505},[378,1336,1283],{"class":578},[378,1338,1189],{"class":534},[378,1340,1341],{"class":395},"engineering",[378,1343,1189],{"class":534},[378,1345,642],{"class":578},[378,1347,1189],{"class":534},[378,1349,1350],{"class":395},"content",[378,1352,1189],{"class":534},[378,1354,642],{"class":578},[378,1356,1189],{"class":534},[378,1358,1359],{"class":395},"business",[378,1361,1189],{"class":534},[378,1363,642],{"class":578},[378,1365,1189],{"class":534},[378,1367,1368],{"class":395},"infra",[378,1370,1189],{"class":534},[378,1372,642],{"class":578},[378,1374,1189],{"class":534},[378,1376,1377],{"class":395},"human",[378,1379,1189],{"class":534},[378,1381,1263],{"class":578},[378,1383,1266],{"class":505},[378,1385,1269],{"class":505},[378,1387,1388],{"class":380,"line":733},[378,1389,432],{"emptyLinePlaceholder":431},[378,1391,1392,1394,1397,1400,1402],{"class":380,"line":739},[378,1393,616],{"class":505},[378,1395,1396],{"class":505}," type",[378,1398,1399],{"class":638}," AuditEntry",[378,1401,648],{"class":505},[378,1403,1404],{"class":578}," {\n",[378,1406,1407,1410,1412],{"class":380,"line":748},[378,1408,1409],{"class":578},"  ts",[378,1411,635],{"class":505},[378,1413,709],{"class":638},[378,1415,1416,1419,1421,1423],{"class":380,"line":754},[378,1417,1418],{"class":578},"  actor",[378,1420,635],{"class":505},[378,1422,639],{"class":638},[378,1424,1425],{"class":384}," // \"agent:backend-engineer\" or \"human:operator\"\n",[378,1427,1428,1431,1433,1435],{"class":380,"line":772},[378,1429,1430],{"class":578},"  event",[378,1432,635],{"class":505},[378,1434,639],{"class":638},[378,1436,1437],{"class":384}," // e.g. \"status:InProgress->Review\"\n",[378,1439,1440,1443,1446],{"class":380,"line":778},[378,1441,1442],{"class":578},"  detail",[378,1444,1445],{"class":505},"?:",[378,1447,709],{"class":638},[378,1449,1450],{"class":380,"line":793},[378,1451,817],{"class":578},[23,1453,1454],{},"Neon 側に固有な部分は Prisma スキーマに出る：",[267,1456,1459],{"className":1457,"code":1458,"language":444,"meta":273,"style":273},"language-prisma shiki shiki-themes dracula","// prisma/schema.prisma — Neon-specific bits\ngenerator client {\n  provider        = \"prisma-client-js\"\n  previewFeatures = [\"postgresqlExtensions\"]\n}\n\ndatasource db {\n  provider   = \"postgresql\"\n  url        = env(\"DATABASE_URL\")  // Neon pooled\n  directUrl  = env(\"DIRECT_URL\")    // Neon direct (for migrate)\n  extensions = [pgvector]\n}\n\nmodel Task {\n  id          String   @id @default(cuid())\n  status      String\n  priority    String\n  team        String\n  auditTrail  Json     // Postgres JSONB — supports @> partial match\n  // ...\n}\n\nmodel HandoffEmbedding {\n  taskId    String   @id\n  slug      String\n  embedding Unsupported(\"vector(1536)\")?\n  createdAt DateTime @default(now())\n}\n",[35,1460,1461,1466,1471,1476,1481,1485,1489,1494,1499,1504,1509,1514,1518,1522,1527,1532,1537,1542,1547,1552,1557,1561,1565,1570,1575,1580,1585,1590],{"__ignoreMap":273},[378,1462,1463],{"class":380,"line":381},[378,1464,1465],{},"// prisma/schema.prisma — Neon-specific bits\n",[378,1467,1468],{"class":380,"line":388},[378,1469,1470],{},"generator client {\n",[378,1472,1473],{"class":380,"line":415},[378,1474,1475],{},"  provider        = \"prisma-client-js\"\n",[378,1477,1478],{"class":380,"line":428},[378,1479,1480],{},"  previewFeatures = [\"postgresqlExtensions\"]\n",[378,1482,1483],{"class":380,"line":435},[378,1484,817],{},[378,1486,1487],{"class":380,"line":441},[378,1488,432],{"emptyLinePlaceholder":431},[378,1490,1491],{"class":380,"line":458},[378,1492,1493],{},"datasource db {\n",[378,1495,1496],{"class":380,"line":463},[378,1497,1498],{},"  provider   = \"postgresql\"\n",[378,1500,1501],{"class":380,"line":469},[378,1502,1503],{},"  url        = env(\"DATABASE_URL\")  // Neon pooled\n",[378,1505,1506],{"class":380,"line":701},[378,1507,1508],{},"  directUrl  = env(\"DIRECT_URL\")    // Neon direct (for migrate)\n",[378,1510,1511],{"class":380,"line":712},[378,1512,1513],{},"  extensions = [pgvector]\n",[378,1515,1516],{"class":380,"line":722},[378,1517,817],{},[378,1519,1520],{"class":380,"line":733},[378,1521,432],{"emptyLinePlaceholder":431},[378,1523,1524],{"class":380,"line":739},[378,1525,1526],{},"model Task {\n",[378,1528,1529],{"class":380,"line":748},[378,1530,1531],{},"  id          String   @id @default(cuid())\n",[378,1533,1534],{"class":380,"line":754},[378,1535,1536],{},"  status      String\n",[378,1538,1539],{"class":380,"line":772},[378,1540,1541],{},"  priority    String\n",[378,1543,1544],{"class":380,"line":778},[378,1545,1546],{},"  team        String\n",[378,1548,1549],{"class":380,"line":793},[378,1550,1551],{},"  auditTrail  Json     // Postgres JSONB — supports @> partial match\n",[378,1553,1554],{"class":380,"line":808},[378,1555,1556],{},"  // ...\n",[378,1558,1559],{"class":380,"line":814},[378,1560,817],{},[378,1562,1563],{"class":380,"line":1059},[378,1564,432],{"emptyLinePlaceholder":431},[378,1566,1567],{"class":380,"line":1064},[378,1568,1569],{},"model HandoffEmbedding {\n",[378,1571,1572],{"class":380,"line":1070},[378,1573,1574],{},"  taskId    String   @id\n",[378,1576,1577],{"class":380,"line":1076},[378,1578,1579],{},"  slug      String\n",[378,1581,1582],{"class":380,"line":1082},[378,1583,1584],{},"  embedding Unsupported(\"vector(1536)\")?\n",[378,1586,1587],{"class":380,"line":1088},[378,1588,1589],{},"  createdAt DateTime @default(now())\n",[378,1591,1592],{"class":380,"line":1093},[378,1593,817],{},[23,1595,1596,1597,1600,1601,1604],{},"状態遷移は表で見たほうが早い。Review→Done では ",[35,1598,1599],{},"handoffNote"," を",[26,1602,1603],{},"警告レベル","で要求している点がポイントだ。エラーで弾くと「とりあえず空文字を入れて通す」という回避が起きるので、ブロックせず警告として浮上させる設計にしている。",[55,1606,1607,1623],{},[58,1608,1609],{},[61,1610,1611,1614,1617,1620],{},[64,1612,1613],{},"From → To",[64,1615,1616],{},"必須",[64,1618,1619],{},"監査イベント",[64,1621,1622],{},"副作用",[71,1624,1625,1645,1663,1681,1702],{},[61,1626,1627,1634,1637,1642],{},[76,1628,1629,1633],{},[1630,1631,1632],"em",{},"new"," → Inbox",[76,1635,1636],{},"title, description, createdBy",[76,1638,1639],{},[35,1640,1641],{},"created",[76,1643,1644],{},"auditTrail 初期化",[61,1646,1647,1650,1655,1660],{},[76,1648,1649],{},"InProgress → Blocked",[76,1651,1652],{},[35,1653,1654],{},"blockerReason",[76,1656,1657],{},[35,1658,1659],{},"status:InProgress->Blocked",[76,1661,1662],{},"—",[61,1664,1665,1668,1673,1678],{},[76,1666,1667],{},"InProgress → Review",[76,1669,1670],{},[35,1671,1672],{},"acceptanceCriteria",[76,1674,1675],{},[35,1676,1677],{},"status:InProgress->Review",[76,1679,1680],{},"qa-reviewer が自動拾い上げ",[61,1682,1683,1686,1691,1696],{},[76,1684,1685],{},"Review → Done",[76,1687,1688,1690],{},[35,1689,1599],{}," (推奨)",[76,1692,1693],{},[35,1694,1695],{},"status:Review->Done",[76,1697,1698,1701],{},[35,1699,1700],{},"completedAt"," セット",[61,1703,1704,1707,1709,1714],{},[76,1705,1706],{},"any → Archived",[76,1708,1662],{},[76,1710,1711],{},[35,1712,1713],{},"archived",[76,1715,1716],{},"listTasks から除外",[23,1718,1719,1722,1723,1726],{},[26,1720,1721],{},"削除は UI / CLI からは不可能","にした。これは事故防止の意味でかなり効いている（後述）。本当に消したい場合は ",[35,1724,1725],{},"prisma studio"," をオペレーター（=私）が手動で開く。",[47,1728],{},[50,1730,1732],{"id":1731},"knowledge-vault-と非同期ハンドオフ","knowledge/ vault と非同期ハンドオフ",[23,1734,1735,1737,1738,1741],{},[35,1736,306],{}," は repo ルート直下のフォルダで、Obsidian でそのまま vault として開ける。サブエージェント同士は",[26,1739,1740],{},"リアルタイムに会話しない","。代わりに、ここにファイルを書いて引き継ぐ。",[267,1743,1746],{"className":1744,"code":1745,"language":272,"meta":273},[270],"knowledge/\n├── inbox/        # ブレインダンプ・夜間スナップショット・朝のブリーフ\n├── projects/     # プロジェクト単位のブリーフ\n├── ideas/        # まだプロジェクト化していない発想\n├── resources/    # 参考資料\n├── context/      # 哲学・identity・voice・strategy・boundaries\n├── handoffs/     # \u003Ctask-id>-\u003Cslug>.md 形式の引き継ぎノート\n├── decisions/    # 連番ADR\n└── playbooks/    # nightly-qa など反復手順\n",[35,1747,1745],{"__ignoreMap":273},[23,1749,1750,1751,1754,1755,1757],{},"特に重要なのが ",[35,1752,1753],{},"context/"," と ",[35,1756,553],{}," の2つだ。",[23,1759,1760,1762],{},[35,1761,1753],{}," には philosophy / professional-identity / visual-design-language / product-strategy / decision-boundaries が並んでいる。これらが全エージェントに「ZYL0 Lab とは何か」を常時供給する共有記憶になる。",[23,1764,1765,1767,1768,1771,1772,1754,1775,1778,1779,1786],{},[35,1766,553],{}," のファイル名は ",[35,1769,1770],{},"\u003Ctask-id>-\u003Cslug>.md"," という規約にしてあるので、",[35,1773,1774],{},"pnpm task show \u003Cid>",[35,1776,1777],{},"ls knowledge/handoffs/\u003Cid>-*.md"," の双方向引きが効く。",[26,1780,1781,1782,1785],{},"ファイル名引きで足りない「意味で似た過去ノート」は、Neon 上の pgvector 経由で ",[35,1783,1784],{},"searchHandoffs"," を叩く","——Neon を導入した理由3そのままで、ファイル系と意味系の二層検索が同じDBにまとまっているのは想像以上に楽だった。",[23,1788,1789,1790,1793],{},"AWSでIoT Coreの非同期メッセージングを設計したとき、「リアルタイム同期は壊れやすく、非同期キュー＋永続ログは壊れにくい」という感覚を強く持った。サブエージェント運用でもまったく同じで、",[26,1791,1792],{},"ハンドオフをチャットではなくファイルに落とす","だけでデバッグ可能性が桁違いに上がる。",[47,1795],{},[50,1797,1799],{"id":1798},"decision-boundaries誰が何を決めていいか","Decision Boundaries：誰が何を決めていいか",[23,1801,1802,1803,1806],{},"12体のサブエージェントを動かしていて一番効いたのが、",[35,1804,1805],{},"knowledge/context/decision-boundaries.md"," を最初に書き切ったことだ。3つの領域で線を引いている。",[23,1808,1809],{},[26,1810,1811],{},"Agentが自分で決めていい",[1813,1814,1815,1819,1822,1825,1828],"ul",{},[1816,1817,1818],"li",{},"自分のタスク内のファイル単位リファクタ",[1816,1820,1821],{},"テスト追加",[1816,1823,1824],{},"既存フォルダ内のノート再整理",[1816,1826,1827],{},"より適切なサブエージェントへの再アサイン（監査記録あり）",[1816,1829,1830,1831,1833],{},"独立検証後の ",[35,1832,1232],{}," マーク",[23,1835,1836],{},[26,1837,1838],{},"オペレーターにエスカレートする",[1813,1840,1841,1847,1853,1868,1871,1874],{},[1816,1842,1843,1846],{},[35,1844,1845],{},"prisma/schema.prisma"," のスキーマ変更",[1816,1848,1849,1852],{},[35,1850,1851],{},"package.json"," への依存追加",[1816,1854,1855,1857,1858,1857,1861,1857,1864,1867],{},[35,1856,324],{}," ・ ",[35,1859,1860],{},".claude/agents/*",[35,1862,1863],{},".claude/skills/*",[35,1865,1866],{},"CLAUDE.md"," の変更",[1816,1869,1870],{},"クラウド/外部システムに触る操作",[1816,1872,1873],{},"ADR 級の判断",[1816,1875,1876,1878],{},[35,1877,1221],{}," への遷移",[23,1880,1881],{},[26,1882,1883],{},"Hard Stops（オペレーター明示確認なしには絶対に実行しない）",[1813,1885,1886,1891,1896,1901,1906,1909,1915],{},[1816,1887,1888],{},[35,1889,1890],{},"git push --force",[1816,1892,1893],{},[35,1894,1895],{},"prisma migrate reset",[1816,1897,1898],{},[35,1899,1900],{},"rm -rf",[1816,1902,1903],{},[35,1904,1905],{},"pnpm prune",[1816,1907,1908],{},"他エージェントが進行中のタスクの archive",[1816,1910,1911,1914],{},[35,1912,1913],{},"knowledge/decisions/"," の編集（追記のみ）",[1816,1916,1917],{},[26,1918,1919],{},"Neon prod ブランチへの直接 schema push（必ず preview ブランチ経由）",[23,1921,1922,1923,1926,1927,1929],{},"エスカレーションの",[26,1924,1925],{},"メカニズム","もコード化してある。サブエージェントはタスクを ",[35,1928,1199],{}," に戻し、フィールドを次のように埋める。",[1813,1931,1932,1940,1948,1951],{},[1816,1933,1934,1937,1938],{},[35,1935,1936],{},"assigneeType"," = ",[35,1939,1377],{},[1816,1941,1942,1937,1945],{},[35,1943,1944],{},"assigneeId",[35,1946,1947],{},"operator",[1816,1949,1950],{},"優先度を設定",[1816,1952,1953,1955],{},[35,1954,1599],{}," に質問を書き込む",[23,1957,1958,1959,1962],{},"すると私の ",[35,1960,1961],{},"/board/needs-attention"," ビューが自動的にそれを拾う。",[47,1964],{},[50,1966,1968],{"id":1967},"_1000時間運用で見えた3つの教訓","1000時間運用で見えた3つの教訓",[23,1970,1971],{},"ここからが今日一番書きたかった部分だ。500 時間のオペレーター直接稼働、無人稼働を含めて 1000 時間級ぶん回して、私が本当に大事だと思うようになったのは次の3つだ。",[363,1973,1975],{"id":1974},"_1-最大の見返りは時間節約ではない","1. 最大の見返りは時間節約ではない",[23,1977,1978,1979,1982,1983,1986],{},"夜中に動くQA、knowledge/ のゴミ掃除、stale-checkジョブ——これらは",[26,1980,1981],{},"個人プレイヤーでは経済的に成立しない仕事","だ。一人だと割に合わないので、普通はやらない。でも自律的に動くサブエージェントがいれば、追加の人件費なしで 24 時間動かせる。",[26,1984,1985],{},"結果として「シリコンバレーのまともな現場と同じ品質管理」が、一人事業の規模で初めて手に入る","——これが私には一番効いた。時間節約ではなく「不可能だった仕事の経済的成立」が、組織化AIの本当の価値だと現時点では考えている。そして Neon の suspend-on-idle と Vercel のサーバレス課金がここに直接効く——アイドル時間にコストが発生しないから、24/7 シフトを一人で持てる経済が成立した。",[363,1988,1990],{"id":1989},"_2-暗黙の了解は通用しない","2. 暗黙の了解は通用しない",[23,1992,1993,1994,1997],{},"人間の新人なら「Inboxを勝手に消したら怒られそう」と察してくれる。サブエージェントは察してくれない。",[26,1995,1996],{},"「消すな」と書いていなければ、消す可能性がある。"," これは比喩ではなく、私のknowledge/で実際に起きた。あるエージェントが「整理しておきます」と言って Inbox の未処理ノートをまとめて削除したのだ。",[23,1999,2000,2001,2004,2005,2008],{},"ここから学んだのは、",[26,2002,2003],{},"判断基準は全部書き下す必要がある","ということ。今は「Tasks: deletion is not supported via UI/CLI」「Knowledge: handoffs/ は decision boundaries により削除禁止」を明文化し、UI と CLI からは archive しか提供していない。投資チームのDD標準化のときも全く同じで、「常識でわかるだろう」と省略した部分が必ず事故を生んだ。",[26,2006,2007],{},"補足すると、Neon に移してから PITR が「不可逆な事故」を「5分のロールバック」に変えた","。記述による予防が第一線、Neon のリストアが第二線、という二重構造になっている。",[363,2010,2012],{"id":2011},"_3-aiの組織は静かに壊れる","3. AIの組織は静かに壊れる",[23,2014,2015,2016,2019],{},"これが一番怖い教訓だ。",[26,2017,2018],{},"サブエージェント組織は、エラーも警告も出さずに壊れる。"," 設定ファイルが壊れていても「書き込み完了しました」と返事して次の仕事に移る。タスクボードのキューが詰まっても「処理中です」と表示し続ける。",[23,2021,2022,2023,2026],{},"人間の新人なら「このメッセージ届いてないんですけど？」とエスカレーションしてくれるが、AIはしない。だから**「動いてます」報告だけでは絶対に足りない**。今は morning-standup-writer が毎朝、夜間スナップショット＋今日のフォーカス＋エディター注釈を ",[35,2024,2025],{},"knowledge/inbox/morning-brief-latest.md"," に書く。私はこれを開けば 3 分で全体の健康診断ができる。観察可能性（observability）はサブエージェント運用の必須要件だと言い切れる。",[47,2028],{},[50,2030,2032],{"id":2031},"落とし穴500時間で踏んだ罠と回避策","落とし穴：500時間で踏んだ罠と回避策",[23,2034,2035],{},"特に頻度が高かったハマりポイントを共有する。",[23,2037,2038,2041],{},[26,2039,2040],{},"罠1: description が曖昧でルーターが詰まる。"," 「Use when engineering tasks」みたいな広すぎる description だと、task-dispatcher が UI も schema も infra hygiene も全部 backend-engineer に振る。回避策は description を**「Use when X. Do not invoke for Y.」の対称形**で書くこと。Don't 側が Router の精度を上げる。",[23,2043,2044,2047,2048,1754,2050,2052,2053,2055,2056,2059],{},[26,2045,2046],{},"罠2: 検証ロジックが分散する。"," UI のサーバーアクション、REST ルート、CLI で別々に validation を書くと、必ず仕様乖離が起きる。回避策は ",[35,2049,293],{},[35,2051,297],{}," を ",[35,2054,289],{}," の単一 export として持ち、3経路すべてがそれを通す設計にすること。CLI と UI が",[26,2057,2058],{},"同じ Prisma クライアント","を共有しているからこそ成立する。",[23,2061,2062,2065,2066,2069,2070,2072,2073,2076,2077,2080,2081,2084,2085,2088],{},[26,2063,2064],{},"罠3: タスクボードが腐る。"," 完了したのに ",[35,2067,2068],{},"status"," が ",[35,2071,1210],{}," のまま放置されるタスクが、数日で数十件溜まる。回避策は ",[35,2074,2075],{},"scripts/jobs/stale-check.ts"," を夜間に走らせる方式だ。 ",[35,2078,2079],{},"updatedAt"," が 72 時間以上前の非 Done / 非 Archived タスクを ",[35,2082,2083],{},"stale"," タグでマークする。ただし",[26,2086,2087],{},"自動 archive はしない","——infra-ops は「これは stale に見える」とオペレーターに提案するだけで、最終判断は人間に残す。",[23,2090,2091,2094],{},[26,2092,2093],{},"罠4: AIっぽい文章が混ざる。"," content-director だけだと、どうしても「いかがでしたか」的な表現や em-dash padding が混ざる。回避策が anti-ai-slop-reviewer を最終チェックに置くこと。これは私が普段絶対書かないフレーズリストをマニュアルに持っていて、検出したら強制的に書き直しを要求する。",[23,2096,2097,2100,2101,2103,2104,2052,2107,2110,2111,2113,2114,2116,2117,2120],{},[26,2098,2099],{},"罠5: Vercel + Neon でのコネクション管理。"," Vercel のサーバレス関数は呼び出しごとに新しい接続を張るので、Neon に対してすぐに接続上限が見える。回避策はシンプルで、",[35,2102,335],{}," には Neon の ",[26,2105,2106],{},"pooled endpoint",[35,2108,2109],{},"?pgbouncer=true&connection_limit=1"," 付きで使い、",[35,2112,339],{}," には direct endpoint を割り当てて ",[35,2115,343],{}," 専用にする。Edge runtime で動かしたいルートだけ ",[35,2118,2119],{},"@neondatabase/serverless"," の HTTP/WebSocket ドライバに切り替える、という3経路の使い分けが今のところ一番安定している。Prisma の Data Proxy を使う手もあるが、CLI と UI で同じクライアントを共有する設計と相性が悪く、今は採用していない。",[47,2122],{},[50,2124,2125],{"id":2125},"まとめ",[23,2127,2128],{},"500時間オペレーター稼働、累計1000時間級でこの仕組みを回した結論は、当初の予想よりずっとシンプルだった。",[1813,2130,2131,2137,2146,2155],{},[1816,2132,2133,2136],{},[26,2134,2135],{},"一つのAIに全部やらせない","——12体に分け、文脈を物理的に分離する",[1816,2138,2139,2142,2143,2145],{},[26,2140,2141],{},"全員が同じ記憶を共有する","——",[35,2144,306],{}," vault と Prisma タスクボードが共有メモリ",[1816,2147,2148,2142,2151,2154],{},[26,2149,2150],{},"引き継ぎは会話ではなく書き物で",[35,2152,2153],{},"handoffs/\u003Ctask-id>-\u003Cslug>.md"," と auditTrail JSON が永続ログになる",[1816,2156,2157,2142,2160,2162],{},[26,2158,2159],{},"裁量と Hard Stop を明文化する",[35,2161,244],{}," に書いていないことは AI は察してくれない",[23,2164,2165,2166,2169],{},"この4つは、私がCVCで投資チームを標準化したときの方法論とほぼ同じだ。AIだから特別な原則が必要、ということはない。",[26,2167,2168],{},"人間の組織が長い時間をかけて見つけてきた答えに、AIならではの強み（24時間稼働・コスト最適化・並列実行）を足す","——これが現時点で私の見ている景色だ。",[23,2171,2172,2173,2176,2177,2180],{},"どのモデルが強いかで議論するのは表面的な勝負で、",[26,2174,2175],{},"どう回すかで本当の差がつく","。Claude でも Gemini でも GPT でも、Prisma のテーブルと knowledge vault を中心に据える設計思想は同じように適用できる。",[26,2178,2179],{},"そしてその「Prisma のテーブル」を Neon の上に置いた瞬間、ブランチ・PITR・pgvector・suspend-on-idle という4つの装備が一気に手に入る","。12体のサブエージェントを本番DBに対して安心して走らせられるのは、この組み合わせの成果だ。",[47,2182],{},[23,2184,2185],{},[1630,2186,2187,2188,2193],{},"免責事項：本記事は情報提供・教育目的のものであり、特定の銘柄推奨や投資助言を構成するものではありません。記載のツール・技術情報は執筆時点のものであり、最新情報は各公式ドキュメントをご確認ください。生成AIをリサーチ・翻訳・推敲の補助として用いていますが、最終内容はZYL0が人手で確認しています。詳細は",[2189,2190,2192],"a",{"href":2191},"/disclaimer","免責事項","をご覧ください。",[47,2195],{},[11,2197,2199,2203,2217,2224,2226,2230,2300,2302,2306,2313,2316,2322,2331,2337,2343,2345,2349,2352,2418,2425,2427,2431,2434,2439,2457,2471,2507,2519,2521,2525,2532,2536,2539,2615,2618,2622,2625,2665,2668,2674,2683,2871,2878,2882,2885,2888,2890,2894,2903,2967,2970,2975,2982,2984,2988,2999,3135,3142,3144,3148,3164,3422,3425,3541,3551,3645,3654,3656,3660,3669,3675,3682,3687,3705,3711,3713,3717,3723,3728,3748,3753,3790,3796,3828,3838,3863,3869,3871,3875,3878,3882,3893,3897,3904,3928,3932,3939,3953,3955,3959,3962,3972,3986,4008,4014,4037,4039,4043,4046,4083,4090,4101,4103],{"lang":2198},"en",[15,2200,2202],{"id":2201},"running-ai-agents-as-an-organization-a-12-subagent-neon-backed-postgres-task-board-architecture-for-a-one-person-company","Running AI Agents as an Organization: A 12-Subagent, Neon-Backed Postgres Task Board Architecture for a One-Person Company",[20,2204,2205],{},[23,2206,2207,2210,2211,2213,2214,2216],{},[26,2208,2209],{},"Version note",": Based on operational logs as of May 2026. Assumes Claude Code v2.x, Claude Sonnet 4.6 / Haiku 4.5, Next.js 14, Prisma 5, ",[26,2212,32],{},", and Vercel runtime. Uses ",[35,2215,37],{}," for subagents and two Claude Code hooks (SessionStart and PreToolUse). Model specs, Claude Code hook specs, and Neon pricing tiers move fast — check official docs for current behavior.",[23,2218,2219,2220,2223],{},"I started out as a semiconductor process development engineer and later moved into venture capital as a CVC investor. The first thing I ran into when I joined the investment team was that \"DD quality standards varied wildly between people.\" When I led the standardization effort over three months, the lesson that stuck was the obvious one: ",[26,2221,2222],{},"quality is guaranteed by structure, not by individual effort."," That same realization came back, almost word-for-word, after I spent 500 hours running Claude Code subagents (closer to 1,000 if you count unattended runtime). This post is the operational design I arrived at — written at the code, schema, and Neon-utilization level, with nothing hidden.",[47,2225],{},[50,2227,2229],{"id":2228},"tldr-what-youll-learn","TL;DR: What You'll Learn",[55,2231,2232,2242],{},[58,2233,2234],{},[61,2235,2236,2239],{},[64,2237,2238],{},"Topic",[64,2240,2241],{},"What you'll learn",[71,2243,2244,2252,2260,2268,2284,2292],{},[61,2245,2246,2249],{},[76,2247,2248],{},"Single AI vs. organized AI",[76,2250,2251],{},"Three structural reasons a single chat-window setup hits a ceiling",[61,2253,2254,2257],{},[76,2255,2256],{},"Four organizational pillars",[76,2258,2259],{},"How \"specialization, review, written handoff, clear ownership\" from VC team ops translate to subagents",[61,2261,2262,2265],{},[76,2263,2264],{},"The 12-agent breakdown",[76,2266,2267],{},"Boundaries between Leadership / Engineering / Quality / Content-Strategy-Legal",[61,2269,2270,2273],{},[76,2271,2272],{},"Implementation stack",[76,2274,105,2275,109,2278,2280,2281,2283],{},[26,2276,2277],{},"Neon (serverless Postgres + pgvector)",[35,2279,112],{}," CLI + an Obsidian-compatible ",[35,2282,306],{}," vault",[61,2285,2286,2289],{},[76,2287,2288],{},"Why Neon (the core wins)",[76,2290,2291],{},"Branching as DB-level git, PITR as the Inbox-deletion safety net, pgvector for semantic recall, suspend-on-idle as the economic enabler",[61,2293,2294,2297],{},[76,2295,2296],{},"Pitfalls",[76,2298,2299],{},"The Inbox-deletion incident, Decision Boundaries as the antidote, Vercel + Neon connection management",[47,2301],{},[50,2303,2305],{"id":2304},"the-ceiling-of-one-ai-does-everything","The Ceiling of \"One AI Does Everything\"",[23,2307,2308,2309,2312],{},"Discussions about AI agent operations still feel ",[26,2310,2311],{},"too anchored on \"a smarter model will solve it,\""," at least to me. Comparing Claude vs. GPT vs. Codex is fair, but every one of those debates assumes a single AI doing the entire job. That assumption, I think, is where the wheels come off.",[23,2314,2315],{},"After three months of running Claude Code 6+ hours a day, I see three structural ceilings to that approach.",[23,2317,2318,2321],{},[26,2319,2320],{},"1. Mixed context warps output."," When you stuff Project A's spec, Client B's requirements, last week's meeting notes, and today's grocery list into the same session, irrelevant signal becomes noise and answers drift. It's structurally identical to running a TCAD process simulation where one wrong boundary condition shifts the result by an order of magnitude.",[23,2323,2324,2327,2328],{},[26,2325,2326],{},"2. Hallucinations multiply."," With cluttered context, the AI confidently asserts things that were never decided. I'm reminded of a yield issue at a portfolio company that the field engineer \"confidently reported\" as an equipment problem — when I re-ran the TCAD simulation, the actual root cause was a process-side boundary condition. ",[26,2329,2330],{},"Confidently wrong reports cannot be caught without multiple lenses.",[23,2332,2333,2336],{},[26,2334,2335],{},"3. There is no reviewer."," With a single AI, the responsibility to check output collapses onto one human (me). I write the prompt, I read the result, I judge — that's a sole-investor decision with no investment committee, and no serious shop runs that way.",[23,2338,2339,2340],{},"The unsolved part is ",[26,2341,2342],{},"how to address all three at once through \"organization.\"",[47,2344],{},[50,2346,2348],{"id":2347},"the-four-pillars-i-borrowed-from-investment-team-ops","The Four Pillars I Borrowed from Investment-Team Ops",[23,2350,2351],{},"When I led the DD standardization at the investment team, the structure that emerged had four pillars. The moment I realized those same four pillars map cleanly onto Claude Code subagents was where this whole operation began.",[55,2353,2354,2367],{},[58,2355,2356],{},[61,2357,2358,2361,2364],{},[64,2359,2360],{},"Pillar",[64,2362,2363],{},"Investment team",[64,2365,2366],{},"Subagent org",[71,2368,2369,2380,2391,2405],{},[61,2370,2371,2374,2377],{},[76,2372,2373],{},"Specialization",[76,2375,2376],{},"DD split by market / tech / finance / legal",[76,2378,2379],{},"12 agents across 4 functional groups (below)",[61,2381,2382,2385,2388],{},[76,2383,2384],{},"Review culture",[76,2386,2387],{},"Investment committee runs multiple lenses",[76,2389,2390],{},"qa-reviewer / brand-voice-reviewer / anti-ai-slop-reviewer in series",[61,2392,2393,2396,2399],{},[76,2394,2395],{},"Written handoff",[76,2397,2398],{},"Investment memos, ADRs, PRDs",[76,2400,2401,2402,2404],{},"Mandatory ",[35,2403,230],{}," notes per task",[61,2406,2407,2410,2413],{},[76,2408,2409],{},"Clear ownership",[76,2411,2412],{},"Analyst / manager / committee authority",[76,2414,2415,2417],{},[35,2416,244],{}," codifies \"agent decides / escalate / hard stop\"",[23,2419,2420,2421,2424],{},"Honestly, I thought \"this is just common sense\" at first. But mapping it onto subagents, I found that ",[26,2422,2423],{},"the answers human organizations spent millennia evolving carry over almost intact."," Information sharing, decision distribution, quality assurance, escalation paths — when you run multiple subagents, the exact same four problems resurface. So borrowing the historical answer is the rational move, at least where I currently stand.",[47,2426],{},[50,2428,2430],{"id":2429},"architecture-overview-nextjs-prisma-neon-12-subagents","Architecture Overview: Next.js + Prisma + Neon + 12 Subagents",[23,2432,2433],{},"From here I'll describe the system I actually use — not a demo mock, but the live setup that runs ZYL0 Lab's real work (blog drafting, code, investment analysis, first-pass contract review). The stack is deliberately not flashy; everything has to be maintainable by one person.",[267,2435,2437],{"className":2436,"code":271,"language":272,"meta":273},[270],[35,2438,271],{"__ignoreMap":273},[23,2440,2441,2442,2445,2446,2448,2449,294,2451,2453,2454,2456],{},"Four design choices stand out. ",[26,2443,2444],{},"First, the CLI shares the Prisma client directly instead of going through HTTP."," Subagents manipulate the board by running ",[35,2447,285],{}," from Bash, but UI server actions, REST routes, and the CLI all funnel through ",[35,2450,293],{},[35,2452,297],{}," in ",[35,2455,289],{},". One validation surface, period. The semiconductor world has a similar law: keep the same inspection spec across multiple test paths or your spec will silently diverge.",[23,2458,2459,2465,2466,2468,2469,2464],{},[26,2460,2461,2462,2464],{},"Second, the Markdown vault sits at the repo root as ",[35,2463,306],{},"."," That placement is intentional so I can open the repo as an Obsidian vault. Subagents read and write through ",[35,2467,311],{},", which path-sandboxes everything to ",[35,2470,315],{},[23,2472,2473,2483,2484,2487,2488,642,2491,2494,2495,2498,2499,2502,2503,2506],{},[26,2474,2475,2476,2479,2480,2464],{},"Third, Claude Code hooks live as TS scripts under ",[35,2477,2478],{},".claude/hooks/",", not inline in ",[35,2481,2482],{},"settings.json"," ",[35,2485,2486],{},"SessionStart"," queries ",[35,2489,2490],{},"p0Tasks",[35,2492,2493],{},"blockedTasks",", and ",[35,2496,2497],{},"staleTasks",", then pipes a markdown summary to stdout. ",[35,2500,2501],{},"PreToolUse"," (matcher: Task) reads the JSON payload from stdin, extracts ",[35,2504,2505],{},"subagent_type",", and writes a role-specific reminder. Keeping hook bodies in TypeScript means they reuse the same Prisma client and view functions the UI uses.",[23,2508,2509,2512,2513,2515,2516,2518],{},[26,2510,2511],{},"Fourth, the DB is pinned to Neon serverless Postgres, and local dev uses a Neon dev branch — there is no SQLite anywhere."," SQLite-local-Postgres-prod looks convenient until column behavior, JSONB indexing, and transaction isolation start drifting between environments and you ship bugs that only surface in production. Applying the \"one validation surface\" rule to the database, basically. ",[35,2514,335],{}," points at Neon's pooled endpoint; ",[35,2517,339],{}," points at the direct endpoint and is reserved for migrations.",[47,2520],{},[50,2522,2524],{"id":2523},"why-neon-four-specific-wins","Why Neon: Four Specific Wins",[23,2526,2527,2528,2531],{},"This is the new piece compared to the original write-up. Switching from SQLite to Neon serverless Postgres wasn't cosmetic — it filled four very specific gaps in subagent operations. Honestly, I expected \"branching for a one-person stack\" to be overkill. ",[26,2529,2530],{},"Neon's branching turned out to be the single most-used safety device in the whole architecture"," — that's a sentence I couldn't have written before running this for a few hundred hours.",[363,2533,2535],{"id":2534},"_1-branching-is-git-for-databases","1. Branching is git-for-databases",[23,2537,2538],{},"When a subagent runs schema-touching work (migrations, new columns, index changes), letting it hit the production DB directly is scary. A Neon branch is a fully isolated DB you can spin up in seconds, carrying the production data shape so experiments are realistic.",[267,2540,2542],{"className":372,"code":2541,"language":374,"meta":273,"style":273},"# Branch off main and hand the agent the branch's DATABASE_URL\nneonctl branches create --name preview/agent-add-tags-col --parent main\nneonctl connection-string preview/agent-add-tags-col --pooled\n\n# The agent runs the migration on the branch\nprisma migrate dev --name add_tags_col\n\n# Re-apply on main if review passes; otherwise drop the branch and move on\nneonctl branches delete preview/agent-add-tags-col\n",[35,2543,2544,2549,2565,2575,2579,2584,2596,2600,2605],{"__ignoreMap":273},[378,2545,2546],{"class":380,"line":381},[378,2547,2548],{"class":384},"# Branch off main and hand the agent the branch's DATABASE_URL\n",[378,2550,2551,2553,2555,2557,2559,2561,2563],{"class":380,"line":388},[378,2552,392],{"class":391},[378,2554,396],{"class":395},[378,2556,399],{"class":395},[378,2558,403],{"class":402},[378,2560,406],{"class":395},[378,2562,409],{"class":402},[378,2564,412],{"class":395},[378,2566,2567,2569,2571,2573],{"class":380,"line":415},[378,2568,392],{"class":391},[378,2570,420],{"class":395},[378,2572,406],{"class":395},[378,2574,425],{"class":402},[378,2576,2577],{"class":380,"line":428},[378,2578,432],{"emptyLinePlaceholder":431},[378,2580,2581],{"class":380,"line":435},[378,2582,2583],{"class":384},"# The agent runs the migration on the branch\n",[378,2585,2586,2588,2590,2592,2594],{"class":380,"line":441},[378,2587,444],{"class":391},[378,2589,447],{"class":395},[378,2591,450],{"class":395},[378,2593,403],{"class":402},[378,2595,455],{"class":395},[378,2597,2598],{"class":380,"line":458},[378,2599,432],{"emptyLinePlaceholder":431},[378,2601,2602],{"class":380,"line":463},[378,2603,2604],{"class":384},"# Re-apply on main if review passes; otherwise drop the branch and move on\n",[378,2606,2607,2609,2611,2613],{"class":380,"line":469},[378,2608,392],{"class":391},[378,2610,396],{"class":395},[378,2612,476],{"class":395},[378,2614,479],{"class":395},[23,2616,2617],{},"The Decision Boundaries doc explicitly forbids direct schema pushes to the prod branch — every migration goes through a preview branch first. Structurally identical to \"no direct push to main\" in git, and the minimum bar I want when handing schema authority to an AI.",[363,2619,2621],{"id":2620},"_2-pitr-is-the-safety-net-for-the-inbox-deletion-incident","2. PITR is the safety net for the Inbox-deletion incident",[23,2623,2624],{},"For Lesson 2's Inbox bulk-deletion incident, all I had at the time were manual SQLite snapshots. Neon's Point-in-Time Restore goes back to the second, up to 30 days depending on the plan. You branch from five minutes before the event and copy back just the rows that were deleted.",[267,2626,2627],{"className":372,"code":492,"language":374,"meta":273,"style":273},[35,2628,2629,2639,2647,2655],{"__ignoreMap":273},[378,2630,2631,2633,2635,2637],{"class":380,"line":381},[378,2632,392],{"class":391},[378,2634,396],{"class":395},[378,2636,399],{"class":395},[378,2638,506],{"class":505},[378,2640,2641,2643,2645],{"class":380,"line":388},[378,2642,511],{"class":402},[378,2644,514],{"class":395},[378,2646,506],{"class":505},[378,2648,2649,2651,2653],{"class":380,"line":415},[378,2650,521],{"class":402},[378,2652,524],{"class":395},[378,2654,506],{"class":505},[378,2656,2657,2659,2661,2663],{"class":380,"line":428},[378,2658,531],{"class":402},[378,2660,535],{"class":534},[378,2662,538],{"class":395},[378,2664,541],{"class":534},[23,2666,2667],{},"When \"irreversible mistake\" turns into \"five-minute rollback,\" the psychological bar for what you'll let an agent attempt drops noticeably. That's an effect I couldn't have predicted on paper.",[363,2669,2671,2672],{"id":2670},"_3-pgvector-for-semantic-recall-over-knowledge","3. pgvector for semantic recall over ",[35,2673,306],{},[23,2675,2676,2677,2679,2680,2682],{},"Once ",[35,2678,553],{}," and ",[35,2681,557],{}," get past a few dozen entries, filename search stops working — \"where was that ADR about model selection?\" Neon ships pgvector natively, so I embed handoff/ADR text and store the vectors in the same DB.",[267,2684,2686],{"className":561,"code":2685,"language":563,"meta":273,"style":273},"// src/lib/embeddings.ts\nimport { prisma } from './db'\nimport { embed } from './embedder'\n\nexport async function searchHandoffs(query: string, k = 5) {\n  const [{ embedding }] = await embed([query])\n  // pgvector cosine distance for nearest-neighbor search\n  return prisma.$queryRaw\u003C\n    Array\u003C{\n      taskId: string\n      slug: string\n      similarity: number\n    }>\n  >`\n    SELECT \"taskId\", \"slug\",\n           1 - (\"embedding\" \u003C=> ${embedding}::vector) AS similarity\n    FROM \"HandoffEmbedding\"\n    ORDER BY \"embedding\" \u003C=> ${embedding}::vector\n    LIMIT ${k};\n  `\n}\n",[35,2687,2688,2692,2706,2720,2724,2752,2766,2771,2779,2785,2793,2801,2809,2813,2819,2823,2835,2839,2851,2863,2867],{"__ignoreMap":273},[378,2689,2690],{"class":380,"line":381},[378,2691,570],{"class":384},[378,2693,2694,2696,2698,2700,2702,2704],{"class":380,"line":388},[378,2695,575],{"class":505},[378,2697,579],{"class":578},[378,2699,582],{"class":505},[378,2701,585],{"class":534},[378,2703,588],{"class":395},[378,2705,591],{"class":534},[378,2707,2708,2710,2712,2714,2716,2718],{"class":380,"line":415},[378,2709,575],{"class":505},[378,2711,598],{"class":578},[378,2713,582],{"class":505},[378,2715,585],{"class":534},[378,2717,605],{"class":395},[378,2719,591],{"class":534},[378,2721,2722],{"class":380,"line":428},[378,2723,432],{"emptyLinePlaceholder":431},[378,2725,2726,2728,2730,2732,2734,2736,2738,2740,2742,2744,2746,2748,2750],{"class":380,"line":435},[378,2727,616],{"class":505},[378,2729,619],{"class":505},[378,2731,622],{"class":505},[378,2733,625],{"class":391},[378,2735,628],{"class":578},[378,2737,632],{"class":631},[378,2739,635],{"class":505},[378,2741,639],{"class":638},[378,2743,642],{"class":578},[378,2745,645],{"class":631},[378,2747,648],{"class":505},[378,2749,651],{"class":402},[378,2751,654],{"class":578},[378,2753,2754,2756,2758,2760,2762,2764],{"class":380,"line":441},[378,2755,659],{"class":505},[378,2757,662],{"class":578},[378,2759,665],{"class":505},[378,2761,668],{"class":505},[378,2763,671],{"class":391},[378,2765,674],{"class":578},[378,2767,2768],{"class":380,"line":458},[378,2769,2770],{"class":384},"  // pgvector cosine distance for nearest-neighbor search\n",[378,2772,2773,2775,2777],{"class":380,"line":463},[378,2774,684],{"class":505},[378,2776,687],{"class":578},[378,2778,690],{"class":505},[378,2780,2781,2783],{"class":380,"line":469},[378,2782,695],{"class":391},[378,2784,698],{"class":578},[378,2786,2787,2789,2791],{"class":380,"line":701},[378,2788,704],{"class":578},[378,2790,635],{"class":505},[378,2792,709],{"class":638},[378,2794,2795,2797,2799],{"class":380,"line":712},[378,2796,715],{"class":578},[378,2798,635],{"class":505},[378,2800,709],{"class":638},[378,2802,2803,2805,2807],{"class":380,"line":722},[378,2804,725],{"class":578},[378,2806,635],{"class":505},[378,2808,730],{"class":638},[378,2810,2811],{"class":380,"line":733},[378,2812,736],{"class":578},[378,2814,2815,2817],{"class":380,"line":739},[378,2816,742],{"class":505},[378,2818,745],{"class":395},[378,2820,2821],{"class":380,"line":748},[378,2822,751],{"class":395},[378,2824,2825,2827,2829,2831,2833],{"class":380,"line":754},[378,2826,757],{"class":395},[378,2828,760],{"class":505},[378,2830,763],{"class":578},[378,2832,766],{"class":505},[378,2834,769],{"class":395},[378,2836,2837],{"class":380,"line":772},[378,2838,775],{"class":395},[378,2840,2841,2843,2845,2847,2849],{"class":380,"line":778},[378,2842,781],{"class":395},[378,2844,760],{"class":505},[378,2846,763],{"class":578},[378,2848,766],{"class":505},[378,2850,790],{"class":395},[378,2852,2853,2855,2857,2859,2861],{"class":380,"line":793},[378,2854,796],{"class":395},[378,2856,760],{"class":505},[378,2858,645],{"class":578},[378,2860,766],{"class":505},[378,2862,805],{"class":395},[378,2864,2865],{"class":380,"line":808},[378,2866,811],{"class":395},[378,2868,2869],{"class":380,"line":814},[378,2870,817],{"class":578},[23,2872,2873,2874,2877],{},"Filename lookup is for known IDs. pgvector is for fuzzy recall — \"find me prior work that smells like this.\" A subagent that calls ",[35,2875,2876],{},"searchHandoffs(\"similar prior decisions\")"," gets semantically nearby notes without me having to remember the exact slug, and handoffs stop being write-only.",[363,2879,2881],{"id":2880},"_4-suspend-on-idle-is-what-makes-the-solo-operator-economics-work","4. Suspend-on-idle is what makes the solo-operator economics work",[23,2883,2884],{},"This is directly downstream of Lesson 1's \"previously impossible work becoming viable.\" Neon compute auto-suspends after an idle window, which kills the bill while no agent is running. In practice, nightly QA runs ~2–3 minutes per hour, so the 24/7 footprint stays in the low single-dollar range monthly.",[23,2886,2887],{},"Running a 24-hour organization without worrying about server costs — that was the single biggest win from the Vercel + Neon pair, in my current view.",[47,2889],{},[50,2891,2893],{"id":2892},"the-12-agent-roster-why-four-groups","The 12-Agent Roster: Why Four Groups",[23,2895,2896,2897,2899,2900,2902],{},"Subagents live in ",[35,2898,846],{}," with YAML frontmatter. The ",[35,2901,850],{}," field doubles as the Claude Code router, so writing it as \"Use when… Do not invoke for…\" is critical.",[55,2904,2905,2921],{},[58,2906,2907],{},[61,2908,2909,2912,2915,2918],{},[64,2910,2911],{},"Group",[64,2913,2914],{},"Agents",[64,2916,2917],{},"Model",[64,2919,2920],{},"Primary responsibilities",[71,2922,2923,2934,2945,2956],{},[61,2924,2925,2927,2929,2931],{},[76,2926,876],{},[76,2928,879],{},[76,2930,882],{},[76,2932,2933],{},"Decompose work, route, prioritize",[61,2935,2936,2938,2940,2942],{},[76,2937,890],{},[76,2939,893],{},[76,2941,882],{},[76,2943,2944],{},"UI / schema-API-CLI / board hygiene + nightly jobs",[61,2946,2947,2949,2951,2953],{},[76,2948,903],{},[76,2950,906],{},[76,2952,909],{},[76,2954,2955],{},"AC verification / brand alignment / AI-slop detection",[61,2957,2958,2960,2962,2964],{},[76,2959,917],{},[76,2961,920],{},[76,2963,882],{},[76,2965,2966],{},"Long-form structure / contract first-pass / morning brief",[23,2968,2969],{},"The base routing flow is short:",[267,2971,2973],{"className":2972,"code":932,"language":272},[270],[35,2974,932],{"__ignoreMap":273},[23,2976,2977,2978,2981],{},"Model selection is simple: roles that exercise judgment over multi-file context (engineering, content, QA, legal) run on Sonnet. Rule-following / detection roles where the prompt does most of the thinking (slop, voice, dispatcher, infra hygiene, morning brief) run on Haiku. ",[26,2979,2980],{},"Opus is intentionally not in the roster."," Strategic calls are picked up by me or escalated as ADRs. That keeps cost and ownership clean.",[47,2983],{},[50,2985,2987],{"id":2986},"minimal-agent-definition","Minimal Agent Definition",[23,2989,2990,2991,2994,2995,2998],{},"Here's a slightly simplified version of ",[35,2992,2993],{},"backend-engineer",". Writing the description as ",[26,2996,2997],{},"a router switch"," is the most important part. Vague descriptions cause task-dispatcher to misroute work.",[267,3000,3001],{"className":952,"code":953,"language":954,"meta":273,"style":273},[35,3002,3003,3007,3011,3015,3019,3023,3027,3031,3035,3039,3043,3047,3051,3055,3059,3063,3067,3071,3075,3079,3083,3087,3091,3095,3099,3103,3107,3111,3115,3119,3123,3127,3131],{"__ignoreMap":273},[378,3004,3005],{"class":380,"line":381},[378,3006,961],{},[378,3008,3009],{"class":380,"line":388},[378,3010,966],{},[378,3012,3013],{"class":380,"line":415},[378,3014,971],{},[378,3016,3017],{"class":380,"line":428},[378,3018,976],{},[378,3020,3021],{"class":380,"line":435},[378,3022,981],{},[378,3024,3025],{"class":380,"line":441},[378,3026,986],{},[378,3028,3029],{"class":380,"line":458},[378,3030,991],{},[378,3032,3033],{"class":380,"line":463},[378,3034,996],{},[378,3036,3037],{"class":380,"line":469},[378,3038,1001],{},[378,3040,3041],{"class":380,"line":701},[378,3042,961],{},[378,3044,3045],{"class":380,"line":712},[378,3046,432],{"emptyLinePlaceholder":431},[378,3048,3049],{"class":380,"line":722},[378,3050,1014],{},[378,3052,3053],{"class":380,"line":733},[378,3054,432],{"emptyLinePlaceholder":431},[378,3056,3057],{"class":380,"line":739},[378,3058,1023],{},[378,3060,3061],{"class":380,"line":748},[378,3062,432],{"emptyLinePlaceholder":431},[378,3064,3065],{"class":380,"line":754},[378,3066,1032],{},[378,3068,3069],{"class":380,"line":772},[378,3070,1037],{},[378,3072,3073],{"class":380,"line":778},[378,3074,1042],{},[378,3076,3077],{"class":380,"line":793},[378,3078,1047],{},[378,3080,3081],{"class":380,"line":808},[378,3082,432],{"emptyLinePlaceholder":431},[378,3084,3085],{"class":380,"line":814},[378,3086,1056],{},[378,3088,3089],{"class":380,"line":1059},[378,3090,432],{"emptyLinePlaceholder":431},[378,3092,3093],{"class":380,"line":1064},[378,3094,1067],{},[378,3096,3097],{"class":380,"line":1070},[378,3098,1073],{},[378,3100,3101],{"class":380,"line":1076},[378,3102,1079],{},[378,3104,3105],{"class":380,"line":1082},[378,3106,1085],{},[378,3108,3109],{"class":380,"line":1088},[378,3110,432],{"emptyLinePlaceholder":431},[378,3112,3113],{"class":380,"line":1093},[378,3114,1096],{},[378,3116,3117],{"class":380,"line":1099},[378,3118,432],{"emptyLinePlaceholder":431},[378,3120,3121],{"class":380,"line":1104},[378,3122,1107],{},[378,3124,3125],{"class":380,"line":1110},[378,3126,1113],{},[378,3128,3129],{"class":380,"line":1116},[378,3130,1119],{},[378,3132,3133],{"class":380,"line":1122},[378,3134,1125],{},[23,3136,3137,3138,3141],{},"The \"Do not invoke for…\" tail of the description is the part most people skip, and it's the part that actually pays the rent. ",[26,3139,3140],{},"Codifying what an agent must NOT do is what makes role boundaries crisp"," — exactly the same lesson I beat into the investment team during DD standardization.",[47,3143],{},[50,3145,3147],{"id":3146},"task-schema-states-and-validation","Task Schema: States and Validation",[23,3149,3150,3151,3153,3154,3157,3158,3160,3161,3163],{},"The board core is a single Prisma ",[35,3152,1144],{}," table living in Neon Postgres. Enums could be promoted to Postgres native enums, but I keep them as ",[35,3155,3156],{},"string"," for portability with local mocks and tests. ",[35,3159,1148],{}," is a Postgres-native JSONB column now — no more \"stringify and parse on every read\" the way I had to under SQLite. Partial-match queries like ",[35,3162,1152],{}," become available out of the box.",[267,3165,3166],{"className":561,"code":1156,"language":563,"meta":273,"style":273},[35,3167,3168,3172,3184,3194,3204,3214,3224,3234,3244,3254,3262,3310,3366,3370,3382,3390,3400,3410,3418],{"__ignoreMap":273},[378,3169,3170],{"class":380,"line":381},[378,3171,1163],{"class":384},[378,3173,3174,3176,3178,3180,3182],{"class":380,"line":388},[378,3175,616],{"class":505},[378,3177,1170],{"class":505},[378,3179,1173],{"class":578},[378,3181,665],{"class":505},[378,3183,1178],{"class":578},[378,3185,3186,3188,3190,3192],{"class":380,"line":415},[378,3187,1183],{"class":534},[378,3189,1186],{"class":395},[378,3191,1189],{"class":534},[378,3193,1192],{"class":578},[378,3195,3196,3198,3200,3202],{"class":380,"line":428},[378,3197,1183],{"class":534},[378,3199,1199],{"class":395},[378,3201,1189],{"class":534},[378,3203,1192],{"class":578},[378,3205,3206,3208,3210,3212],{"class":380,"line":435},[378,3207,1183],{"class":534},[378,3209,1210],{"class":395},[378,3211,1189],{"class":534},[378,3213,1192],{"class":578},[378,3215,3216,3218,3220,3222],{"class":380,"line":441},[378,3217,1183],{"class":534},[378,3219,1221],{"class":395},[378,3221,1189],{"class":534},[378,3223,1192],{"class":578},[378,3225,3226,3228,3230,3232],{"class":380,"line":458},[378,3227,1183],{"class":534},[378,3229,1232],{"class":395},[378,3231,1189],{"class":534},[378,3233,1192],{"class":578},[378,3235,3236,3238,3240,3242],{"class":380,"line":463},[378,3237,1183],{"class":534},[378,3239,1243],{"class":395},[378,3241,1189],{"class":534},[378,3243,1192],{"class":578},[378,3245,3246,3248,3250,3252],{"class":380,"line":469},[378,3247,1183],{"class":534},[378,3249,1254],{"class":395},[378,3251,1189],{"class":534},[378,3253,1192],{"class":578},[378,3255,3256,3258,3260],{"class":380,"line":701},[378,3257,1263],{"class":578},[378,3259,1266],{"class":505},[378,3261,1269],{"class":505},[378,3263,3264,3266,3268,3270,3272,3274,3276,3278,3280,3282,3284,3286,3288,3290,3292,3294,3296,3298,3300,3302,3304,3306,3308],{"class":380,"line":712},[378,3265,616],{"class":505},[378,3267,1170],{"class":505},[378,3269,1278],{"class":578},[378,3271,665],{"class":505},[378,3273,1283],{"class":578},[378,3275,1189],{"class":534},[378,3277,1288],{"class":395},[378,3279,1189],{"class":534},[378,3281,642],{"class":578},[378,3283,1189],{"class":534},[378,3285,1297],{"class":395},[378,3287,1189],{"class":534},[378,3289,642],{"class":578},[378,3291,1189],{"class":534},[378,3293,1306],{"class":395},[378,3295,1189],{"class":534},[378,3297,642],{"class":578},[378,3299,1189],{"class":534},[378,3301,1315],{"class":395},[378,3303,1189],{"class":534},[378,3305,1263],{"class":578},[378,3307,1266],{"class":505},[378,3309,1269],{"class":505},[378,3311,3312,3314,3316,3318,3320,3322,3324,3326,3328,3330,3332,3334,3336,3338,3340,3342,3344,3346,3348,3350,3352,3354,3356,3358,3360,3362,3364],{"class":380,"line":722},[378,3313,616],{"class":505},[378,3315,1170],{"class":505},[378,3317,1332],{"class":578},[378,3319,665],{"class":505},[378,3321,1283],{"class":578},[378,3323,1189],{"class":534},[378,3325,1341],{"class":395},[378,3327,1189],{"class":534},[378,3329,642],{"class":578},[378,3331,1189],{"class":534},[378,3333,1350],{"class":395},[378,3335,1189],{"class":534},[378,3337,642],{"class":578},[378,3339,1189],{"class":534},[378,3341,1359],{"class":395},[378,3343,1189],{"class":534},[378,3345,642],{"class":578},[378,3347,1189],{"class":534},[378,3349,1368],{"class":395},[378,3351,1189],{"class":534},[378,3353,642],{"class":578},[378,3355,1189],{"class":534},[378,3357,1377],{"class":395},[378,3359,1189],{"class":534},[378,3361,1263],{"class":578},[378,3363,1266],{"class":505},[378,3365,1269],{"class":505},[378,3367,3368],{"class":380,"line":733},[378,3369,432],{"emptyLinePlaceholder":431},[378,3371,3372,3374,3376,3378,3380],{"class":380,"line":739},[378,3373,616],{"class":505},[378,3375,1396],{"class":505},[378,3377,1399],{"class":638},[378,3379,648],{"class":505},[378,3381,1404],{"class":578},[378,3383,3384,3386,3388],{"class":380,"line":748},[378,3385,1409],{"class":578},[378,3387,635],{"class":505},[378,3389,709],{"class":638},[378,3391,3392,3394,3396,3398],{"class":380,"line":754},[378,3393,1418],{"class":578},[378,3395,635],{"class":505},[378,3397,639],{"class":638},[378,3399,1425],{"class":384},[378,3401,3402,3404,3406,3408],{"class":380,"line":772},[378,3403,1430],{"class":578},[378,3405,635],{"class":505},[378,3407,639],{"class":638},[378,3409,1437],{"class":384},[378,3411,3412,3414,3416],{"class":380,"line":778},[378,3413,1442],{"class":578},[378,3415,1445],{"class":505},[378,3417,709],{"class":638},[378,3419,3420],{"class":380,"line":793},[378,3421,817],{"class":578},[23,3423,3424],{},"The Neon-specific bits show up in the Prisma schema:",[267,3426,3427],{"className":1457,"code":1458,"language":444,"meta":273,"style":273},[35,3428,3429,3433,3437,3441,3445,3449,3453,3457,3461,3465,3469,3473,3477,3481,3485,3489,3493,3497,3501,3505,3509,3513,3517,3521,3525,3529,3533,3537],{"__ignoreMap":273},[378,3430,3431],{"class":380,"line":381},[378,3432,1465],{},[378,3434,3435],{"class":380,"line":388},[378,3436,1470],{},[378,3438,3439],{"class":380,"line":415},[378,3440,1475],{},[378,3442,3443],{"class":380,"line":428},[378,3444,1480],{},[378,3446,3447],{"class":380,"line":435},[378,3448,817],{},[378,3450,3451],{"class":380,"line":441},[378,3452,432],{"emptyLinePlaceholder":431},[378,3454,3455],{"class":380,"line":458},[378,3456,1493],{},[378,3458,3459],{"class":380,"line":463},[378,3460,1498],{},[378,3462,3463],{"class":380,"line":469},[378,3464,1503],{},[378,3466,3467],{"class":380,"line":701},[378,3468,1508],{},[378,3470,3471],{"class":380,"line":712},[378,3472,1513],{},[378,3474,3475],{"class":380,"line":722},[378,3476,817],{},[378,3478,3479],{"class":380,"line":733},[378,3480,432],{"emptyLinePlaceholder":431},[378,3482,3483],{"class":380,"line":739},[378,3484,1526],{},[378,3486,3487],{"class":380,"line":748},[378,3488,1531],{},[378,3490,3491],{"class":380,"line":754},[378,3492,1536],{},[378,3494,3495],{"class":380,"line":772},[378,3496,1541],{},[378,3498,3499],{"class":380,"line":778},[378,3500,1546],{},[378,3502,3503],{"class":380,"line":793},[378,3504,1551],{},[378,3506,3507],{"class":380,"line":808},[378,3508,1556],{},[378,3510,3511],{"class":380,"line":814},[378,3512,817],{},[378,3514,3515],{"class":380,"line":1059},[378,3516,432],{"emptyLinePlaceholder":431},[378,3518,3519],{"class":380,"line":1064},[378,3520,1569],{},[378,3522,3523],{"class":380,"line":1070},[378,3524,1574],{},[378,3526,3527],{"class":380,"line":1076},[378,3528,1579],{},[378,3530,3531],{"class":380,"line":1082},[378,3532,1584],{},[378,3534,3535],{"class":380,"line":1088},[378,3536,1589],{},[378,3538,3539],{"class":380,"line":1093},[378,3540,817],{},[23,3542,3543,3544,3546,3547,3550],{},"The state transitions are easier to read as a table. Note that Review→Done flags a missing ",[35,3545,1599],{}," as a ",[26,3548,3549],{},"warning, not an error",". Hard-rejecting it would just make agents stuff in empty strings — surfacing as a warning encourages real handoff notes without blocking the flow.",[55,3552,3553,3568],{},[58,3554,3555],{},[61,3556,3557,3559,3562,3565],{},[64,3558,1613],{},[64,3560,3561],{},"Required",[64,3563,3564],{},"Audit event",[64,3566,3567],{},"Side effect",[71,3569,3570,3585,3599,3614,3632],{},[61,3571,3572,3576,3578,3582],{},[76,3573,3574,1633],{},[1630,3575,1632],{},[76,3577,1636],{},[76,3579,3580],{},[35,3581,1641],{},[76,3583,3584],{},"auditTrail initialized",[61,3586,3587,3589,3593,3597],{},[76,3588,1649],{},[76,3590,3591],{},[35,3592,1654],{},[76,3594,3595],{},[35,3596,1659],{},[76,3598,1662],{},[61,3600,3601,3603,3607,3611],{},[76,3602,1667],{},[76,3604,3605],{},[35,3606,1672],{},[76,3608,3609],{},[35,3610,1677],{},[76,3612,3613],{},"qa-reviewer auto-picks up",[61,3615,3616,3618,3623,3627],{},[76,3617,1685],{},[76,3619,3620,3622],{},[35,3621,1599],{}," (recommended)",[76,3624,3625],{},[35,3626,1695],{},[76,3628,3629,3631],{},[35,3630,1700],{}," set",[61,3633,3634,3636,3638,3642],{},[76,3635,1706],{},[76,3637,1662],{},[76,3639,3640],{},[35,3641,1713],{},[76,3643,3644],{},"excluded from listTasks",[23,3646,3647,3650,3651,3653],{},[26,3648,3649],{},"Deletion is not exposed via UI or CLI."," This single rule has prevented several near-incidents. If real deletion is ever needed, I open ",[35,3652,1725],{}," manually.",[47,3655],{},[50,3657,3659],{"id":3658},"the-knowledge-vault-and-asynchronous-handoffs","The knowledge/ Vault and Asynchronous Handoffs",[23,3661,3662,3664,3665,3668],{},[35,3663,306],{}," lives at the repo root and opens as an Obsidian vault as-is. Subagents ",[26,3666,3667],{},"never chat with each other in real time."," They write files instead.",[267,3670,3673],{"className":3671,"code":3672,"language":272,"meta":273},[270],"knowledge/\n├── inbox/        # brain dumps, nightly snapshots, morning briefs\n├── projects/     # per-initiative briefs\n├── ideas/        # not-yet-projects\n├── resources/    # reference material\n├── context/      # philosophy, identity, voice, strategy, boundaries\n├── handoffs/     # \u003Ctask-id>-\u003Cslug>.md handoff notes\n├── decisions/    # numbered ADRs\n└── playbooks/    # nightly-qa and other repeatables\n",[35,3674,3672],{"__ignoreMap":273},[23,3676,3677,2679,3679,3681],{},[35,3678,1753],{},[35,3680,553],{}," are the two folders that earn their keep.",[23,3683,3684,3686],{},[35,3685,1753],{}," holds philosophy, professional-identity, visual-design-language, product-strategy, and decision-boundaries — every agent gets that as ambient \"what is ZYL0 Lab\" memory.",[23,3688,3689,3690,3692,3693,2679,3695,3697,3698,3704],{},"Handoff filenames follow ",[35,3691,1770],{},", so ",[35,3694,1774],{},[35,3696,1777],{}," work as bidirectional lookups. ",[26,3699,3700,3701,3703],{},"For the cases where filename lookup isn't enough — \"find me a similar prior decision\" — agents call ",[35,3702,1784],{}," against the pgvector store on Neon",", exactly the win described in reason 3 above. Filename and semantic recall sitting in the same DB has been more useful than I expected.",[23,3706,3707,3708],{},"Designing AWS IoT Core async messaging years ago left me with a strong intuition: real-time sync is fragile, async queues plus durable logs are robust. Subagent operations are the same — ",[26,3709,3710],{},"writing handoffs to files instead of conversations turns debugging from impossible to tractable.",[47,3712],{},[50,3714,3716],{"id":3715},"decision-boundaries-who-decides-what","Decision Boundaries: Who Decides What",[23,3718,3719,3720,3722],{},"Of everything I built for this org, ",[35,3721,1805],{}," was the highest-leverage single document. It draws lines in three regions.",[23,3724,3725],{},[26,3726,3727],{},"Agents may decide on their own",[1813,3729,3730,3733,3736,3739,3742],{},[1816,3731,3732],{},"File-level refactors within the assigned task",[1816,3734,3735],{},"Adding tests for code already being changed",[1816,3737,3738],{},"Reorganizing notes within an existing folder",[1816,3740,3741],{},"Reassigning to a more appropriate sub-agent (must record in audit)",[1816,3743,3744,3745,3747],{},"Marking another agent's task ",[35,3746,1232],{}," after independent verification",[23,3749,3750],{},[26,3751,3752],{},"Agents must escalate to the operator",[1813,3754,3755,3761,3766,3778,3781,3784],{},[1816,3756,3757,3758,3760],{},"Any change to ",[35,3759,1845],{}," requiring a migration",[1816,3762,3763,3764],{},"Adding dependencies to ",[35,3765,1851],{},[1816,3767,3768,3769,642,3771,642,3773,3775,3776],{},"Changes to ",[35,3770,324],{},[35,3772,1860],{},[35,3774,1863],{},", or ",[35,3777,1866],{},[1816,3779,3780],{},"Anything touching cloud or external systems",[1816,3782,3783],{},"Any decision that warrants an ADR",[1816,3785,3786,3787,3789],{},"Transition to ",[35,3788,1221],{}," on operator input",[23,3791,3792,3795],{},[26,3793,3794],{},"Hard stops"," (never without explicit operator confirmation)",[1813,3797,3798,3802,3806,3810,3814,3817,3823],{},[1816,3799,3800],{},[35,3801,1890],{},[1816,3803,3804],{},[35,3805,1895],{},[1816,3807,3808],{},[35,3809,1900],{},[1816,3811,3812],{},[35,3813,1905],{},[1816,3815,3816],{},"Archiving a task another agent is working on",[1816,3818,3819,3820,3822],{},"Editing existing entries under ",[35,3821,1913],{}," (only append new ADRs)",[1816,3824,3825],{},[26,3826,3827],{},"Direct schema push to the Neon prod branch (must go via a preview branch)",[23,3829,3830,3831,3834,3835,3837],{},"The escalation ",[26,3832,3833],{},"mechanism"," is encoded too. The agent moves the task to ",[35,3836,1199],{}," and fills in the fields:",[1813,3839,3840,3846,3852,3855],{},[1816,3841,3842,1937,3844],{},[35,3843,1936],{},[35,3845,1377],{},[1816,3847,3848,1937,3850],{},[35,3849,1944],{},[35,3851,1947],{},[1816,3853,3854],{},"Sets priority",[1816,3856,3857,3858,3860,3861],{},"Writes the question into ",[35,3859,850],{}," or ",[35,3862,1599],{},[23,3864,3865,3866,3868],{},"My ",[35,3867,1961],{}," view picks it up automatically.",[47,3870],{},[50,3872,3874],{"id":3873},"three-lessons-from-1000-hours","Three Lessons from 1,000 Hours",[23,3876,3877],{},"This is the part I most wanted to write. After ~500 hours of direct operator time and roughly 1,000 hours of cumulative agent runtime, here's what I now consider truly important.",[363,3879,3881],{"id":3880},"_1-the-biggest-payoff-isnt-time-savings","1. The biggest payoff isn't time savings",[23,3883,3884,3885,3888,3889,3892],{},"Overnight QA, knowledge/ cleanup, the stale-check job — these are jobs ",[26,3886,3887],{},"that don't make economic sense for a solo player."," They aren't worth the time, so usually nobody does them. But with autonomous subagents, you can run them 24/7 at near-zero marginal cost. ",[26,3890,3891],{},"The result: \"Silicon-Valley-grade quality processes\" become attainable at the scale of a single-person operation, possibly for the first time."," That's what hit me hardest. The real value of an organized AI setup, in my current view, isn't time saved — it's \"work that was previously impossible becoming economically viable.\" Neon's suspend-on-idle compute and Vercel's serverless billing line up directly with that thesis: when the bill stops while no agent is running, a 24/7 shift becomes affordable for one person.",[363,3894,3896],{"id":3895},"_2-implicit-understanding-does-not-transfer","2. Implicit understanding does not transfer",[23,3898,3899,3900,3903],{},"A human new hire would sense \"I probably shouldn't delete the Inbox unilaterally.\" A subagent senses no such thing. ",[26,3901,3902],{},"If you didn't write \"do not delete,\" there is a real chance it will delete."," This isn't a metaphor — it actually happened in my knowledge/ vault. One agent declared \"I'll tidy up\" and bulk-deleted unprocessed Inbox notes.",[23,3905,3906,3907,3910,3911,3913,3914,3917,3918,3920,3921,3923,3924,3927],{},"The lesson: ",[26,3908,3909],{},"every judgment criterion has to be written down explicitly."," The board now exposes only ",[35,3912,1254],{},", not ",[35,3915,3916],{},"delete",". ",[35,3919,553],{}," is explicitly listed under \"do not delete\" in ",[35,3922,244],{},". It was the same during the DD standardization — every place I cut corners on the assumption \"this is obvious\" eventually produced an incident. ",[26,3925,3926],{},"One footnote: after moving to Neon, PITR turned \"irreversible incident\" into \"five-minute rollback.\""," Written rules remain the first line of defense; Neon's restore is the second line — a two-layer setup that didn't exist on SQLite.",[363,3929,3931],{"id":3930},"_3-ai-organizations-break-silently","3. AI organizations break silently",[23,3933,3934,3935,3938],{},"This is the scariest lesson. ",[26,3936,3937],{},"Subagent organizations break without errors or warnings."," A corrupted config file? \"Write complete, moving on.\" A clogged task queue? \"In progress\" indefinitely.",[23,3940,3941,3942,3945,3946,3949,3950,3952],{},"A human new hire would escalate \"this message hasn't reached me.\" AI doesn't. So ",[26,3943,3944],{},"\"the agent reported it's running\" is never enough."," Every morning, ",[35,3947,3948],{},"morning-standup-writer"," produces a brief at ",[35,3951,2025],{}," containing the overnight summary, today's focus, and an editor's note. Three minutes of reading and I know whether the org is healthy. Observability is, I'd argue, a non-negotiable requirement for subagent operations.",[47,3954],{},[50,3956,3958],{"id":3957},"pitfalls-traps-i-hit-and-how-i-worked-around-them","Pitfalls: Traps I Hit and How I Worked Around Them",[23,3960,3961],{},"Sharing the most frequent traps from 500+ hours of direct ops.",[23,3963,3964,3967,3968,3971],{},[26,3965,3966],{},"Trap 1: Vague descriptions clog the router."," \"Use when engineering tasks\" is too broad — task-dispatcher routes UI, schema, and infra hygiene all to backend-engineer. Workaround: write the description as ",[26,3969,3970],{},"a symmetric \"Use when X. Do not invoke for Y.\""," The Y side is what actually sharpens routing accuracy.",[23,3973,3974,3977,3978,294,3980,3982,3983,3985],{},[26,3975,3976],{},"Trap 2: Validation logic drifts."," When UI server actions, REST routes, and CLI each carry their own validation, the specs diverge. Workaround: keep ",[35,3979,293],{},[35,3981,297],{}," as the only exports from ",[35,3984,289],{}," and route every entry path through them. This works precisely because the CLI shares the same Prisma client.",[23,3987,3988,3991,3992,3994,3995,3997,3998,4000,4001,4003,4004,4007],{},[26,3989,3990],{},"Trap 3: The board rots."," Tasks completed but never transitioned out of ",[35,3993,1210],{}," accumulate — dozens within days. Workaround: a nightly ",[35,3996,2075],{}," flags non-Done / non-Archived tasks whose ",[35,3999,2079],{}," is over 72 hours old as ",[35,4002,2083],{},". Crucially, ",[26,4005,4006],{},"it never auto-archives."," infra-ops surfaces \"this looks stale\" to the operator; the call stays human.",[23,4009,4010,4013],{},[26,4011,4012],{},"Trap 4: AI-flavored prose creeps in."," With content-director alone, \"as you can see\" phrasing and em-dash padding inevitably leak through. The workaround is keeping anti-ai-slop-reviewer at the final check stage, with a list of phrases I never use, forcing a rewrite on any hit.",[23,4015,4016,4019,4020,4022,4023,4025,4026,2494,4028,4030,4031,4033,4034,4036],{},[26,4017,4018],{},"Trap 5: Connection management on Vercel + Neon."," Vercel serverless functions open a fresh connection per invocation, which hits Neon's connection limit fast. The workaround is to point ",[35,4021,335],{}," at Neon's ",[26,4024,2106],{}," with ",[35,4027,2109],{},[35,4029,339],{}," at the direct endpoint reserved for ",[35,4032,343],{},". Routes that run in edge runtime get switched to ",[35,4035,2119],{}," (the HTTP/WebSocket driver). That three-lane setup has been the most stable so far. Prisma Data Proxy is another option, but it conflicts with the \"CLI and UI share the same Prisma client\" principle, so I haven't adopted it.",[47,4038],{},[50,4040,4042],{"id":4041},"wrap-up","Wrap-Up",[23,4044,4045],{},"After 500 hours of direct operations and roughly 1,000 hours of cumulative runtime, the conclusion is simpler than I expected.",[1813,4047,4048,4054,4063,4074],{},[1816,4049,4050,4053],{},[26,4051,4052],{},"Don't make one AI do everything."," Twelve agents, physically isolated context.",[1816,4055,4056,4059,4060,4062],{},[26,4057,4058],{},"Everyone shares the same memory."," The ",[35,4061,306],{}," vault and Prisma task board are the shared memory.",[1816,4064,4065,2483,4068,4070,4071,4073],{},[26,4066,4067],{},"Handoff in writing, not in conversation.",[35,4069,2153],{}," plus an append-only ",[35,4072,1148],{}," JSON is the durable log.",[1816,4075,4076,4079,4080,4082],{},[26,4077,4078],{},"Codify ownership and hard stops."," Anything not in ",[35,4081,244],{}," is something AI will not infer.",[23,4084,4085,4086,4089],{},"These four are nearly identical to the methodology I used when standardizing the investment team's DD process. There's nothing AI-specific required as a principle — ",[26,4087,4088],{},"the answers human organizations have refined over a long arc still apply, with AI's distinct strengths layered on top (24/7 uptime, cost optimization, parallelism)."," That's the view from where I currently stand.",[23,4091,4092,4093,4096,4097,4100],{},"Arguing about which model is strongest is a surface-level game. ",[26,4094,4095],{},"The real edge comes from how you run it."," Whether your stack is Claude, Gemini, or GPT, a Prisma table plus a markdown vault as the shared substrate carries over. ",[26,4098,4099],{},"And the moment that Prisma table sits on Neon, four pieces of gear show up at once: branching, PITR, pgvector, and suspend-on-idle."," Running 12 autonomous subagents against a real production database without flinching is what that combination buys you.",[47,4102],{},[23,4104,4105],{},[1630,4106,4107,4108,4111],{},"Disclaimer: This article is for informational and educational purposes only and does not constitute a recommendation of any specific security or investment advice. Tool and technology details reflect the state at the time of writing — please consult each vendor's official documentation for current information. Generative AI is used to assist research, translation, and proofreading; final content is reviewed by ZYL0. See the ",[2189,4109,4110],{"href":2191},"disclaimer page"," for details.",[4113,4114,4115],"style",{},"html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}html pre.shiki code .sCp4m, html code.shiki .sCp4m{--shiki-default:#8BE9FD;--shiki-default-font-style:italic}",{"title":273,"searchDepth":388,"depth":388,"links":4117},[4118,4119,4120,4121,4122,4128,4129,4130,4131,4132,4133,4138,4139,4140,4141,4142,4143,4144,4151,4152,4153,4154,4155,4156,4161,4162],{"id":52,"depth":388,"text":53},{"id":134,"depth":388,"text":135},{"id":174,"depth":388,"text":175},{"id":257,"depth":388,"text":258},{"id":349,"depth":388,"text":350,"children":4123},[4124,4125,4126,4127],{"id":365,"depth":415,"text":366},{"id":485,"depth":415,"text":486},{"id":547,"depth":415,"text":548},{"id":827,"depth":415,"text":828},{"id":839,"depth":388,"text":840},{"id":946,"depth":388,"text":946},{"id":1137,"depth":388,"text":1138},{"id":1731,"depth":388,"text":1732},{"id":1798,"depth":388,"text":1799},{"id":1967,"depth":388,"text":1968,"children":4134},[4135,4136,4137],{"id":1974,"depth":415,"text":1975},{"id":1989,"depth":415,"text":1990},{"id":2011,"depth":415,"text":2012},{"id":2031,"depth":388,"text":2032},{"id":2125,"depth":388,"text":2125},{"id":2228,"depth":388,"text":2229},{"id":2304,"depth":388,"text":2305},{"id":2347,"depth":388,"text":2348},{"id":2429,"depth":388,"text":2430},{"id":2523,"depth":388,"text":2524,"children":4145},[4146,4147,4148,4150],{"id":2534,"depth":415,"text":2535},{"id":2620,"depth":415,"text":2621},{"id":2670,"depth":415,"text":4149},"3. pgvector for semantic recall over knowledge/",{"id":2880,"depth":415,"text":2881},{"id":2892,"depth":388,"text":2893},{"id":2986,"depth":388,"text":2987},{"id":3146,"depth":388,"text":3147},{"id":3658,"depth":388,"text":3659},{"id":3715,"depth":388,"text":3716},{"id":3873,"depth":388,"text":3874,"children":4157},[4158,4159,4160],{"id":3880,"depth":415,"text":3881},{"id":3895,"depth":415,"text":3896},{"id":3930,"depth":415,"text":3931},{"id":3957,"depth":388,"text":3958},{"id":4041,"depth":388,"text":4042},"一つのAIに全部やらせる時代は終わった。Next.js + Prisma + Neon（serverless Postgres）で自作した一人会社用OSと、12体のClaude Codeサブエージェントを「組織」として回す設計思想を、Neonブランチ・PITR・pgvectorの活用も含め実装レベルで公開する。","md",{"date":4166,"image":4167,"alt":4168,"tags":4169,"tagsEn":4171,"published":431},"10th May 2026","/blogs-img/blog-ai-agent-organization-1000-hours.png","12体のサブエージェントとNeon × Prismaタスクボードで構成される一人会社AI OSのアーキテクチャ図",[4170],"テック解説",[4172],"Tech Deep Dive","/blogs/15-ai-agent-organization-1000-hours",{"title":6,"description":4163},"blogs/15-ai-agent-organization-1000-hours","KcHLFiPBNLDtoscAF6i3R7AQD2SmsA3gDeBjLxq-lNs",{"id":4178,"title":4179,"body":4180,"description":6483,"extension":4164,"meta":6484,"navigation":431,"ogImage":6486,"path":6492,"seo":6493,"stem":6494,"__hash__":6495},"content/blogs/13-claude-skills-mcp-web-video-engineer-guide.md","Claude Skills・MCP・ウェブ制作・動画生成を実務で使い倒す：エンジニア向け実践ガイド2026 | Claude Skills, MCP, Website Generation, and Programmatic Video in Production: A Practical Engineer's Guide 2026",{"type":8,"value":4181,"toc":6429},[4182,5329,5331,6426],[11,4183,4184,4188,4195,4206,4208,4210,4262,4264,4268,4271,4281,4288,4362,4365,4369,4372,4375,4378,4460,4462,4466,4469,4472,4475,4511,4515,4518,4660,4664,4764,4767,4809,4816,4818,4822,4825,4828,4832,4835,4912,4915,4919,4922,4954,4957,4959,4963,4970,4973,5022,5025,5028,5031,5037,5040,5084,5087,5155,5158,5160,5163,5166,5170,5183,5189,5195,5199,5205,5215,5218,5224,5230,5234,5240,5246,5252,5254,5257,5318,5321,5323],{"lang":13},[15,4185,4187],{"id":4186},"claude-skillsmcpウェブ制作動画生成を実務で使い倒すエンジニア向け実践ガイド2026","Claude Skills・MCP・ウェブ制作・動画生成を実務で使い倒す：エンジニア向け実践ガイド2026",[20,4189,4190],{},[23,4191,4192,4194],{},[26,4193,28],{},": 本記事は2026年5月時点の情報を基に執筆している。mcp Python SDK 1.27.0、MCP仕様 2025-11-25リビジョン、Remotion最新版を参照している。MCPの仕様更新は活発なため、公式ドキュメント（modelcontextprotocol.io）で最新情報を確認することを推奨する。",[23,4196,4197,4198,4201,4202,4205],{},"私は半導体プロセス開発からCVCに転身し、AWS（IoT Core・Lambda・DynamoDB・API Gateway）でゼロから河川洪水検知システムを6ヶ月で立ち上げた経験があります。",[26,4199,4200],{},"「動かしてみないと本当の落とし穴は見えない」","——これがエンジニアリング現場で身に染みた感覚で、Skills・MCP・Remotionも同じでした。今回はドキュメントを読むだけでは見えない",[26,4203,4204],{},"ハマりどころと最短実装パス","を、実際に手を動かした上で書きます。",[47,4207],{},[50,4209,53],{"id":52},[55,4211,4212,4220],{},[58,4213,4214],{},[61,4215,4216,4218],{},[64,4217,66],{},[64,4219,69],{},[71,4221,4222,4230,4238,4246,4254],{},[61,4223,4224,4227],{},[76,4225,4226],{},"Claude Skills",[76,4228,4229],{},"SKILL.mdの仕組み・MCP との役割分担・実務での使い方",[61,4231,4232,4235],{},[76,4233,4234],{},"MCP サーバー構築",[76,4236,4237],{},"Python FastMCP で50行以下のサーバーを作る最短手順",[61,4239,4240,4243],{},[76,4241,4242],{},"ウェブサイト生成",[76,4244,4245],{},"Claude Code + Next.js / Nuxt 4 でのサイト生成ワークフロー",[61,4247,4248,4251],{},[76,4249,4250],{},"Remotion 動画制作",[76,4252,4253],{},"コードで動画を書いてClaude Codeでレンダリングする実践手順",[61,4255,4256,4259],{},[76,4257,4258],{},"ハマりポイント",[76,4260,4261],{},"それぞれの罠と回避策",[47,4263],{},[50,4265,4267],{"id":4266},"skills-と-mcp-は何が違うのか役割を正確に理解する","Skills と MCP は何が違うのか——役割を正確に理解する",[23,4269,4270],{},"Claude CodeやClaude.aiを使い込んでいくと、必ずぶつかる疑問がある。「Skills と MCP って結局どう使い分けるの？」だ。ドキュメントを読んでもピンとこない場合、次のメンタルモデルが効く。",[23,4272,4273,4276,4277,4280],{},[26,4274,4275],{},"Skills = エージェントの「手順書」","、",[26,4278,4279],{},"MCP = エージェントの「外部接続線」","。",[23,4282,4283,4284,4287],{},"Skillsは",[35,4285,4286],{},".claude/skills/","以下に置いたSKILL.mdファイルだ。Claudeがタスクの文脈を判断し、関連するSkillを自動でロードして指示に従う。コードを書かず、マークダウンを書くだけで動く。一方MCPはJSON-RPC 2.0で動くクライアント・サーバープロトコルで、ClaudeをGitHub・データベース・社内APIなどの外部システムに繋ぐ。",[55,4289,4290,4303],{},[58,4291,4292],{},[61,4293,4294,4297,4300],{},[64,4295,4296],{},"比較軸",[64,4298,4299],{},"Skills",[64,4301,4302],{},"MCP",[71,4304,4305,4316,4327,4338,4349],{},[61,4306,4307,4310,4313],{},[76,4308,4309],{},"実装言語",[76,4311,4312],{},"Markdown（SKILL.md）",[76,4314,4315],{},"Python / TypeScript / Go など",[61,4317,4318,4321,4324],{},[76,4319,4320],{},"コンテキスト消費",[76,4322,4323],{},"30〜50トークン（必要時のみロード）",[76,4325,4326],{},"50,000トークン超になることも",[61,4328,4329,4332,4335],{},[76,4330,4331],{},"用途",[76,4333,4334],{},"手順・ベストプラクティスの埋め込み",[76,4336,4337],{},"外部システムとのリアルタイム連携",[61,4339,4340,4343,4346],{},[76,4341,4342],{},"横断性",[76,4344,4345],{},"Claude Code / Cursor / Gemini CLI で共通動作",[76,4347,4348],{},"MCP対応クライアント全般で動作",[61,4350,4351,4354,4359],{},[76,4352,4353],{},"設定方法",[76,4355,4356,4358],{},[35,4357,4286],{}," にファイルを置くだけ",[76,4360,4361],{},"サーバーを立ててclaude_desktop_config.jsonに登録",[23,4363,4364],{},"重要な点は「SkillはMCPツールを呼べる」という非対称性だ。Skillで手順を定義し、MCPで外部ツールを接続する——両方組み合わせることで初めてフルオートのエージェントができる。",[363,4366,4368],{"id":4367},"skills-の実務パターン","Skills の実務パターン",[23,4370,4371],{},"2026年3月時点のSkillsエコシステムは、公式Anthropicスキル・検証済みサードパーティ・コミュニティスキルの三層構造になっている。frontend-designスキルが27万インストール超、Remotionスキルが週11.7万インストール、gws（Google Workspace）が公開3日で4,900 GitHubスターを記録した。",[23,4373,4374],{},"実務でSkillが威力を発揮するのは「同じ手順を何度も説明するのが嫌な場面」全般だ。独自DBスキーマを理解するSQLアシスタントSkill・社内コーディング規約を埋め込んだレビューSkill・独自データ形式の変換Skillなどを一度書けば、以降はプロンプト一行で呼び出せる。",[23,4376,4377],{},"SKILL.mdを自分で書く場合の最小構成は以下だ：",[267,4379,4381],{"className":952,"code":4380,"language":954,"meta":273,"style":273},"---\nname: my-skill\ndescription: >\n  説明。Claudeがこれを見てスキルをロードするかを判断する。\n  トリガー条件を具体的に書くこと。\n---\n\n# My Skill\n\n## 手順\n\n1. まず〇〇を確認する\n2. 次に△△を実行する\n\n## 落とし穴\n\n- □□の場合は××してはいけない\n",[35,4382,4383,4387,4392,4396,4401,4406,4410,4414,4419,4423,4428,4432,4437,4442,4446,4451,4455],{"__ignoreMap":273},[378,4384,4385],{"class":380,"line":381},[378,4386,961],{},[378,4388,4389],{"class":380,"line":388},[378,4390,4391],{},"name: my-skill\n",[378,4393,4394],{"class":380,"line":415},[378,4395,971],{},[378,4397,4398],{"class":380,"line":428},[378,4399,4400],{},"  説明。Claudeがこれを見てスキルをロードするかを判断する。\n",[378,4402,4403],{"class":380,"line":435},[378,4404,4405],{},"  トリガー条件を具体的に書くこと。\n",[378,4407,4408],{"class":380,"line":441},[378,4409,961],{},[378,4411,4412],{"class":380,"line":458},[378,4413,432],{"emptyLinePlaceholder":431},[378,4415,4416],{"class":380,"line":463},[378,4417,4418],{},"# My Skill\n",[378,4420,4421],{"class":380,"line":469},[378,4422,432],{"emptyLinePlaceholder":431},[378,4424,4425],{"class":380,"line":701},[378,4426,4427],{},"## 手順\n",[378,4429,4430],{"class":380,"line":712},[378,4431,432],{"emptyLinePlaceholder":431},[378,4433,4434],{"class":380,"line":722},[378,4435,4436],{},"1. まず〇〇を確認する\n",[378,4438,4439],{"class":380,"line":733},[378,4440,4441],{},"2. 次に△△を実行する\n",[378,4443,4444],{"class":380,"line":739},[378,4445,432],{"emptyLinePlaceholder":431},[378,4447,4448],{"class":380,"line":748},[378,4449,4450],{},"## 落とし穴\n",[378,4452,4453],{"class":380,"line":754},[378,4454,432],{"emptyLinePlaceholder":431},[378,4456,4457],{"class":380,"line":772},[378,4458,4459],{},"- □□の場合は××してはいけない\n",[47,4461],{},[50,4463,4465],{"id":4464},"mcpサーバーを50行で作るpython-fastmcp-最短実装","MCPサーバーを50行で作る——Python FastMCP 最短実装",[23,4467,4468],{},"MCPの普及速度は前例がない。2024年11月の公開時に月200万SDK DLだったものが、OpenAI採用（2025年3月）・Microsoft統合（7月）・AWS対応（11月）を経て、2026年3月には9,700万DL/月、公開サーバー1万超に達した。ReactはこのDL数に3年かかったが、MCPは16ヶ月でやってのけた。",[23,4470,4471],{},"MCPが解決する問題はシンプルだ。社内CRM・請求システム・機能フラグサービスをAIエージェントから叩くには、従来クライアントAIごとに別の統合コードを書く必要があった。MCP対応サーバーを一つ作れば、Claude・ChatGPT・Cursor・Gemini全クライアントで動く。",[363,4473,4474],{"id":4474},"セットアップ",[267,4476,4478],{"className":372,"code":4477,"language":374,"meta":273,"style":273},"# uv 推奨（pip でも可）\nuv add mcp\n# または\npip install mcp\n",[35,4479,4480,4485,4496,4501],{"__ignoreMap":273},[378,4481,4482],{"class":380,"line":381},[378,4483,4484],{"class":384},"# uv 推奨（pip でも可）\n",[378,4486,4487,4490,4493],{"class":380,"line":388},[378,4488,4489],{"class":391},"uv",[378,4491,4492],{"class":395}," add",[378,4494,4495],{"class":395}," mcp\n",[378,4497,4498],{"class":380,"line":415},[378,4499,4500],{"class":384},"# または\n",[378,4502,4503,4506,4509],{"class":380,"line":428},[378,4504,4505],{"class":391},"pip",[378,4507,4508],{"class":395}," install",[378,4510,4495],{"class":395},[363,4512,4514],{"id":4513},"最小構成サーバーpython-fastmcp","最小構成サーバー（Python FastMCP）",[23,4516,4517],{},"以下は実際に動くMCPサーバーの最小実装だ。Tools・Resources・Promptsの三要素を全て含む：",[267,4519,4523],{"className":4520,"code":4521,"language":4522,"meta":273,"style":273},"language-python shiki shiki-themes dracula","from mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"my-service\", json_response=True)\n\n# Tool: 副作用のある操作（POSTに相当）\n@mcp.tool()\ndef check_stock(sku: str) -> dict:\n    \"\"\"指定SKUの在庫数を返す\"\"\"\n    # 実際はDBクエリ等に置き換える\n    return {\"sku\": sku, \"quantity\": 42, \"warehouse\": \"tokyo\"}\n\n# Resource: 読み取り専用データ（GETに相当）\n@mcp.resource(\"products://catalog\")\ndef get_catalog() -> str:\n    \"\"\"商品カタログの一覧を返す\"\"\"\n    return \"SKU-001: Widget A\\nSKU-002: Widget B\"\n\n# Prompt: 再利用可能なプロンプトテンプレート\n@mcp.prompt()\ndef stock_check_prompt(sku: str) -> str:\n    \"\"\"在庫確認のためのプロンプトを生成\"\"\"\n    return f\"SKU {sku} の在庫を確認し、少ない場合は補充を提案してください。\"\n\nif __name__ == \"__main__\":\n    # ローカル開発: stdio\n    # mcp.run()\n    # リモート/本番: Streamable HTTP\n    mcp.run(transport=\"streamable-http\", host=\"0.0.0.0\", port=3050)\n","python",[35,4524,4525,4530,4534,4539,4543,4548,4553,4558,4563,4568,4573,4577,4582,4587,4592,4597,4602,4606,4611,4616,4621,4626,4631,4635,4640,4645,4650,4655],{"__ignoreMap":273},[378,4526,4527],{"class":380,"line":381},[378,4528,4529],{},"from mcp.server.fastmcp import FastMCP\n",[378,4531,4532],{"class":380,"line":388},[378,4533,432],{"emptyLinePlaceholder":431},[378,4535,4536],{"class":380,"line":415},[378,4537,4538],{},"mcp = FastMCP(\"my-service\", json_response=True)\n",[378,4540,4541],{"class":380,"line":428},[378,4542,432],{"emptyLinePlaceholder":431},[378,4544,4545],{"class":380,"line":435},[378,4546,4547],{},"# Tool: 副作用のある操作（POSTに相当）\n",[378,4549,4550],{"class":380,"line":441},[378,4551,4552],{},"@mcp.tool()\n",[378,4554,4555],{"class":380,"line":458},[378,4556,4557],{},"def check_stock(sku: str) -> dict:\n",[378,4559,4560],{"class":380,"line":463},[378,4561,4562],{},"    \"\"\"指定SKUの在庫数を返す\"\"\"\n",[378,4564,4565],{"class":380,"line":469},[378,4566,4567],{},"    # 実際はDBクエリ等に置き換える\n",[378,4569,4570],{"class":380,"line":701},[378,4571,4572],{},"    return {\"sku\": sku, \"quantity\": 42, \"warehouse\": \"tokyo\"}\n",[378,4574,4575],{"class":380,"line":712},[378,4576,432],{"emptyLinePlaceholder":431},[378,4578,4579],{"class":380,"line":722},[378,4580,4581],{},"# Resource: 読み取り専用データ（GETに相当）\n",[378,4583,4584],{"class":380,"line":733},[378,4585,4586],{},"@mcp.resource(\"products://catalog\")\n",[378,4588,4589],{"class":380,"line":739},[378,4590,4591],{},"def get_catalog() -> str:\n",[378,4593,4594],{"class":380,"line":748},[378,4595,4596],{},"    \"\"\"商品カタログの一覧を返す\"\"\"\n",[378,4598,4599],{"class":380,"line":754},[378,4600,4601],{},"    return \"SKU-001: Widget A\\nSKU-002: Widget B\"\n",[378,4603,4604],{"class":380,"line":772},[378,4605,432],{"emptyLinePlaceholder":431},[378,4607,4608],{"class":380,"line":778},[378,4609,4610],{},"# Prompt: 再利用可能なプロンプトテンプレート\n",[378,4612,4613],{"class":380,"line":793},[378,4614,4615],{},"@mcp.prompt()\n",[378,4617,4618],{"class":380,"line":808},[378,4619,4620],{},"def stock_check_prompt(sku: str) -> str:\n",[378,4622,4623],{"class":380,"line":814},[378,4624,4625],{},"    \"\"\"在庫確認のためのプロンプトを生成\"\"\"\n",[378,4627,4628],{"class":380,"line":1059},[378,4629,4630],{},"    return f\"SKU {sku} の在庫を確認し、少ない場合は補充を提案してください。\"\n",[378,4632,4633],{"class":380,"line":1064},[378,4634,432],{"emptyLinePlaceholder":431},[378,4636,4637],{"class":380,"line":1070},[378,4638,4639],{},"if __name__ == \"__main__\":\n",[378,4641,4642],{"class":380,"line":1076},[378,4643,4644],{},"    # ローカル開発: stdio\n",[378,4646,4647],{"class":380,"line":1082},[378,4648,4649],{},"    # mcp.run()\n",[378,4651,4652],{"class":380,"line":1088},[378,4653,4654],{},"    # リモート/本番: Streamable HTTP\n",[378,4656,4657],{"class":380,"line":1093},[378,4658,4659],{},"    mcp.run(transport=\"streamable-http\", host=\"0.0.0.0\", port=3050)\n",[363,4661,4663],{"id":4662},"claude-desktop-への登録","Claude Desktop への登録",[267,4665,4669],{"className":4666,"code":4667,"language":4668,"meta":273,"style":273},"language-json shiki shiki-themes dracula","{\n  \"mcpServers\": {\n    \"my-service\": {\n      \"command\": \"python\",\n      \"args\": [\"/path/to/server.py\"]\n    }\n  }\n}\n","json",[35,4670,4671,4676,4693,4707,4727,4750,4755,4760],{"__ignoreMap":273},[378,4672,4673],{"class":380,"line":381},[378,4674,4675],{"class":578},"{\n",[378,4677,4678,4682,4686,4689,4691],{"class":380,"line":388},[378,4679,4681],{"class":4680},"sY8FZ","  \"",[378,4683,4685],{"class":4684},"sLL85","mcpServers",[378,4687,4688],{"class":4680},"\"",[378,4690,635],{"class":505},[378,4692,1404],{"class":578},[378,4694,4695,4698,4701,4703,4705],{"class":380,"line":415},[378,4696,4697],{"class":4680},"    \"",[378,4699,4700],{"class":4684},"my-service",[378,4702,4688],{"class":4680},[378,4704,635],{"class":505},[378,4706,1404],{"class":578},[378,4708,4709,4712,4715,4717,4719,4721,4723,4725],{"class":380,"line":428},[378,4710,4711],{"class":4680},"      \"",[378,4713,4714],{"class":4684},"command",[378,4716,4688],{"class":4680},[378,4718,635],{"class":505},[378,4720,535],{"class":534},[378,4722,4522],{"class":395},[378,4724,4688],{"class":534},[378,4726,1192],{"class":578},[378,4728,4729,4731,4734,4736,4738,4740,4742,4745,4747],{"class":380,"line":435},[378,4730,4711],{"class":4680},[378,4732,4733],{"class":4684},"args",[378,4735,4688],{"class":4680},[378,4737,635],{"class":505},[378,4739,1283],{"class":578},[378,4741,4688],{"class":534},[378,4743,4744],{"class":395},"/path/to/server.py",[378,4746,4688],{"class":534},[378,4748,4749],{"class":578},"]\n",[378,4751,4752],{"class":380,"line":441},[378,4753,4754],{"class":578},"    }\n",[378,4756,4757],{"class":380,"line":458},[378,4758,4759],{"class":578},"  }\n",[378,4761,4762],{"class":380,"line":463},[378,4763,817],{"class":578},[363,4765,4766],{"id":4766},"トランスポートの選び方",[55,4768,4769,4781],{},[58,4770,4771],{},[61,4772,4773,4776,4778],{},[64,4774,4775],{},"トランスポート",[64,4777,4331],{},[64,4779,4780],{},"注意",[71,4782,4783,4796],{},[61,4784,4785,4790,4793],{},[76,4786,4787],{},[35,4788,4789],{},"stdio",[76,4791,4792],{},"ローカル・Claude Desktop連携・開発",[76,4794,4795],{},"ネットワーク設定不要",[61,4797,4798,4803,4806],{},[76,4799,4800],{},[35,4801,4802],{},"streamable-http",[76,4804,4805],{},"リモート・チーム共有・クラウドデプロイ",[76,4807,4808],{},"2025年3月仕様で標準化。SSE は非推奨",[23,4810,4811,4812,4815],{},"TypeScriptで書く場合は",[35,4813,4814],{},"@modelcontextprotocol/sdk","とZodを使う。Python FastMCPと同じ三要素（Tool / Resource / Prompt）をサポートし、型安全性が高い。どちらの言語でも「ワイヤプロトコルはJSON-RPC 2.0で共通」なので、PythonサーバーにTypeScriptクライアントを繋ぐことも普通に動く。",[47,4817],{},[50,4819,4821],{"id":4820},"claude-code-でウェブサイトを生成するclaudemdとskillの組み合わせ","Claude Code でウェブサイトを生成する——CLAUDE.mdとSkillの組み合わせ",[23,4823,4824],{},"2026年初頭時点でClaude Codeは全GitHubコミットの4%を生成しており、VS Codeへの日次インストールは2,900万に達した。「バイブコーディング」と呼ばれるこのワークフローは、エンジニア経験ゼロの人でもNext.jsアプリを作れるレベルに成熟している。",[23,4826,4827],{},"ただしClaudeに「サイト作って」と言うだけでは、Interフォント・パープルグラデーション・白背景というお約束の「AI生成デザイン」が出てくる。これを回避するのがCLAUDE.mdとSkillの組み合わせだ。",[363,4829,4831],{"id":4830},"claudemdの位置づけ","CLAUDE.mdの位置づけ",[23,4833,4834],{},"プロジェクトルートに置くCLAUDE.mdはClaude Codeがセッション開始時に自動読み込みする設定ファイルだ。ここに「プロジェクトのコンテキスト」を書く：",[267,4836,4838],{"className":952,"code":4837,"language":954,"meta":273,"style":273},"# Project: MyApp\n\n## スタック\n- Nuxt 4 (Nuxt Content 3, Vue 3 Composition API)\n- Tailwind CSS v4, shadcn/ui\n- Vercel デプロイ\n\n## ルール\n- コミット前に必ずビルドを通す\n- TypeScript strict モード必須\n- MDX コンポーネントは使わない（Nuxt Content の CommonMark のみ）\n\n## 禁止事項\n- console.log を残したままコミットしない\n- any 型の使用\n",[35,4839,4840,4845,4849,4854,4859,4864,4869,4873,4878,4883,4888,4893,4897,4902,4907],{"__ignoreMap":273},[378,4841,4842],{"class":380,"line":381},[378,4843,4844],{},"# Project: MyApp\n",[378,4846,4847],{"class":380,"line":388},[378,4848,432],{"emptyLinePlaceholder":431},[378,4850,4851],{"class":380,"line":415},[378,4852,4853],{},"## スタック\n",[378,4855,4856],{"class":380,"line":428},[378,4857,4858],{},"- Nuxt 4 (Nuxt Content 3, Vue 3 Composition API)\n",[378,4860,4861],{"class":380,"line":435},[378,4862,4863],{},"- Tailwind CSS v4, shadcn/ui\n",[378,4865,4866],{"class":380,"line":441},[378,4867,4868],{},"- Vercel デプロイ\n",[378,4870,4871],{"class":380,"line":458},[378,4872,432],{"emptyLinePlaceholder":431},[378,4874,4875],{"class":380,"line":463},[378,4876,4877],{},"## ルール\n",[378,4879,4880],{"class":380,"line":469},[378,4881,4882],{},"- コミット前に必ずビルドを通す\n",[378,4884,4885],{"class":380,"line":701},[378,4886,4887],{},"- TypeScript strict モード必須\n",[378,4889,4890],{"class":380,"line":712},[378,4891,4892],{},"- MDX コンポーネントは使わない（Nuxt Content の CommonMark のみ）\n",[378,4894,4895],{"class":380,"line":722},[378,4896,432],{"emptyLinePlaceholder":431},[378,4898,4899],{"class":380,"line":733},[378,4900,4901],{},"## 禁止事項\n",[378,4903,4904],{"class":380,"line":739},[378,4905,4906],{},"- console.log を残したままコミットしない\n",[378,4908,4909],{"class":380,"line":748},[378,4910,4911],{},"- any 型の使用\n",[23,4913,4914],{},"CLAUDE.mdとSkillの役割分担は明確だ。CLAUDE.mdは「このプロジェクトの文脈」、Skillは「このタスクのやり方」。両方あることで、プロジェクトを知りつつ特定作業を正しくこなすエージェントができる。",[363,4916,4918],{"id":4917},"nextjs-nuxt-でのサイト生成ワークフロー","Next.js / Nuxt でのサイト生成ワークフロー",[23,4920,4921],{},"実際に動くフローは以下になる：",[4923,4924,4925,4931,4940,4948],"ol",{},[1816,4926,4927,4930],{},[26,4928,4929],{},"CLAUDE.mdを作成",": スタック・命名規則・禁止事項を記述",[1816,4932,4933,4936,4937],{},[26,4934,4935],{},"公式または自作Skillを追加",": ",[35,4938,4939],{},"npx skills add frontend-design",[1816,4941,4942,4936,4945],{},[26,4943,4944],{},"プランモードで要件確認",[35,4946,4947],{},"claude --plan \"〇〇なランディングページを作りたい\"",[1816,4949,4950,4953],{},[26,4951,4952],{},"イテレーティブに実装",": 一度に全部頼まず、セクション単位で進める",[23,4955,4956],{},"重要なのはステップ3のプランモードだ。いきなり実装させると「間違った問題を解くコード」が生成されることがある。まずClaudeに既存のコードベースを探索させ、変更箇所・影響範囲・エッジケースを特定したプランを出させる。プランを確認してからイエスと言うだけで、実装ミスの大半を防げる。",[47,4958],{},[50,4960,4962],{"id":4961},"claude-code-remotion-で動画をコードで書く","Claude Code + Remotion で動画をコードで書く",[23,4964,4965,4966,4969],{},"「動画をコードで管理する」という発想は、フロントエンドエンジニアには自然に受け入れられる。Remotionはまさにそれを実現するReactベースの動画フレームワークで、",[35,4967,4968],{},"useCurrentFrame()","でフレーム番号を取得しアニメーションをコードで記述する。Claude Codeとの組み合わせは「プロンプトで動画を書く」ワークフローを実現する。",[363,4971,4474],{"id":4972},"セットアップ-1",[267,4974,4976],{"className":372,"code":4975,"language":374,"meta":273,"style":273},"# Remotionプロジェクトを作成\nnpx create-video@latest my-video-project\ncd my-video-project\n\n# Agent Skillsをインストール（Remotionチームが提供するベストプラクティス集）\nnpx skills add remotion-dev/skills\n",[35,4977,4978,4983,4994,5001,5005,5010],{"__ignoreMap":273},[378,4979,4980],{"class":380,"line":381},[378,4981,4982],{"class":384},"# Remotionプロジェクトを作成\n",[378,4984,4985,4988,4991],{"class":380,"line":388},[378,4986,4987],{"class":391},"npx",[378,4989,4990],{"class":395}," create-video@latest",[378,4992,4993],{"class":395}," my-video-project\n",[378,4995,4996,4999],{"class":380,"line":415},[378,4997,4998],{"class":4684},"cd",[378,5000,4993],{"class":395},[378,5002,5003],{"class":380,"line":428},[378,5004,432],{"emptyLinePlaceholder":431},[378,5006,5007],{"class":380,"line":435},[378,5008,5009],{"class":384},"# Agent Skillsをインストール（Remotionチームが提供するベストプラクティス集）\n",[378,5011,5012,5014,5017,5019],{"class":380,"line":441},[378,5013,4987],{"class":391},[378,5015,5016],{"class":395}," skills",[378,5018,4492],{"class":395},[378,5020,5021],{"class":395}," remotion-dev/skills\n",[23,5023,5024],{},"SkillsをインストールするとClaude Codeがリモーションの規約を理解し、正しいコンポーネント構造でコードを生成できるようになる。38種類以上のカテゴリがあり、アニメーション・3D・字幕・音声・チャート・トランジションをカバーする。",[363,5026,5027],{"id":5027},"実際のプロンプト例",[23,5029,5030],{},"良いプロンプトの書き方にはコツがある。具体的な数字・解像度・秒数を最初に宣言し、シーンの境界を明示する：",[267,5032,5035],{"className":5033,"code":5034,"language":272,"meta":273},[270],"1920x1080px、30fps、10秒の動画を作って。\n\n0-2秒: ロゴフェードイン（中央配置、白背景）\n2-6秒: 3つの機能を順番にスライドイン（左から右）\n        - \"高速\" + 稲妻アイコン\n        - \"安全\" + シールドアイコン\n        - \"簡単\" + チェックアイコン\n6-9秒: CTAボタンが拡大して登場「今すぐ試す」\n9-10秒: フェードアウト\n\nカラー: bg #0a0a0a, accent #7c3aed, text white\n",[35,5036,5034],{"__ignoreMap":273},[23,5038,5039],{},"生成されたコードはRemotionスタジオでリアルタイムプレビューし、問題なければレンダリングする：",[267,5041,5043],{"className":372,"code":5042,"language":374,"meta":273,"style":273},"# プレビュー\nnpx remotion studio\n\n# レンダリング（MP4）\nnpx remotion render MyComposition out/video.mp4\n",[35,5044,5045,5050,5060,5064,5069],{"__ignoreMap":273},[378,5046,5047],{"class":380,"line":381},[378,5048,5049],{"class":384},"# プレビュー\n",[378,5051,5052,5054,5057],{"class":380,"line":388},[378,5053,4987],{"class":391},[378,5055,5056],{"class":395}," remotion",[378,5058,5059],{"class":395}," studio\n",[378,5061,5062],{"class":380,"line":415},[378,5063,432],{"emptyLinePlaceholder":431},[378,5065,5066],{"class":380,"line":428},[378,5067,5068],{"class":384},"# レンダリング（MP4）\n",[378,5070,5071,5073,5075,5078,5081],{"class":380,"line":435},[378,5072,4987],{"class":391},[378,5074,5056],{"class":395},[378,5076,5077],{"class":395}," render",[378,5079,5080],{"class":395}," MyComposition",[378,5082,5083],{"class":395}," out/video.mp4\n",[363,5085,5086],{"id":5086},"ユースケース別の向き不向き",[55,5088,5089,5102],{},[58,5090,5091],{},[61,5092,5093,5096,5099],{},[64,5094,5095],{},"ユースケース",[64,5097,5098],{},"向いている",[64,5100,5101],{},"向いていない",[71,5103,5104,5114,5124,5134,5145],{},[61,5105,5106,5109,5112],{},[76,5107,5108],{},"製品デモ動画",[76,5110,5111],{},"◎ データと連動した動的更新が容易",[76,5113,1662],{},[61,5115,5116,5119,5122],{},[76,5117,5118],{},"データビジュアライゼーション",[76,5120,5121],{},"◎ コードで数値を動的に渡せる",[76,5123,1662],{},[61,5125,5126,5129,5132],{},[76,5127,5128],{},"SNS縦型クリップ",[76,5130,5131],{},"◎ 9:16を指定するだけ",[76,5133,1662],{},[61,5135,5136,5139,5142],{},[76,5137,5138],{},"人物が話す動画",[76,5140,5141],{},"△ HeyGen等の専用ツールが優勢",[76,5143,5144],{},"複雑なリップシンク",[61,5146,5147,5150,5153],{},[76,5148,5149],{},"長尺映像（10分超）",[76,5151,5152],{},"△ シーン管理が煩雑になる",[76,5154,1662],{},[23,5156,5157],{},"ローカルレンダリングをするのでクラウド動画生成ツールのウォーターマーク・クレジット制限は一切関係ない。「ビルドアーティファクトとしての動画」という考え方で、製品変更のたびに動画をCI/CDで自動更新するパイプラインを組む事例もすでに登場している。",[47,5159],{},[50,5161,5162],{"id":5162},"ハマりポイントと回避策",[23,5164,5165],{},"実際に試してハマった点を正直に書く。",[363,5167,5169],{"id":5168},"mcp-関連","MCP 関連",[23,5171,5172,5175,5176,5178,5179,5182],{},[26,5173,5174],{},"SSEトランスポートを使っていてエラーが出る",": 2025年3月のMCP仕様アップデートでSSE（Server-Sent Events）トランスポートは非推奨になった。リモート接続には必ず",[35,5177,4802],{},"を使う。FastMCPなら",[35,5180,5181],{},"mcp.run(transport=\"streamable-http\")","に変えるだけで移行できる。",[23,5184,5185,5188],{},[26,5186,5187],{},"MCP サーバーを複数入れたら起動が遅くなった",": 5サーバー・58ツール構成だとコンテキスト消費が55,000トークンを超えることがある。AnthropicのTool Search機能（オンデマンドロード）を有効にすると約85%削減できる。モノリシックなサーバーを避け、用途別に小さく分割すること。",[23,5190,5191,5194],{},[26,5192,5193],{},"セキュリティ",": OWASP MCP Top 10（2025年公開）に従いサーバーを審査する。特にプロンプトインジェクション（ツールのdescriptionに悪意ある指示を埋め込む攻撃）に注意。コミュニティのサーバーは使用前にコードレビュー必須。",[363,5196,5198],{"id":5197},"skills-関連","Skills 関連",[23,5200,5201,5204],{},[26,5202,5203],{},"スキルが期待通りにトリガーされない",": descriptionフィールドが曖昧だとClaudeがスキルをロードしない。「〇〇というキーワードが出たら必ずこのSkillを使え」という強い表現を入れること。",[23,5206,5207,5210,5211,5214],{},[26,5208,5209],{},"コンテキスト上限付近でSkillが無視される",": セッションが長くなりコンテキストの70〜85%超えると精度が落ちる。",[35,5212,5213],{},"/compact","でコンテキストを圧縮するか、新しいセッションで継続する。",[363,5216,5217],{"id":5217},"ウェブサイト生成関連",[23,5219,5220,5223],{},[26,5221,5222],{},"一度に全部作らせようとした",": 「ECサイトを全部作って」は失敗率が高い。コンポーネント単位・ページ単位でイテレーティブに進めること。プランモードで方向性を確認してから実装させる。",[23,5225,5226,5229],{},[26,5227,5228],{},"生成コードをそのままコミットした",": ACM 2025年の研究で、LLMのコードは人間比で論理エラーが1.75倍多い可能性が示されている。テストを通してからコミットを徹底する。",[363,5231,5233],{"id":5232},"remotion-関連","Remotion 関連",[23,5235,5236,5239],{},[26,5237,5238],{},"最初から複雑な動画を作ろうとした",": 5秒のサンプルから始め、背景色→テキスト→アニメーション→複数シーンの順に積み上げること。",[23,5241,5242,5245],{},[26,5243,5244],{},"曖昧な指示を出した",": 「80px」「30フレーム（1秒）」のように数値で指定するとClaude Codeの精度が上がる。「大きいフォント」「ゆっくりフェード」は精度が下がる。",[23,5247,5248,5251],{},[26,5249,5250],{},"シーン間でキャラクターの外見が変わる",": Remotionは静的アセットを直接コードで参照するため、画像ファイルを固定すれば解決する。複雑な人物動画はHeyGen等の専用ツールを併用する。",[47,5253],{},[50,5255,5256],{"id":5256},"まとめと次のステップ",[55,5258,5259,5272],{},[58,5260,5261],{},[61,5262,5263,5266,5269],{},[64,5264,5265],{},"やること",[64,5267,5268],{},"優先度",[64,5270,5271],{},"所要時間",[71,5273,5274,5285,5295,5308],{},[61,5275,5276,5279,5282],{},[76,5277,5278],{},"MCPサーバーを一つ作る（社内API連携）",[76,5280,5281],{},"高",[76,5283,5284],{},"1〜2時間",[61,5286,5287,5290,5292],{},[76,5288,5289],{},"プロジェクトにCLAUDE.mdを追加",[76,5291,5281],{},[76,5293,5294],{},"30分",[61,5296,5297,5302,5305],{},[76,5298,5299,5301],{},[35,5300,4939],{}," を試す",[76,5303,5304],{},"中",[76,5306,5307],{},"10分",[61,5309,5310,5313,5315],{},[76,5311,5312],{},"Remotionで30秒のデモ動画を作る",[76,5314,5304],{},[76,5316,5317],{},"2〜3時間",[23,5319,5320],{},"Claude Codeがコミット全体の4%を生成し、Spotifyのエンジニアが2025年12月以降手でコードを書いていないという現在、これらのツールへの習熟は「あると便利」から「ないと遅い」に変わりつつある。まず一つのMCPサーバーかSkillから始め、「毎回説明するのが面倒なこと」を自動化するところから入るのが最短距離だ。",[47,5322],{},[23,5324,5325],{},[1630,5326,2187,5327,2193],{},[2189,5328,2192],{"href":2191},[47,5330],{},[11,5332,5333,5337,5344,5355,5357,5360,5411,5413,5417,5420,5428,5434,5509,5516,5520,5523,5526,5529,5609,5611,5615,5618,5621,5624,5655,5659,5662,5789,5793,5875,5879,5920,5926,5928,5932,5935,5938,5942,5945,6019,6022,6026,6029,6058,6061,6063,6067,6073,6076,6119,6122,6126,6129,6135,6138,6177,6181,6248,6251,6253,6257,6260,6263,6274,6280,6289,6292,6301,6310,6314,6320,6326,6330,6336,6342,6348,6350,6354,6415,6418,6420],{"lang":2198},[15,5334,5336],{"id":5335},"claude-skills-mcp-website-generation-and-programmatic-video-in-production-a-practical-engineers-guide-2026","Claude Skills, MCP, Website Generation, and Programmatic Video in Production: A Practical Engineer's Guide 2026",[20,5338,5339],{},[23,5340,5341,5343],{},[26,5342,2209],{},": This article is based on information as of May 2026. It references mcp Python SDK 1.27.0, MCP spec revision 2025-11-25, and the latest Remotion release. The MCP spec evolves rapidly, so verify the latest information at modelcontextprotocol.io.",[23,5345,5346,5347,5350,5351,5354],{},"I came up through semiconductor process development before moving to corporate VC, and I built a flood-detection IoT system from scratch on AWS (IoT Core, Lambda, DynamoDB, API Gateway) in about six months. The single most reliable lesson from that work: ",[26,5348,5349],{},"the real gotchas only show up when you run the code",". Skills, MCP, and Remotion behave the same way. So this piece is the ",[26,5352,5353],{},"shortest implementation path plus the actual gotchas"," I hit running everything end-to-end.",[47,5356],{},[50,5358,5359],{"id":2228},"TL;DR — What You'll Learn",[55,5361,5362,5371],{},[58,5363,5364],{},[61,5365,5366,5368],{},[64,5367,2238],{},[64,5369,5370],{},"What You'll Pick Up",[71,5372,5373,5380,5388,5396,5404],{},[61,5374,5375,5377],{},[76,5376,4226],{},[76,5378,5379],{},"How SKILL.md works, its split with MCP, day-to-day patterns",[61,5381,5382,5385],{},[76,5383,5384],{},"Building MCP servers",[76,5386,5387],{},"The shortest path to a Python FastMCP server in under 50 lines",[61,5389,5390,5393],{},[76,5391,5392],{},"Website generation",[76,5394,5395],{},"Site generation workflow with Claude Code + Next.js / Nuxt 4",[61,5397,5398,5401],{},[76,5399,5400],{},"Remotion video",[76,5402,5403],{},"Writing video as code and rendering it through Claude Code",[61,5405,5406,5408],{},[76,5407,2296],{},[76,5409,5410],{},"The traps in each area and how to dodge them",[47,5412],{},[50,5414,5416],{"id":5415},"skills-vs-mcp-getting-the-mental-model-right","Skills vs MCP — Getting the Mental Model Right",[23,5418,5419],{},"If you spend any real time with Claude Code or Claude.ai, you'll hit the same question: \"How do I actually decide between Skills and MCP?\" Reading the docs doesn't always make it click. The mental model that does:",[23,5421,5422,642,5425],{},[26,5423,5424],{},"Skills = the agent's \"playbook\"",[26,5426,5427],{},"MCP = the agent's \"external connections.\"",[23,5429,5430,5431,5433],{},"Skills are SKILL.md files placed under ",[35,5432,4286],{},". Claude reads the task context, automatically loads the relevant skill, and follows its instructions. You write Markdown — no code. MCP, in contrast, is a client-server protocol over JSON-RPC 2.0 that connects Claude to external systems like GitHub, databases, or internal APIs.",[55,5435,5436,5447],{},[58,5437,5438],{},[61,5439,5440,5443,5445],{},[64,5441,5442],{},"Dimension",[64,5444,4299],{},[64,5446,4302],{},[71,5448,5449,5460,5471,5482,5493],{},[61,5450,5451,5454,5457],{},[76,5452,5453],{},"Implementation language",[76,5455,5456],{},"Markdown (SKILL.md)",[76,5458,5459],{},"Python / TypeScript / Go, etc.",[61,5461,5462,5465,5468],{},[76,5463,5464],{},"Context consumption",[76,5466,5467],{},"30–50 tokens (loaded only when needed)",[76,5469,5470],{},"Can exceed 50,000 tokens",[61,5472,5473,5476,5479],{},[76,5474,5475],{},"Use case",[76,5477,5478],{},"Embedding procedures and best practices",[76,5480,5481],{},"Real-time integration with external systems",[61,5483,5484,5487,5490],{},[76,5485,5486],{},"Cross-tool",[76,5488,5489],{},"Works in Claude Code / Cursor / Gemini CLI",[76,5491,5492],{},"Works in any MCP-capable client",[61,5494,5495,5498,5503],{},[76,5496,5497],{},"Setup",[76,5499,5500,5501],{},"Drop a file under ",[35,5502,4286],{},[76,5504,5505,5506],{},"Run a server and register it in ",[35,5507,5508],{},"claude_desktop_config.json",[23,5510,5511,5512,5515],{},"The key asymmetry is: ",[26,5513,5514],{},"a Skill can call MCP tools, but not the other way around."," Define procedures with Skills, connect external tools with MCP — putting them together is what unlocks fully automated agents.",[363,5517,5519],{"id":5518},"real-world-skills-patterns","Real-World Skills Patterns",[23,5521,5522],{},"As of March 2026, the Skills ecosystem is structured in three layers: official Anthropic skills, vetted third-party skills, and community skills. The frontend-design skill has crossed 270K installs, the Remotion skill is doing 117K installs per week, and gws (Google Workspace) hit 4,900 GitHub stars within three days of release.",[23,5524,5525],{},"Skills shine in any situation where \"I'm tired of explaining the same procedure over and over.\" Write a SQL assistant skill that knows your custom DB schema once, embed your team's coding conventions into a review skill, build a converter skill for your proprietary data format — after that, a single one-line prompt invokes them.",[23,5527,5528],{},"The minimum SKILL.md, when you write your own:",[267,5530,5532],{"className":952,"code":5531,"language":954,"meta":273,"style":273},"---\nname: my-skill\ndescription: >\n  Description here. Claude reads this to decide whether to load the skill.\n  Spell out the trigger conditions concretely.\n---\n\n# My Skill\n\n## Steps\n\n1. First, check X.\n2. Then, run Y.\n\n## Pitfalls\n\n- When Z, do not do W.\n",[35,5533,5534,5538,5542,5546,5551,5556,5560,5564,5568,5572,5577,5581,5586,5591,5595,5600,5604],{"__ignoreMap":273},[378,5535,5536],{"class":380,"line":381},[378,5537,961],{},[378,5539,5540],{"class":380,"line":388},[378,5541,4391],{},[378,5543,5544],{"class":380,"line":415},[378,5545,971],{},[378,5547,5548],{"class":380,"line":428},[378,5549,5550],{},"  Description here. Claude reads this to decide whether to load the skill.\n",[378,5552,5553],{"class":380,"line":435},[378,5554,5555],{},"  Spell out the trigger conditions concretely.\n",[378,5557,5558],{"class":380,"line":441},[378,5559,961],{},[378,5561,5562],{"class":380,"line":458},[378,5563,432],{"emptyLinePlaceholder":431},[378,5565,5566],{"class":380,"line":463},[378,5567,4418],{},[378,5569,5570],{"class":380,"line":469},[378,5571,432],{"emptyLinePlaceholder":431},[378,5573,5574],{"class":380,"line":701},[378,5575,5576],{},"## Steps\n",[378,5578,5579],{"class":380,"line":712},[378,5580,432],{"emptyLinePlaceholder":431},[378,5582,5583],{"class":380,"line":722},[378,5584,5585],{},"1. First, check X.\n",[378,5587,5588],{"class":380,"line":733},[378,5589,5590],{},"2. Then, run Y.\n",[378,5592,5593],{"class":380,"line":739},[378,5594,432],{"emptyLinePlaceholder":431},[378,5596,5597],{"class":380,"line":748},[378,5598,5599],{},"## Pitfalls\n",[378,5601,5602],{"class":380,"line":754},[378,5603,432],{"emptyLinePlaceholder":431},[378,5605,5606],{"class":380,"line":772},[378,5607,5608],{},"- When Z, do not do W.\n",[47,5610],{},[50,5612,5614],{"id":5613},"building-an-mcp-server-in-50-lines-the-python-fastmcp-shortcut","Building an MCP Server in 50 Lines — The Python FastMCP Shortcut",[23,5616,5617],{},"MCP's adoption curve is unprecedented. From 2 million SDK downloads/month at launch (November 2024), it crossed 22 million when OpenAI adopted (March 2025), 45 million when Microsoft integrated (July), 68 million when AWS came on (November), and reached 97 million per month with over 10,000 public servers by March 2026. React took three years to reach those download numbers; MCP did it in 16 months.",[23,5619,5620],{},"The problem MCP solves is simple: previously, hooking your internal CRM, billing system, or feature-flag service into AI agents meant writing separate integration code for every AI client. Build one MCP-compatible server, and it works from Claude, ChatGPT, Cursor, and Gemini.",[363,5622,5497],{"id":5623},"setup",[267,5625,5627],{"className":372,"code":5626,"language":374,"meta":273,"style":273},"# uv recommended (pip works too)\nuv add mcp\n# or\npip install mcp\n",[35,5628,5629,5634,5642,5647],{"__ignoreMap":273},[378,5630,5631],{"class":380,"line":381},[378,5632,5633],{"class":384},"# uv recommended (pip works too)\n",[378,5635,5636,5638,5640],{"class":380,"line":388},[378,5637,4489],{"class":391},[378,5639,4492],{"class":395},[378,5641,4495],{"class":395},[378,5643,5644],{"class":380,"line":415},[378,5645,5646],{"class":384},"# or\n",[378,5648,5649,5651,5653],{"class":380,"line":428},[378,5650,4505],{"class":391},[378,5652,4508],{"class":395},[378,5654,4495],{"class":395},[363,5656,5658],{"id":5657},"minimal-server-python-fastmcp","Minimal Server (Python FastMCP)",[23,5660,5661],{},"Below is a minimal MCP server that actually runs. It includes all three primitives — Tools, Resources, and Prompts:",[267,5663,5665],{"className":4520,"code":5664,"language":4522,"meta":273,"style":273},"from mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"my-service\", json_response=True)\n\n# Tool: side-effecting operations (analogous to POST)\n@mcp.tool()\ndef check_stock(sku: str) -> dict:\n    \"\"\"Return the inventory count for the given SKU.\"\"\"\n    # In practice, replace with a DB query, etc.\n    return {\"sku\": sku, \"quantity\": 42, \"warehouse\": \"tokyo\"}\n\n# Resource: read-only data (analogous to GET)\n@mcp.resource(\"products://catalog\")\ndef get_catalog() -> str:\n    \"\"\"Return the product catalog listing.\"\"\"\n    return \"SKU-001: Widget A\\nSKU-002: Widget B\"\n\n# Prompt: a reusable prompt template\n@mcp.prompt()\ndef stock_check_prompt(sku: str) -> str:\n    \"\"\"Generate a prompt for checking inventory.\"\"\"\n    return f\"Check the stock for SKU {sku} and propose a restock if it is low.\"\n\nif __name__ == \"__main__\":\n    # Local dev: stdio\n    # mcp.run()\n    # Remote/production: Streamable HTTP\n    mcp.run(transport=\"streamable-http\", host=\"0.0.0.0\", port=3050)\n",[35,5666,5667,5671,5675,5679,5683,5688,5692,5696,5701,5706,5710,5714,5719,5723,5727,5732,5736,5740,5745,5749,5753,5758,5763,5767,5771,5776,5780,5785],{"__ignoreMap":273},[378,5668,5669],{"class":380,"line":381},[378,5670,4529],{},[378,5672,5673],{"class":380,"line":388},[378,5674,432],{"emptyLinePlaceholder":431},[378,5676,5677],{"class":380,"line":415},[378,5678,4538],{},[378,5680,5681],{"class":380,"line":428},[378,5682,432],{"emptyLinePlaceholder":431},[378,5684,5685],{"class":380,"line":435},[378,5686,5687],{},"# Tool: side-effecting operations (analogous to POST)\n",[378,5689,5690],{"class":380,"line":441},[378,5691,4552],{},[378,5693,5694],{"class":380,"line":458},[378,5695,4557],{},[378,5697,5698],{"class":380,"line":463},[378,5699,5700],{},"    \"\"\"Return the inventory count for the given SKU.\"\"\"\n",[378,5702,5703],{"class":380,"line":469},[378,5704,5705],{},"    # In practice, replace with a DB query, etc.\n",[378,5707,5708],{"class":380,"line":701},[378,5709,4572],{},[378,5711,5712],{"class":380,"line":712},[378,5713,432],{"emptyLinePlaceholder":431},[378,5715,5716],{"class":380,"line":722},[378,5717,5718],{},"# Resource: read-only data (analogous to GET)\n",[378,5720,5721],{"class":380,"line":733},[378,5722,4586],{},[378,5724,5725],{"class":380,"line":739},[378,5726,4591],{},[378,5728,5729],{"class":380,"line":748},[378,5730,5731],{},"    \"\"\"Return the product catalog listing.\"\"\"\n",[378,5733,5734],{"class":380,"line":754},[378,5735,4601],{},[378,5737,5738],{"class":380,"line":772},[378,5739,432],{"emptyLinePlaceholder":431},[378,5741,5742],{"class":380,"line":778},[378,5743,5744],{},"# Prompt: a reusable prompt template\n",[378,5746,5747],{"class":380,"line":793},[378,5748,4615],{},[378,5750,5751],{"class":380,"line":808},[378,5752,4620],{},[378,5754,5755],{"class":380,"line":814},[378,5756,5757],{},"    \"\"\"Generate a prompt for checking inventory.\"\"\"\n",[378,5759,5760],{"class":380,"line":1059},[378,5761,5762],{},"    return f\"Check the stock for SKU {sku} and propose a restock if it is low.\"\n",[378,5764,5765],{"class":380,"line":1064},[378,5766,432],{"emptyLinePlaceholder":431},[378,5768,5769],{"class":380,"line":1070},[378,5770,4639],{},[378,5772,5773],{"class":380,"line":1076},[378,5774,5775],{},"    # Local dev: stdio\n",[378,5777,5778],{"class":380,"line":1082},[378,5779,4649],{},[378,5781,5782],{"class":380,"line":1088},[378,5783,5784],{},"    # Remote/production: Streamable HTTP\n",[378,5786,5787],{"class":380,"line":1093},[378,5788,4659],{},[363,5790,5792],{"id":5791},"registering-with-claude-desktop","Registering With Claude Desktop",[267,5794,5795],{"className":4666,"code":4667,"language":4668,"meta":273,"style":273},[35,5796,5797,5801,5813,5825,5843,5863,5867,5871],{"__ignoreMap":273},[378,5798,5799],{"class":380,"line":381},[378,5800,4675],{"class":578},[378,5802,5803,5805,5807,5809,5811],{"class":380,"line":388},[378,5804,4681],{"class":4680},[378,5806,4685],{"class":4684},[378,5808,4688],{"class":4680},[378,5810,635],{"class":505},[378,5812,1404],{"class":578},[378,5814,5815,5817,5819,5821,5823],{"class":380,"line":415},[378,5816,4697],{"class":4680},[378,5818,4700],{"class":4684},[378,5820,4688],{"class":4680},[378,5822,635],{"class":505},[378,5824,1404],{"class":578},[378,5826,5827,5829,5831,5833,5835,5837,5839,5841],{"class":380,"line":428},[378,5828,4711],{"class":4680},[378,5830,4714],{"class":4684},[378,5832,4688],{"class":4680},[378,5834,635],{"class":505},[378,5836,535],{"class":534},[378,5838,4522],{"class":395},[378,5840,4688],{"class":534},[378,5842,1192],{"class":578},[378,5844,5845,5847,5849,5851,5853,5855,5857,5859,5861],{"class":380,"line":435},[378,5846,4711],{"class":4680},[378,5848,4733],{"class":4684},[378,5850,4688],{"class":4680},[378,5852,635],{"class":505},[378,5854,1283],{"class":578},[378,5856,4688],{"class":534},[378,5858,4744],{"class":395},[378,5860,4688],{"class":534},[378,5862,4749],{"class":578},[378,5864,5865],{"class":380,"line":441},[378,5866,4754],{"class":578},[378,5868,5869],{"class":380,"line":458},[378,5870,4759],{"class":578},[378,5872,5873],{"class":380,"line":463},[378,5874,817],{"class":578},[363,5876,5878],{"id":5877},"choosing-a-transport","Choosing a Transport",[55,5880,5881,5894],{},[58,5882,5883],{},[61,5884,5885,5888,5891],{},[64,5886,5887],{},"Transport",[64,5889,5890],{},"Use Case",[64,5892,5893],{},"Notes",[71,5895,5896,5908],{},[61,5897,5898,5902,5905],{},[76,5899,5900],{},[35,5901,4789],{},[76,5903,5904],{},"Local, Claude Desktop integration, development",[76,5906,5907],{},"No network setup required",[61,5909,5910,5914,5917],{},[76,5911,5912],{},[35,5913,4802],{},[76,5915,5916],{},"Remote, team-shared, cloud-deployed",[76,5918,5919],{},"Standardized in the March 2025 spec. SSE is deprecated",[23,5921,5922,5923,5925],{},"For TypeScript, use ",[35,5924,4814],{}," with Zod. It supports the same three primitives (Tool / Resource / Prompt) as Python FastMCP, with strong type safety. In either language, \"the wire protocol is JSON-RPC 2.0,\" so connecting a TypeScript client to a Python server just works.",[47,5927],{},[50,5929,5931],{"id":5930},"generating-websites-with-claude-code-combining-claudemd-and-skills","Generating Websites With Claude Code — Combining CLAUDE.md and Skills",[23,5933,5934],{},"As of early 2026, Claude Code generates 4% of all GitHub commits, with daily VS Code installs reaching 29 million. The \"vibe coding\" workflow has matured to the point where someone with zero engineering experience can ship a Next.js app.",[23,5936,5937],{},"That said, telling Claude \"make me a site\" still produces the familiar AI-generated look — Inter font, purple gradient, white background. The way to escape that is the combination of CLAUDE.md and Skills.",[363,5939,5941],{"id":5940},"where-claudemd-fits","Where CLAUDE.md Fits",[23,5943,5944],{},"A CLAUDE.md placed at the project root is auto-loaded by Claude Code at session start. Use it to capture \"what this project is\":",[267,5946,5948],{"className":952,"code":5947,"language":954,"meta":273,"style":273},"# Project: MyApp\n\n## Stack\n- Nuxt 4 (Nuxt Content 3, Vue 3 Composition API)\n- Tailwind CSS v4, shadcn/ui\n- Deployed on Vercel\n\n## Rules\n- Always make sure the build passes before committing.\n- TypeScript strict mode is required.\n- Don't use MDX components (Nuxt Content's CommonMark only).\n\n## Don't\n- Leave console.log calls in committed code.\n- Use the any type.\n",[35,5949,5950,5954,5958,5963,5967,5971,5976,5980,5985,5990,5995,6000,6004,6009,6014],{"__ignoreMap":273},[378,5951,5952],{"class":380,"line":381},[378,5953,4844],{},[378,5955,5956],{"class":380,"line":388},[378,5957,432],{"emptyLinePlaceholder":431},[378,5959,5960],{"class":380,"line":415},[378,5961,5962],{},"## Stack\n",[378,5964,5965],{"class":380,"line":428},[378,5966,4858],{},[378,5968,5969],{"class":380,"line":435},[378,5970,4863],{},[378,5972,5973],{"class":380,"line":441},[378,5974,5975],{},"- Deployed on Vercel\n",[378,5977,5978],{"class":380,"line":458},[378,5979,432],{"emptyLinePlaceholder":431},[378,5981,5982],{"class":380,"line":463},[378,5983,5984],{},"## Rules\n",[378,5986,5987],{"class":380,"line":469},[378,5988,5989],{},"- Always make sure the build passes before committing.\n",[378,5991,5992],{"class":380,"line":701},[378,5993,5994],{},"- TypeScript strict mode is required.\n",[378,5996,5997],{"class":380,"line":712},[378,5998,5999],{},"- Don't use MDX components (Nuxt Content's CommonMark only).\n",[378,6001,6002],{"class":380,"line":722},[378,6003,432],{"emptyLinePlaceholder":431},[378,6005,6006],{"class":380,"line":733},[378,6007,6008],{},"## Don't\n",[378,6010,6011],{"class":380,"line":739},[378,6012,6013],{},"- Leave console.log calls in committed code.\n",[378,6015,6016],{"class":380,"line":748},[378,6017,6018],{},"- Use the any type.\n",[23,6020,6021],{},"The split between CLAUDE.md and Skills is clean: CLAUDE.md is \"the context of this project,\" Skills are \"how to do this task.\" Together, you get an agent that understands the project and executes specific tasks correctly.",[363,6023,6025],{"id":6024},"site-generation-workflow-with-nextjs-nuxt","Site Generation Workflow With Next.js / Nuxt",[23,6027,6028],{},"A workflow that actually works in practice:",[4923,6030,6031,6037,6044,6052],{},[1816,6032,6033,6036],{},[26,6034,6035],{},"Create CLAUDE.md",": stack, naming conventions, things to avoid",[1816,6038,6039,4936,6042],{},[26,6040,6041],{},"Add an official or custom Skill",[35,6043,4939],{},[1816,6045,6046,4936,6049],{},[26,6047,6048],{},"Sanity-check requirements in plan mode",[35,6050,6051],{},"claude --plan \"I want a landing page that looks like X\"",[1816,6053,6054,6057],{},[26,6055,6056],{},"Implement iteratively",": don't ask for the whole thing at once — go section by section",[23,6059,6060],{},"Step 3 is the critical one. Asking for an implementation directly sometimes produces \"code that solves the wrong problem.\" Have Claude explore the existing codebase first, identify the change locations, impact range, and edge cases, and surface them as a plan. Once the plan looks right, just say yes — that alone prevents most implementation mistakes.",[47,6062],{},[50,6064,6066],{"id":6065},"writing-video-as-code-with-claude-code-remotion","Writing Video as Code With Claude Code + Remotion",[23,6068,6069,6070,6072],{},"The idea of \"managing video in code\" lands naturally for front-end engineers. Remotion is exactly that — a React-based video framework where ",[35,6071,4968],{}," returns the current frame number and you describe animation in code. Combined with Claude Code, it produces a \"write video by prompt\" workflow.",[363,6074,5497],{"id":6075},"setup-1",[267,6077,6079],{"className":372,"code":6078,"language":374,"meta":273,"style":273},"# Create a Remotion project\nnpx create-video@latest my-video-project\ncd my-video-project\n\n# Install Agent Skills (best-practices bundle from the Remotion team)\nnpx skills add remotion-dev/skills\n",[35,6080,6081,6086,6094,6100,6104,6109],{"__ignoreMap":273},[378,6082,6083],{"class":380,"line":381},[378,6084,6085],{"class":384},"# Create a Remotion project\n",[378,6087,6088,6090,6092],{"class":380,"line":388},[378,6089,4987],{"class":391},[378,6091,4990],{"class":395},[378,6093,4993],{"class":395},[378,6095,6096,6098],{"class":380,"line":415},[378,6097,4998],{"class":4684},[378,6099,4993],{"class":395},[378,6101,6102],{"class":380,"line":428},[378,6103,432],{"emptyLinePlaceholder":431},[378,6105,6106],{"class":380,"line":435},[378,6107,6108],{"class":384},"# Install Agent Skills (best-practices bundle from the Remotion team)\n",[378,6110,6111,6113,6115,6117],{"class":380,"line":441},[378,6112,4987],{"class":391},[378,6114,5016],{"class":395},[378,6116,4492],{"class":395},[378,6118,5021],{"class":395},[23,6120,6121],{},"Once the skills are in place, Claude Code understands Remotion conventions and generates code with the right component structure. There are 38+ categories covering animation, 3D, captions, audio, charts, and transitions.",[363,6123,6125],{"id":6124},"example-prompt","Example Prompt",[23,6127,6128],{},"There's a knack to writing good prompts: declare the concrete numbers — resolution, duration — up front, and make scene boundaries explicit:",[267,6130,6133],{"className":6131,"code":6132,"language":272,"meta":273},[270],"Create a 1920x1080px, 30fps, 10-second video.\n\n0–2s: Logo fades in (centered, white background)\n2–6s: Three features slide in one by one (left to right)\n        - \"Fast\" + lightning icon\n        - \"Safe\" + shield icon\n        - \"Easy\" + check icon\n6–9s: CTA button scales up: \"Try it now\"\n9–10s: Fade out\n\nColors: bg #0a0a0a, accent #7c3aed, text white\n",[35,6134,6132],{"__ignoreMap":273},[23,6136,6137],{},"Preview the generated code live in Remotion Studio, and once it looks right, render:",[267,6139,6141],{"className":372,"code":6140,"language":374,"meta":273,"style":273},"# Preview\nnpx remotion studio\n\n# Render (MP4)\nnpx remotion render MyComposition out/video.mp4\n",[35,6142,6143,6148,6156,6160,6165],{"__ignoreMap":273},[378,6144,6145],{"class":380,"line":381},[378,6146,6147],{"class":384},"# Preview\n",[378,6149,6150,6152,6154],{"class":380,"line":388},[378,6151,4987],{"class":391},[378,6153,5056],{"class":395},[378,6155,5059],{"class":395},[378,6157,6158],{"class":380,"line":415},[378,6159,432],{"emptyLinePlaceholder":431},[378,6161,6162],{"class":380,"line":428},[378,6163,6164],{"class":384},"# Render (MP4)\n",[378,6166,6167,6169,6171,6173,6175],{"class":380,"line":435},[378,6168,4987],{"class":391},[378,6170,5056],{"class":395},[378,6172,5077],{"class":395},[378,6174,5080],{"class":395},[378,6176,5083],{"class":395},[363,6178,6180],{"id":6179},"what-remotion-is-and-isnt-good-at","What Remotion Is and Isn't Good At",[55,6182,6183,6195],{},[58,6184,6185],{},[61,6186,6187,6189,6192],{},[64,6188,5890],{},[64,6190,6191],{},"Good Fit",[64,6193,6194],{},"Not a Good Fit",[71,6196,6197,6207,6217,6227,6238],{},[61,6198,6199,6202,6205],{},[76,6200,6201],{},"Product demo videos",[76,6203,6204],{},"◎ Easy to wire up to data and update dynamically",[76,6206,1662],{},[61,6208,6209,6212,6215],{},[76,6210,6211],{},"Data visualization",[76,6213,6214],{},"◎ Pass numbers in dynamically through code",[76,6216,1662],{},[61,6218,6219,6222,6225],{},[76,6220,6221],{},"Vertical social clips",[76,6223,6224],{},"◎ Just specify 9:16",[76,6226,1662],{},[61,6228,6229,6232,6235],{},[76,6230,6231],{},"Talking-head videos",[76,6233,6234],{},"△ Specialized tools like HeyGen win",[76,6236,6237],{},"Complex lip-sync",[61,6239,6240,6243,6246],{},[76,6241,6242],{},"Long-form footage (10+ min)",[76,6244,6245],{},"△ Scene management gets unwieldy",[76,6247,1662],{},[23,6249,6250],{},"Because rendering happens locally, watermarks and credit caps from cloud video generators don't apply at all. Treating \"video as a build artifact\" — auto-rebuilding the video in CI/CD whenever the product changes — is already showing up in real-world pipelines.",[47,6252],{},[50,6254,6256],{"id":6255},"pitfalls-and-how-to-avoid-them","Pitfalls and How to Avoid Them",[23,6258,6259],{},"Here, honestly, are the things that tripped me up.",[363,6261,4302],{"id":6262},"mcp",[23,6264,6265,6268,6269,6271,6272,2464],{},[26,6266,6267],{},"Errors when using SSE transport."," The March 2025 MCP spec update deprecated SSE (Server-Sent Events). For remote connections, always use ",[35,6270,4802],{},". With FastMCP, switching is just ",[35,6273,5181],{},[23,6275,6276,6279],{},[26,6277,6278],{},"Multiple MCP servers slowing startup."," A 5-server, 58-tool setup can push context consumption past 55,000 tokens. Anthropic's Tool Search feature (on-demand loading) cuts that by about 85%. Avoid monolithic servers — split by purpose into smaller ones.",[23,6281,6282,6285,6286,6288],{},[26,6283,6284],{},"Security."," Audit your servers against the OWASP MCP Top 10 (published in 2025). Watch especially for prompt injection (malicious instructions hidden in a tool's ",[35,6287,850],{},"). Code-review community servers before using them.",[363,6290,4299],{"id":6291},"skills",[23,6293,6294,6297,6298,6300],{},[26,6295,6296],{},"The skill doesn't trigger when expected."," A vague ",[35,6299,850],{}," field means Claude won't load the skill. Use strong language like \"whenever the user mentions X, use this skill.\"",[23,6302,6303,6306,6307,6309],{},[26,6304,6305],{},"Skills get ignored near the context limit."," Once a session crosses 70–85% of the context window, accuracy drops. Use ",[35,6308,5213],{}," to compress context, or continue in a fresh session.",[363,6311,6313],{"id":6312},"website-generation","Website Generation",[23,6315,6316,6319],{},[26,6317,6318],{},"\"Build the whole thing at once.\""," \"Build me an entire e-commerce site\" has a very high failure rate. Iterate component by component, page by page. Confirm direction in plan mode before implementation.",[23,6321,6322,6325],{},[26,6323,6324],{},"Committing generated code as-is."," A 2025 ACM study suggests LLM-written code has roughly 1.75× more logic errors than human-written code. Make sure tests pass before committing.",[363,6327,6329],{"id":6328},"remotion","Remotion",[23,6331,6332,6335],{},[26,6333,6334],{},"Trying to build something complex from the start."," Start with a 5-second sample, then layer up: background color → text → animation → multiple scenes.",[23,6337,6338,6341],{},[26,6339,6340],{},"Vague directions."," \"80px,\" \"30 frames (1s),\" and other concrete numbers boost Claude Code's accuracy. \"Big font\" and \"slow fade\" hurt it.",[23,6343,6344,6347],{},[26,6345,6346],{},"Character appearance changes between scenes."," Remotion references static assets directly in code, so pin the image files. For complex character video, pair with a specialized tool like HeyGen.",[47,6349],{},[50,6351,6353],{"id":6352},"wrap-up-and-next-steps","Wrap-up and Next Steps",[55,6355,6356,6369],{},[58,6357,6358],{},[61,6359,6360,6363,6366],{},[64,6361,6362],{},"Action",[64,6364,6365],{},"Priority",[64,6367,6368],{},"Time Required",[71,6370,6371,6382,6392,6405],{},[61,6372,6373,6376,6379],{},[76,6374,6375],{},"Build one MCP server (internal API integration)",[76,6377,6378],{},"High",[76,6380,6381],{},"1–2 hours",[61,6383,6384,6387,6389],{},[76,6385,6386],{},"Add CLAUDE.md to your project",[76,6388,6378],{},[76,6390,6391],{},"30 minutes",[61,6393,6394,6399,6402],{},[76,6395,6396,6397],{},"Try ",[35,6398,4939],{},[76,6400,6401],{},"Medium",[76,6403,6404],{},"10 minutes",[61,6406,6407,6410,6412],{},[76,6408,6409],{},"Build a 30-second demo video in Remotion",[76,6411,6401],{},[76,6413,6414],{},"2–3 hours",[23,6416,6417],{},"With Claude Code generating 4% of all commits and Spotify's engineers reportedly writing no code by hand since December 2025, fluency with these tools is shifting from \"nice to have\" to \"you'll fall behind without it.\" Start with one MCP server or one Skill — automating \"the thing I'm tired of explaining every time\" is the shortest path in.",[47,6419],{},[23,6421,6422],{},[1630,6423,4107,6424,4111],{},[2189,6425,4110],{"href":2191},[4113,6427,6428],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .shSDL, html code.shiki .shSDL{--shiki-default:#6272A4}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .sY8FZ, html code.shiki .sY8FZ{--shiki-default:#8BE9FE}html pre.shiki code .sLL85, html code.shiki .sLL85{--shiki-default:#8BE9FD}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}",{"title":273,"searchDepth":388,"depth":388,"links":6430},[6431,6432,6435,6441,6445,6450,6456,6457,6458,6461,6467,6471,6476,6482],{"id":52,"depth":388,"text":53},{"id":4266,"depth":388,"text":4267,"children":6433},[6434],{"id":4367,"depth":415,"text":4368},{"id":4464,"depth":388,"text":4465,"children":6436},[6437,6438,6439,6440],{"id":4474,"depth":415,"text":4474},{"id":4513,"depth":415,"text":4514},{"id":4662,"depth":415,"text":4663},{"id":4766,"depth":415,"text":4766},{"id":4820,"depth":388,"text":4821,"children":6442},[6443,6444],{"id":4830,"depth":415,"text":4831},{"id":4917,"depth":415,"text":4918},{"id":4961,"depth":388,"text":4962,"children":6446},[6447,6448,6449],{"id":4972,"depth":415,"text":4474},{"id":5027,"depth":415,"text":5027},{"id":5086,"depth":415,"text":5086},{"id":5162,"depth":388,"text":5162,"children":6451},[6452,6453,6454,6455],{"id":5168,"depth":415,"text":5169},{"id":5197,"depth":415,"text":5198},{"id":5217,"depth":415,"text":5217},{"id":5232,"depth":415,"text":5233},{"id":5256,"depth":388,"text":5256},{"id":2228,"depth":388,"text":5359},{"id":5415,"depth":388,"text":5416,"children":6459},[6460],{"id":5518,"depth":415,"text":5519},{"id":5613,"depth":388,"text":5614,"children":6462},[6463,6464,6465,6466],{"id":5623,"depth":415,"text":5497},{"id":5657,"depth":415,"text":5658},{"id":5791,"depth":415,"text":5792},{"id":5877,"depth":415,"text":5878},{"id":5930,"depth":388,"text":5931,"children":6468},[6469,6470],{"id":5940,"depth":415,"text":5941},{"id":6024,"depth":415,"text":6025},{"id":6065,"depth":388,"text":6066,"children":6472},[6473,6474,6475],{"id":6075,"depth":415,"text":5497},{"id":6124,"depth":415,"text":6125},{"id":6179,"depth":415,"text":6180},{"id":6255,"depth":388,"text":6256,"children":6477},[6478,6479,6480,6481],{"id":6262,"depth":415,"text":4302},{"id":6291,"depth":415,"text":4299},{"id":6312,"depth":415,"text":6313},{"id":6328,"depth":415,"text":6329},{"id":6352,"depth":388,"text":6353},"Claude Codeのスキルシステム・MCPサーバー構築・ウェブサイト生成・Remotion動画制作まで、エンジニアが実際に業務で使える知識を一冊にまとめた。コードと具体的な数字で語る実践ガイド。",{"date":6485,"image":6486,"alt":6487,"tags":6488,"tagsEn":6490,"published":431},"3rd May 2026","/blogs-img/blog-claude-skills-mcp-web-video-engineer-guide.png","Claude Skills・MCP・Remotionによるエンジニア向け実践ガイド",[4170,6489],"AI活用",[4172,6491],"AI Tools","/blogs/13-claude-skills-mcp-web-video-engineer-guide",{"title":4179,"description":6483},"blogs/13-claude-skills-mcp-web-video-engineer-guide","vRupI5p-5tD_KqHxWD9NRCkGAYIsMUKnXqoTXnxJb14",1778775884505]