yongol — AIコーディングSaaSの竜骨 Image: AI generated 画像:AI生成

AIがコードを上書きし続けるなら、バイブコーディングが200エンドポイントで崩壊したなら、AIの作業対象をコードから仕様に移したいなら――yongolがその竜骨だ。

200番目のエンドポイント

バイブコーディングでSaaSを作る。最初は速い。テーブル5つ、エンドポイント12個——20分で動く。

だが50エンドポイントを超えると奇妙なことが起きる。AIが昨日作ったパターンを今日は別のものにする。100を超えると既存の機能がひっそりと壊れる。200を超えると、新機能を1つ追加するのに最初の10個を作った時の10倍かかる。

DORA 2025レポートがこれを実証した——AIツールはスループットを2-18%向上させるが、同時に変更失敗率と手戻りを増加させる[1]。AIは既存プロセスの弱点を増幅する「鏡であり乗数」だということだ。

モデルが馬鹿なのではない。


決定と実装

ソースコードには3つのものが混在している:

  • ユーザーの決定 ——このカラムはBIGINTだ。このエンドポイントは所有者だけがアクセスする。ページネーションはカーソル方式だ。
  • ビジネスロジック ——価格設定、ワークフロー、ライフサイクルルール。
  • 実装詳細 ——変数名、ライブラリ呼び出し順序、エラーラッピング。

AIがこのコードを読むとき、どの行が決定でどの行が詳細かを区別できない。だから「リファクタリング」や「整理」をするとき、決定を詳細と間違えてひっそりと上書きする。ユーザーは動作がすでにおかしくなった後に気づく。1972年、Parnasは「変更される可能性が高い設計決定をインターフェースの背後に隠せ」[2]と言った——彼は人間に向けて語ったのだ。だがAIがコードを編集する今、決定と詳細の区別が媒体自体に存在しなければ、誰も——人間もモデルも——その区別を守れない。

これが200エンドポイントでバイブコーディングが崩壊する理由だ。より大きなモデルを使っても解決しない。**媒体(生のコード)自体が決定を保存しないからだ。**すべてのモデルが結局同じ壁にぶつかる。


竜骨

船を造るとき最初に置く骨格が竜骨だ。船体の重さを支え、左右の揺れを防ぎ、他のすべての構造物が竜骨の上に乗る。竜骨なしで造った船は穏やかな海では浮くが、波が来ると歪む。

バイブコーディングで作ったSaaSもそうだ。小さいときは浮く。大きくなると歪む。

yongolはAIコーディングSaaSの竜骨だ。

Harness with reins ——より大きなモデルではなく、より精密な手綱。決定論的バリデーターがすべての成果物を判定し、ラチェットが進行を強制し、完了かどうかを機械が決定する。


決定をコードの外へ

yongolの核心はシンプルだ。決定をコードから分離する。

10個の宣言的仕様(SSOT)がそれぞれ1つの関心事だけを担当する:

SSOT担当
features.yaml機能カタログ——何を作るか
manifest.yamlプロジェクト設定——認証、ミドルウェア、インフラ
OpenAPIAPI契約——パス、パラメーター、レスポンス
SQL DDL + sqlcデータモデル——テーブル、カラム、制約、クエリ
SSaCサービスフロー——エンドポイント内部の決定順序
Rego認可ポリシー——誰が何をできるか
Mermaid stateDiagram状態遷移——エンティティのライフサイクル
FuncSpecカスタム関数——CRUDで表現できないロジック
Hurlテストシナリオ——smoke、scenario、invariantの3分類
STMLフロントエンド——Semantic Template Markup Language(data-*属性ベースのHTML)

10種中8種は業界標準(OpenAPI、SQL、sqlc、Rego、Mermaid、Hurl、YAML)だ。SSaCとSTMLだけがyongolが作ったDSLだ。AIが新たに学ばなければならないものを最小化する。

各SSOTには決定だけが入る。実装詳細はない。AIはSSOTを編集し、yongol generateがSSOTからコードをレンダリングする。決定はSSOTに永久に住み、コードは使い捨ての投影だ。


整合性を強制する

決定を10個のファイルに分散させたので、ファイル間の矛盾が生じ得る。DDLではBIGINTなのにOpenAPIではstring?SSaCで@authを宣言したのにRegoに該当ルールがない?状態図に遷移があるのにSSaCに該当関数がない?

