← すべての記事
アプリ開発 開発者 公開済み · · 著者 ObjectStack Team

「オントロジーがソフトウェアである」とはどういう意味か?実行可能なビジネスオントロジーの定義

この一文は ObjectStack のポジショニングであり、本稿はその定義だ。実行可能なビジネスオントロジーには六種の中核、四つの投影、三つの「ではないもの」があり、中核と投影を見分けるテストがある。

「オントロジーがソフトウェアである」とはどういう意味か?実行可能なビジネスオントロジーの定義
  • オントロジー
  • 実行可能なビジネスオントロジー

要点:「オントロジーがソフトウェアである。」は ObjectStack README の最初の一文で、その下の行が定義だ:「実行可能なビジネスオントロジーをひとつ。AI が書き、ランタイムが動かし、エージェントが操作し、あなたが所有する。」実行可能なビジネスオントロジーとは、ランタイムが直接実行する、あなたのビジネスの定義である。その中核は六種のもの——オブジェクトとフィールド、リレーション、アクション、パーミッション、フロー、エージェントとツールの定義——で、ひとつのアーティファクトにコンパイルされ、そこからデータベース、API、UI、エージェントツールが導出される。ビュー、ダッシュボード、アプリ、翻訳はその投影であって、その一部ではない。知識表現のオントロジーではなく、既存システムの上に載せるセマンティックレイヤーでもなく、哲学的な意味での形式オントロジーでもない。コードは消えない。フック、アクション本体、CEL、制約付き JSX として、ランタイムの中へ移る。

主張はこれで全部だ。本稿はそれを分解する:なぜこの文は「である」と言い、「記述する」と言わないのか。六種の中核。投影と、両者を見分けるテスト。三つの否定。コードの行き先。そして、この一文が帰着する四つの約束。出典は README とそこからリンクされた概念ページで、言い換えずに引用する。同じリポジトリに同梱された CRM サンプルは、説明ではなく計測で示す。

なぜ「である」と言うのか

企業向けオントロジーの多くは、ソフトウェアを記述する。実際にビジネスを動かしているシステムの脇に置かれ——顧客のモデル、何と何がつながるかのグラフ、売上の意味を統制した定義——その下でシステムは何も知らずに動き続ける。記述は有用だが、任意でもある。消しても何も止まらない。

ObjectStack の一文が同一性の形で書かれているのは、関係が逆だからだ。定義そのものが、動いているものである。オントロジーを消せばアプリケーションは残らない。テーブルも、エンドポイントも、画面も、エージェントが呼べるツールもない。概念ページはパイプラインを一行で示す:

objectstack.config.ts -> objectstack.json -> ObjectStack runtime -> database · REST / realtime API · UI · MCP server

型付きメタデータを objectstack.config.ts に書く。それが objectstack.json アーティファクトにコンパイルされる。ランタイムがアーティファクトを読み、残りを導出する。README の同じ図のキャプションはさらに短い:「型付き定義ひとつ → データベース · REST API · クライアント SDK · UI · MCP ツール。」オントロジーが語るだけで、別のアーティファクトがソフトウェアである、ということはない。ここでの「である」はそういう意味で、以下のすべてはそこから導かれる。

六種の中核

概念ページは中核を六種のものとして定義する。下の表は中央の列にその文言をそのまま残し、右の列で各種が同梱 CRM サンプル(ObjectStack リポジトリの examples/app-crm)のどこにあるかを指す。定義をスローガンではなく、実際の定義と照らして検証できるようにするためだ。