矛盾したSSOTは汚染された決定だ。コードがどれだけきれいでも、決定が食い違えば動作がおかしくなる。

yongol validateがこれを捕まえる。

✓ manifest        ✓ openapi_ddl       ✓ ssac_rego
✓ openapi         ✓ openapi_ssac      ✓ ssac_authz
✓ ddl             ✓ hurl_openapi      ✓ ssac_sqlc
✓ query           ✓ hurl_statemachine ✓ ddl_statemachine
✓ ssac            ✓ hurl_manifest     ✓ ddl_rego
✓ statemachine    ✓ openapi_manifest  ✓ rego_manifest
✓ rego            ✓ ssac_ddl          ✓ stml_openapi
✓ hurl            ✓ ssac_statemachine
✓ funcspec        ✓ ssac_func

0 errors, 0 warnings

まず各SSOTを個別に検証し、次にレイヤー間の交差検証を実行する。約287のルールが10個のSSOT間のすべてのシンボル参照を検査する。矛盾が1つでもあればコンパイルを拒否する。Torresらの系統的文献レビュー[3]は、ほとんどのモデル管理ツールが単一モデル内部の整合性のみを扱い、異種モデル間の交差検証は未解決課題として残っていると指摘した——yongol validateが埋める空白がまさにそれだ。

AIは自由に書く。レールを外れればvalidateが即座に捕まえる。レール上の自由。


yongol next ——ラチェットコマンド

yongol validateがすべてのエラーを一度に表示するのに対し、yongol nextはエラーを1つずつ表示する。これがラチェットだ。

$ yongol next specs/

[ERROR] DDL-003: users.id must be BIGINT, got INT
  file: specs/db/users.sql:2
  ▶ Fix this error. Then run `yongol next specs/`.

AIエージェントに必要な指示は一文だ:「yongol next specs/を実行し、エラーが0になるまで修正せよ。」

エラーを直すと次のエラーが出る。全部通過すれば止まる:

$ yongol next specs/

✓ All validations passed. 0 errors.

エージェントが「完了しました」と宣言するのではなく、機械が「まだ残っている」または「全部通過」を判定する。終了判断権がエージェントにない。


プロジェクト作成と機能管理

yongol init

features.yamlからSSOTスキャフォールディングを自動生成する。

yongol init Myapp features.yaml "My workflow automation SaaS"
cd Myapp && yongol validate specs     # 0 errors

manifest、OpenAPI operationIdスタブ、SSaCスタブファイル、Rego認可ルール、Hurlスモークテスト、sqlc設定が一度に生成される。プロジェクトが即座にyongol validate通過状態で始まる。

yongol features add / remove

機能を追加または削除する:

yongol features add new_features.yaml         # 新operationIdのSSaCスタブ生成
yongol features remove ExportWorkflow --yes    # operationId削除 + SSaCスタブ削除

yongol import

外部OpenAPI(Stripe、GitHubなど)からGoクライアントパッケージを生成する:

yongol import https://api.stripe.com/openapi.yaml ./external/

生成された関数をSSaCで@call <pkg>.<Func>({...})として呼び出す。


operationIdがキーストーンだ

10個のレイヤーをどうやって束ねるか?PascalCaseの識別子1つで。

operationId ExecuteWorkflowを入力すると:

── Feature Chain: ExecuteWorkflow ──

  OpenAPI    api/openapi.yaml                POST /workflows/{id}/execute
  SSaC       service/workflow/execute_workflow.ssac   @get @empty @auth @state @call @publish @response
  DDL        db/workflows.sql                CREATE TABLE workflows
  DDL        db/execution_logs.sql           CREATE TABLE execution_logs
  Rego       policy/authz.rego               resource: workflow
  StateDiag  states/workflow.md              diagram: workflow → ExecuteWorkflow
  FuncSpec   func/billing/check_credits.go   @func billing.CheckCredits
  FuncSpec   func/billing/deduct_credit.go   @func billing.DeductCredit
  FuncSpec   func/worker/process_actions.go  @func worker.ProcessActions
  FuncSpec   func/webhook/deliver.go         @func webhook.Deliver
  Hurl       tests/scenario-happy-path.hurl  scenario: scenario-happy-path.hurl

API仕様からDBスキーマ、認可ポリシーから状態遷移、関数実装からテストシナリオまで——機能1つの全体地形が一画面に見える。grep数十回が1コマンドに置き換わる。