中核宣言するもの同梱 CRM サンプルでは
オブジェクトとフィールドビジネスの実体と、その型付き属性——バリデーション、数式、デフォルト値、ファイルsrc/objects/:取引先、担当者、リード、商談、商談明細、活動
リレーションオブジェクト間のルックアップと主従(master-detail)のリンク商談の Field.lookup('crm_account', …)。商談明細はその主従の子
アクションユーザーまたはエージェントがレコードに対して起動できる操作と、それが表示される条件src/actions/convert-lead.action.ts。リードが未転換の間だけ表示される
パーミッション誰が何を読み、作成し、編集し、削除できるか——RBAC、行レベルとフィールドレベルのセキュリティ、共有src/security/sales-positions.ts:crm_sales_user セットと、リードの追加しかできないゲストプロファイル
フロービジネスプロセス——DAG フロー、レコードトリガー、スケジュールジョブ、承認、ワークフローsrc/flows/convert-lead.flow.ts。取引先と商談を作成し、リードを転換済みにする画面フロー
エージェントとツールの定義アプリに同梱される AI エージェント、それらが呼べるツール、それらを形作るスキルこのサンプルでは未宣言。すべてのオブジェクトは既に MCP ツールであり、アクションは ai: { exposed: true } でオプトインする

計測をひとつ。README 自身が「自分で測ってみよう」の下に印字しているコマンドで測った。コミット 9f9510f2 において、CRM サンプルの定義は 31 ファイル、1,917 行の TypeScript だ。その中に、六つのオブジェクト、三つのビュー、ひとつのダッシュボード、ひとつのアプリ、リード転換フロー、ひとつのアクション、ひとつのフック、二つのパーミッションセット、三つのポジション、ひとつの翻訳バンドル、ひとつのページ、そしてシードデータが入っている——アプリケーション全体が、読み切れる diff として。この数字の意味は、抽象的に小さいことではない。エージェントが定義全体を一度に保持し、「ここを変えたら何が壊れるか」を定義そのものから答えられることにある。README はそれを「AI が丸ごと保持できる大きさのアプリ」と呼ぶ。

中核は同時に、構造上、あなたのものである部分だ。概念ページはこう書く:「それはひとつの定義であり、オープンでバージョン管理される。通常の TypeScript としてあなたのリポジトリに置かれ、diff としてレビューでき、Apache-2.0 で仕様化・ライセンスされる——ベンダーのシステム内に保持され、そのベンダーのコンソールからしか届かないグラフではない。」

投影と、削除テスト

ビュー、ダッシュボード、アプリ、翻訳は同じメタデータで書かれ、同じゲートで検証されるが、オントロジーの一部ではない。概念ページはこれらを投影と呼び、それぞれを一節で説明する:「リストビューはオブジェクトのフィールドとパーミッションをグリッドに投影する。ダッシュボードはオブジェクトへのクエリをチャートに投影する。アプリはオブジェクト、ビュー、アクションをナビゲートできる製品にまとめる。翻訳はすべてのラベルをロケールに投影する。」

六種の中核が ObjectStack ランタイムを通じてデータベース、API、Console UI、MCP ツールにコンパイルされる。ビュー、ダッシュボード、アプリ、翻訳は投影としてオントロジーの枠の外にあり、フック、アクション本体、CEL、制約付き JSX はランタイムのフェンスの内側で動く

区別を運用可能にするのはこの一文だ:「中核を変えれば投影は追従する。投影を取り除いても、それが示していたビジネスは変わらない。」これをテストにすれば、プロジェクト内のどんな定義も一手で分類できる。削除テストと呼ぼう:

その定義を削除する。データベーススキーマ、API、あるいはユーザーやエージェントにできることが変わったなら、それは中核だった。画面、チャート、メニュー、ラベルが消えただけなら、それは投影だった。

CRM サンプルに当ててみる。src/views/opportunity.view.ts を削除しても、商談オブジェクト、そのフィールド、ルックアップ、パーミッションセットはすべて残る。REST エンドポイントは応答し続け、MCP ツールも存在し続ける。src/objects/opportunity.object.ts を削除すると、ビューには投影するものがなく、フローには作成するものがなく、パーミッションセットはもう存在しないオブジェクトを指す。前者は投影で、後者がソフトウェアだった。

この区別に名前を付ける価値がある理由も同じページに書いてある:「この区別は、エージェントがビジネスについて推論するために保持すべきものを限定する:中核であって、すべての画面ではない。」承認しきい値の変更をレビューするエージェントに必要なのは、オブジェクト、パーミッション、フローだ。結果をたまたまチャートにしているダッシュボード全部ではない。

それではない三つのもの

「オントロジー」という語は他分野から何十年分もの意味を背負っており、README の定義のかなりの部分は、そのうちどの意味が当てはまらないかを述べることに費やされている。否定は三つあり、それぞれ異なる。

それではないものそのものとは何かなぜ違うのか
知識表現のオントロジーOWL、RDF、ナレッジグラフは領域を記述し、クラス継承と公理を持ち、推論エンジンによって推論されるオブジェクト継承なし、公理なし、推論器なし。定義は検証され——Zod スキーマと os validate によって——そして実行される。abstract キーがまさにその理由で仕様から取り除かれた(ADR-0049)
既存システムの上に載せるセマンティックレイヤー既に運用しているシステムの上の読み取り専用のマッピング。ビジネスを記述するが、動かしはしないオントロジーがシステムである。データベース、API、UI、エージェントツールはそこから導出される。外部データソースのフェデレーションは可能で、デフォルトで読み取り専用、まだ初期段階
哲学的な意味での形式オントロジー一般に何が存在するかについての主張そうした主張はしない。ひとつの企業のアプリケーションを、実行できるだけ正確に定義したものだ

三列の対比:知識表現オントロジーは記述され推論される。セマンティックレイヤーは既存システムの上の読み取り専用マッピング。実行可能なビジネスオントロジーは検証されてから実行され、データベース、API、UI、エージェントツールになる

最初の否定が最も見落とされやすい。制限ではなく設計上の選択だからだ。推論エンジンは第二の真実の源である。実行時に導出される事実は、レビュアーが読める場所にはどこにも書かれていない。概念ページにある ObjectStack のルールはその逆だ:「実行時には何も推論されない。動くのは、検証されたものである。」パーミッションが diff にないなら、それはシステムにない。

二つ目の否定は、プラットフォームを評価する人にとって重要だ。「セマンティックレイヤー」という語が、同じ会話の中で二つの異なるものに使われているからである。セマンティックレイヤーは、ある数字が何を意味するかの優れた定義でありうる——ナレッジグラフとの比較は公平にその擁護をしている。それは名詞のレイヤーだ。実行可能なビジネスオントロジーは動詞を運ぶ。何をしてよいか、誰が、次に何が起きるかを決める、アクション、パーミッション、フローである。ドキュメントは、レポートとダッシュボードがバインドする分析データセット層を指して「セマンティックレイヤー」をより狭い意味でも使うと注記している。その狭い意味はレポーティングの話であって、この一文の意味ではない。

三つ目の否定は最も短く、最も正直だ。このフォーマットは世界について主張しない。主張するのは、ひとつの企業のアプリケーションを、ランタイムが実行でき、レビュアーが丸ごと読めるだけ正確に記述できる、ということだ。

コードの行き先

推論されるのではなく実行される定義にも、スキーマでは表せないものを表現する必要はある。案件成立時に 100% に固定される確度、リード転換後に消えるボタン、レイアウトを持つランディングページ。README の一文は「コードは消えない。フック、アクション本体、CEL、制約付き JSX として、ランタイムの中へ移る」で、概念ページがその理由を述べる。四つすべてが「ランタイムのパーミッションと監査のフェンスの内側で動く」のであり、「そのどれも、オントロジーが後から記述しなければならないコードベースに散らばってはいない」。

CRM サンプルのフックは、オブジェクトのライフサイクルに取り付けられた関数だ:

export const OpportunityStageHook = defineHook({
  name: 'opportunity_stage_probability',
  object: 'crm_opportunity',
  events: ['beforeInsert', 'beforeUpdate'],
  priority: 100,
  handler: async (ctx: HookContext) => {
    const input = ctx.input as { stage?: string; probability?: number };
    if (input.stage === 'closed_won') input.probability = 100;
    if (input.stage === 'closed_lost') input.probability = 0;
  },
});

CEL は数式、述語、ポリシーのための式言語だ。同じサンプルは、計算フィールドとアクションの表示条件の両方にそれを使う:

expected_revenue: Field.formula({
  label: 'Expected Revenue',
  expression: cel`(record.amount == null ? 0 : record.amount) * (record.probability == null ? 0 : record.probability) / 100`,
}),
visible: 'has(record.status) && record.status != "converted"',