operationIdがキーストーンである理由は、フルスタックアプリケーションにおける機能の単位がAPIエンドポイントだからだ。ユーザーがボタンを押すとAPIが呼ばれ、そのAPIが他のすべてのレイヤーを貫通する。この名前1つが10個のレイヤーを物理的にチェイニングする。


SSaC ——なぜカスタムDSLなのか

yongolの10 SSOTのうち8種は業界標準だ。SSaC(Service Sequences as Code)とSTMLだけがyongolが作った。SSaCはサービスフローの決定をキャプチャする。

**SSaCが埋める空白。**宣言的ツールのスペクトラムを見ると、一方の端に契約標準(OpenAPI、SQL、Rego)がある——何を宣言するがどの順序では宣言しない。反対の端にワークフローランタイム(Temporal、Inngest、Restate)がある——それらはコードだ。決定と実装詳細が同じファイルで再結合する。SSaCはその間の空白に座る:「1つのエンドポイント内部で何が、どの順序で、どのガードとともに起きるか。」

SSaCのアノテーション全体は16個だ。1ページマニュアルで学習可能だ。

SSaCアノテーション全リスト

アノテーション役割形式
@getDB読み取りType var = Model.Method({args})
@post行作成Type var = Model.Method({args})
@put行更新(返却なし)Model.Method({args})
@delete行削除Model.Method({args})
@emptynilガード → 404var "message" [STATUS]
@existsnot-nilガード → 409var "message" [STATUS]
@auth認可検証"action" "resource" {inputs} "message" [STATUS]
@state状態機械遷移diagram {inputs} "transition" "message" [STATUS]
@call関数呼び出し[Type var =] pkg.Func({args})
@eval述語ガード(true → エラー)pkg.Func({args}) "message" STATUS
@publishキュー発行"topic" {payload}
@subscribeキュートリガー関数"topic"
@verify-passwordログイン(タイミング防御)Model.col=source Model.hash vs source -> var STATUS "msg"
@responseJSON返却{ field: var, ... } または var
@no-paginationページネーションルール免除(関数レベル)
@state-neutral状態機械ルール免除(関数レベル)

SSaC例 —— AcceptProposal

認可 + 二重状態機械 + エスクロー + キュー:

package service

import "github.com/org/project/internal/billing"

// @get Proposal p = Proposal.FindByID({ID: request.id})
// @empty p "Proposal not found" 404
// @get Gig gig = Gig.FindByID({ID: p.GigID})
// @empty gig "Gig not found" 404
// @auth "AcceptProposal" "gig" {ResourceID: request.id} "Forbidden" 403
// @state proposal {status: p.Status} "AcceptProposal" "Cannot accept" 409
// @state gig {status: gig.Status} "AcceptProposal" "Cannot accept on gig" 409
// @put Proposal.UpdateStatus({ID: p.ID, Status: "accepted"})
// @put Gig.AssignFreelancer({ID: gig.ID, FreelancerID: p.FreelancerID, Status: "in_progress"})
// @call billing.HoldEscrowResponse escrow = billing.HoldEscrow({GigID: gig.ID, Amount: gig.Budget})
// @publish "proposal.accepted" {GigID: gig.ID, FreelancerID: p.FreelancerID}
// @get Proposal updated = Proposal.FindByID({ID: p.ID})
// @response { proposal: updated }
func AcceptProposal() {}

16行。10アノテーション。2つの状態機械、認可、エスクロー、キューイベント、レスポンス——すべての決定が見え、すべての詳細がない。


ベンチマーク:ZenFlow

ZenFlow——マルチテナント・ワークフロー自動化SaaS。

段階内容時間累計
初期ビルド10エンドポイント、6テーブル、認証、状態機械13分13分
+ バージョン管理ワークフロー複製、バージョンリスト6分19分
+ Webhookwebhook CRUD、キューバックエンド6分25分
+ テンプレートマーケットプレイスカーソルページネーション、クロス組織複製3分28分
+ ファイル添付実行レポート、ファイルバックエンド4分32分
+ スケジューリングcronスケジューリング、セッションバックエンド6分38分
+ 監査ログオフセットページネーション、キャッシュバックエンド3分41分
+ ダッシュボードリレーションjoin、funcレスポンスタイプ7分48分
+ 一括操作jsonb一括挿入14分62分
+ 外部APIジオコーディングfunc、カラム追加3分65分
+ 条件付き更新センチネルパターン、自動割り当て4分69分