制約付き JSX はカスタムページの書き方で、制約こそが要点だ。それは「サーバー駆動の UI ツリーに解析され、コードとして実行されることは決してない」。それを行うパッケージは README に、解析はするが決して実行しないコンパイラとして列挙されている。アクション本体が四つ目の行き先で、アクションが起動されたときにサーバー側で行う作業を担う。

四つに共通するパターンは同じだ。コードは許される。だがコードはビジネスの居場所ではない。ビジネスは六種の中核に住み、コードはその六種が定めるフェンスの内側で、クリックやツール呼び出しと同じパーミッションと監査のもとで動く。

検証し、そして実行する

ランタイムがアーティファクトに対して行うことは二つの動詞で表され、概念ページは意図的に両方を使う。それは導出する:「交換可能なドライバー上のデータベーススキーマ、生成された REST とリアルタイムの API、Console 向けのサーバー駆動 UI、そして MCP サーバー」。そして強制する:「RBAC、行レベルとフィールドレベルのセキュリティ、共有、監査は、REST リクエストにも、Console のクリックにも、エージェントのツール呼び出しにも等しく適用される。」

README は最初の動詞をオブジェクトひとつで示す。チケットを宣言する:

import { ObjectSchema, Field } from '@objectstack/spec/data';

export const Ticket = ObjectSchema.create({
  name: 'support_desk_ticket',
  label: 'Ticket',
  sharingModel: 'private',            // org-wide default — the security gate requires it
  fields: {
    subject: Field.text({ label: 'Subject', required: true, searchable: true }),
    status: Field.select({
      label: 'Status',
      required: true,
      options: [
        { label: 'Open', value: 'open', color: '#3B82F6', default: true },
        { label: 'Resolved', value: 'resolved', color: '#10B981' },
      ],
    }),
    due_date: Field.date({ label: 'Due Date' }),
  },
});

すると「REST API はオブジェクトが存在した瞬間に存在する——書くべきコントローラーはない」:

curl http://localhost:3000/api/v1/data/support_desk_ticket

コメント付きの sharingModel: 'private' に注目してほしい。セキュリティの姿勢はオブジェクトの一部であり、ゲートがそれを要求する。os validate は「型チェックは通るが実行時に静かに失敗するメタデータを拒否する:宙に浮いたバインディング、誤った CEL 述語、欠けたセキュリティ姿勢」。これが検証の半分だ。実行の半分は、このオブジェクトから導出されたすべての面——テーブル、エンドポイント、Console のグリッド、MCP ツール——が、呼び出しのたびに同じパーミッションに照らして検査されることにある。だから MCP 経由でチケットに届いたエージェントが見るのは、同じパーミッションを持つ人間が見るものと正確に同じだ。

四つの約束、先頭は「実行可能」

README はこの一文を四つの語に圧縮する:「実行可能 · AI が書ける · エージェントが操作できる · あなたが所有する」。それぞれが仕組みに裏付けられた主張で、順序は飾りではない。最初のひとつが、残り三つの足場だ。

実行可能。 定義が、動いているものそのものである。上の二つの節の内容すべてがこの約束だ。ひとつのアーティファクト、導出される面、呼び出しごとの強制、実行時に推論されるものは何もない。これがなければ、「AI が書ける」は AI がドキュメントを書くという意味になってしまう。

AI が書ける。「エージェントは型付きメタデータを書く——コードベースではない。ゲートは実行時に静かに失敗するものを拒否し、エージェントはあなたの目に入る前にそれを直す。」スキャフォルダーは「AI スキルバンドルをインストールして AGENTS.md を書くので、あなたのエージェントはプロトコルのルールを最初から読み込んだ状態で始まる」。README の四つのゲート——型付き、検証済み、レビュー済み、統制済み——がエージェントの誤りを出荷させない理由であり、そもそもこれが機能する理由として述べられているのが「エージェントの誤りは、位置が特定された、訂正のためのテキストになり、エージェント自身がそれを読んで直せる」だ。

エージェントが操作できる。「オブジェクトはツールであり、アクションはツールであり、パーミッションがエージェントに何を呼べるかを決め、監査が何をしたかを記録する。」動いているアプリは「/api/v1/mcp で MCP サーバーとして提供される——デフォルトでオン」であり、エージェントは「人間と同じパーミッションと RLS のもとで」それを操作する。エージェントが書いた同じオントロジーが、同じフェンスを通って、次はエージェントに使われる。

あなたが所有する。「このリポジトリにあるものはすべてオープンスタックだ——プロトコル、マイクロカーネル、SDK、CLI、そして本番ランタイム。Apache-2.0 で、オープンコアの但し書きはない。」そして定義そのものは「通常の TypeScript としてあなたのリポジトリに置かれ、あなたの VCS でバージョン管理され、diff としてレビューできる——ベンダーのシステム内に保持されるグラフではない」。オントロジーはあなたが手に持つファイルであって、借りているテナントではない。

これが解決しないこと

定義の記事は、定義がどこで止まるかを言うべきだ。

モデリングを簡単にはしない。商談とは何か、誰がそれを成約にできるか、30% を超える値引きに何が必要か——それを決めるのは、相変わらず遅く、議論を呼び、人の手による仕事だ。フォーマットが決めるのは、結果が丸ごと読めるほど小さいか、作成時に誤りを拒めるほど厳格か、だけである。

推論はしない。あなたの問題が本当に領域モデル上の推論——クラス階層、導出される事実、帰結を発見するエンジン——を必要とするなら、それは本稿が明確に「ではない」と言った知識表現のオントロジーだ。そちらのツールを選ぶべきで、こちらに推論器が生えてくることを期待してはいけない。

既に運用しているものの上に載せる層ではない。外部データソースのフェデレーションはデフォルトで読み取り専用で、初期段階と記述されている。だからレガシーデータベースの上の実行可能オントロジーは読み取りモデルから始まり、オブジェクトごとに書き込みを獲得していく。社内システムをメタデータへ移すはその道筋の正直な版で、まったく移さないのが答えになる場合も含む。

そして、新規性のあるロジックはコードのままだ。その行き先がフックとアクション本体で、フェンスの内側にあり、それでも人間がレビューすべきコードである。オントロジーはそのコードを小さく、境界のあるものにする。消しはしない。README はそのとおりの言葉でそう言っている。

ホスト型で、あるいは自社インフラで

README は上のループ——コーディングエージェントがあなたのリポジトリにメタデータを書き、動いているアプリを MCP 越しに操作する——を記述したあと、こう言う:「同じループをホスト型で、ブラウザだけで、何もインストールせずに使いたい?それが ObjectOS — ObjectStack の上に構築された商用ランタイム環境です。」ObjectOS は、ブラウザ上でホストされインストール不要の ObjectOS Cloud としても、自社インフラでセルフマネージドの ObjectOS Enterprise としても動作します。どちらのエディションでも、オントロジーをエクスポートしてオープンソースの ObjectStack ランタイムで実行できます。これは四つ目の約束を製品の境界として述べたものだ。どのホストで動いていても、オントロジーはあなたのものである。

エージェントの道筋から始める

上のどれも、定義を信じて受け取る必要はない。README 自身の五分間の道筋が、読める定義をひとつ作ってくれる。

npm create objectstack@latest my-app && cd my-app

プロジェクトをコーディングエージェントで開き、要件を説明する。README の例はサポートデスクだ。件名、説明、優先度の選択、ステータスの選択を持つ ticket オブジェクト。まだ解決していないチケットにだけ表示される Resolve アクション。「未解決チケット」のリストビューと Support ナビゲーショングループ。終わったら npm run validate。それから結果をプレビューする:

npx os dev --ui   # → http://localhost:3000/_console/

Console を見る前に、エージェントが生成した diff を見てほしい。オブジェクト、アクションとその表示述語、ビュー——削除テストで一行ずつ中核か投影かに仕分けでき、動かない行はゲートが既に拒んでいる。エージェントに舵取りが必要なら、ObjectStack 向けに設定する方法がルールファイル、スキルバンドル、ツールサーバーを扱っている。エージェントが書くその定義がソフトウェアであり、それはあなたのリポジトリにある。