最終:32エンドポイント、14テーブル、47 Hurlリクエスト。11/11段階通過。

機能を追加するほど速度が落ちなかった。既存テストが壊れなかった。200エンドポイントの壁は存在しなかった。

Opus 4.7ベンチマーク ——32エンドポイント、14テーブル、47 Hurlリクエスト、約69分。 Sonnet 4.6ベンチマーク ——32エンドポイント、9テーブル、37 Hurlリクエスト、約43分。


yongol agent

SSOTファイルをLLMがvalidate-fixループで自動修正する。

yongol agent specs/ --model ollama:gemma4:e4b --max-rounds 20

validateエラーをLLMにフィードバックし、LLMが修正し、再びvalidateする。0エラーになるまで繰り返す。ローカル4.5Bモデル(Gemma4)でも動作する。

対応バックエンド:ollama(ローカル)、xai(Grok)、gemini


生成されたコードを編集できるか

できる。yongol generateは再実行時にユーザー編集を保持する:

  • すべての生成ファイルに//yg:checked llm=yongol-gen hash=<8hex>アノテーションが付く。
  • ハッシュが異なれば、そのファイルは**保持(preserved)**状態となり、次のgenerateでスキップされる。
  • yongol statusで保持ファイルと契約ドリフト(PRV-01/PRV-02エラー)を確認できる。
  • 意図を記録するには//yg:preserve reason="..."を追加する(任意)。保持解除はファイル削除で。

ビルトイン関数とモデル

ビルトイン関数(SSaCで@callとして呼び出し)

パッケージ関数説明
authhashPassword, verifyPasswordbcryptハッシュ/検証
authissueToken, verifyToken, refreshTokenJWTトークン
authgenerateResetTokenパスワードリセット
cryptoencrypt, decryptAES-256-GCM
cryptogenerateOTP, verifyOTPTOTP
storageuploadFile, deleteFile, presignURLS3
mailsendEmail, sendTemplateEmailSMTP
textgenerateSlug, sanitizeHTML, truncateTextテキスト処理
imageogImage, thumbnail画像生成

ビルトインモデル(manifest.yamlで設定)

パッケージインターフェースバックエンドSSaC使用法
sessionSessionModel (Set/Get/Delete + TTL)PostgreSQL, Memorysession.Session.Get({key: ...})
cacheCacheModel (Set/Get/Delete + TTL)PostgreSQL, Memorycache.Cache.Set({key: ..., value: ..., ttl: ...})
fileFileModel (Upload/Download/Delete)S3, LocalFilefile.File.Upload({key: ..., body: ...})
queuesingleton Pub/Sub (Publish/Subscribe)PostgreSQL, Memory@publish "topic" {payload}

DDLマイグレーション自動生成

yongol generateはDDL変更を検出してマイグレーションファイルを自動生成する。

specs/db/
└── users.sql                         # SSOT ——ここで編集

artifacts/db/
├── .latest_schema.sql                # ベースラインスナップショット
└── migrations/
    ├── 0001_initial.up.sql
    ├── 0001_initial.down.sql
    ├── 0002_add_users_email.up.sql
    └── 0002_add_users_email.down.sql

曖昧な変更(カラム名変更、型キャスティング、NOT NULLバックフィル)はDDLコメントヒント(-- @rename-- @cast-- @backfill-- @data_migration-- @allow_destructive)で区別する。6つのルール(MIG-001MIG-006)が危険な変更をゲートする。実際のDB適用はgolang-migrateflywayなどの標準ツールに委任する。


なぜより大きなモデルが答えでないのか

「GPT-6が出れば解決するよ。」

解決しない。問題はモデルの知能ではなく媒体だ。

コードという媒体は決定と実装を区別しない。どのモデルがコードを読んでも、決定と詳細が混在したテキストを見る。モデルがどれだけ賢くても、媒体が区別を提供しなければ区別できない。

yongolは媒体を変える。AIが編集する対象をコードから宣言的仕様に移す。仕様には決定だけがあり実装詳細がないので、AIが決定を詳細と間違える余地がない。決定の生存がモデルサイズと無関係になる。

小さなLLMがSSOTだけを編集し、validateが毎回のミスに精密なフィードバックを返せば、はるかに大きなモデルが生のコードを編集するのと同じレベルの決定無欠性を維持できる。yongolがその差を埋める。


ランタイムテスト

Hurlテストはすべてユーザーが作成する。specs/tests/に作成すればyongol generateartifacts/tests/にミラーリングする。検証時にXOH-01〜09ルールがHurlをOpenAPI、状態機械、manifest.authと交差検証する。

hurl --test --variable host=http://localhost:8080 artifacts/my-project/tests/*.hurl

3つの分類:

  • smoke.hurl ——エンドポイントスモークテスト
  • scenario-*.hurl ——ビジネスシナリオテスト
  • invariant-*.hurl ——エンドポイント間不変式テスト

現在の状態

Go+Ginバックエンド生成:Beta ——エンドツーエンド動作。Reactフロントエンド生成:Alpha(作業中)。


始め方

方法1:スキルインストール(推奨)

npx skills add park-jun-woo/yongol

AIエージェント(Claude Code、Cursor、Copilotなど)にyongolスキルをインストールする。エージェントがワークフローを自動で学習する。

/yongol 認証とCRUDのあるマルチテナントToDoアプリSaaSを作って。

方法2:直接インストール

Go 1.25+およびgcc(cgo依存:pg_query_goがDDLパース用にlibpg_queryをリンク)が必要。

git clone https://github.com/park-jun-woo/yongol && cd yongol
make install
yongol validate examples/zenflow

0 errors, 0 warnings。

この仕様の上でAIに機能を追加させてみよう。validateがレールを敷き、AIがレール上を走る。壁はない。


関連記事

コード:github.com/park-jun-woo/yongol


出典

  1. Google DORA Team. DORA State of AI-Assisted Software Development 2025. Google Cloud, 2025. dora.dev/dora-report-2025
  2. David L. Parnas. “On the Criteria to Be Used in Decomposing Systems into Modules.” Communications of the ACM 15(12): 1053-1058, 1972. doi:10.1145/361598.361623
  3. Weslley Torres, Mark G.J. van den Brand, Alexander Serebrenik. “A Systematic Literature Review of Cross-Domain Model Consistency Checking by Model Management Tools.” Software and Systems Modeling 20(3): 897-916, 2021. doi:10.1007/s10270-020-00834-1
  4. Deepak Babu Piskala. “Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants.” arXiv:2602.00180, January 2026. arxiv.org/abs/2602.00180
  5. Ehsani et al. “When AI Code Doesn’t Stick: An Empirical Study on Reverted Changes Introduced by AI Coding Agents.” MSR 2026 Mining Challenge, April 2026. 2026.msrconf.org
  6. Anton Jansen, Jan Bosch. “Software Architecture as a Set of Architectural Design Decisions.” EWSA 2005, LNCS 3527, Springer, 2005. semanticscholar.org
  7. Marco Brambilla, Jordi Cabot, Manuel Wimmer. Model-Driven Software Engineering in Practice. 2nd ed., Springer, 2017. doi:10.1007/978-3-031-02546-4
  8. GitClear. AI Copilot Code Quality 2025. February 2025. gitclear.com

変更履歴

日付変更内容
2026-05-18初回公開
2026-05-19Opusベンチマーク追加。10 SSOT更新
2026-05-21READMEシンク:ベンチマーク更新(Opus 32ep/14tbl/47hurl/69min、Sonnet 32ep/9tbl/37hurl/43min)、“Harness with reins"宣言追加、SSaC例(AcceptProposal)追加、yongol agentコマンド追加、Preserveシステム追加、ビルトイン関数/モデルリスト追加、DDLマイグレーション自動生成追加、STML説明追加、ifeval-ratchet関連記事リンク追加
2026-05-26v0.6.10シンク:yongol nextラチェットコマンド追加、yongol init/features add/features removeプロジェクト作成・管理追加、yongol import外部OpenAPIインポート追加、SSaCアノテーション全リスト(16個)追加(@eval@subscribe@verify-password@no-pagination@state-neutral)、Hurlテスト3分類(smoke/scenario/invariant)、ランタイムテストセクション、Preserve詳細化(PRVエラーコード)、DDLマイグレーションヒント拡張(@data_migration@allow_destructive、MIGルール)、現在の状態(Go+Gin Beta、React Alpha)、インストール方法2種類に分離