diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/cover-en.svg b/content/blog/what-do-ai-models-lack-in-the-enterprise/cover-en.svg
new file mode 100644
index 0000000..39f5568
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/cover-en.svg
@@ -0,0 +1,57 @@
+
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/cover.svg b/content/blog/what-do-ai-models-lack-in-the-enterprise/cover.svg
new file mode 100644
index 0000000..d87c217
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/cover.svg
@@ -0,0 +1,57 @@
+
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/index.mdx b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.mdx
new file mode 100644
index 0000000..cc7ab29
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.mdx
@@ -0,0 +1,175 @@
+---
+title: "What Do AI Models Lack in the Enterprise? A World, Hands and a Fence"
+description: "Not intelligence. In a company a model lacks a world to reason about, hands to act with and a fence around the acting. One executable business ontology supplies all three; a sourced table maps each to its runtime mechanism."
+author: ObjectStack Team
+date: 2026-11-03
+status: published
+topic: ai-agents
+audience: it
+solutions: []
+industries: []
+cover: ./cover-en.svg
+tags:
+ - AI agents
+ - Executable business ontology
+ - MCP
+ - Agent permissions
+---
+
+**World.** What exists in this business, how each thing is typed, and how the things connect.
+
+**Hands.** The operations an agent may perform on that world, offered as tools it can call.
+
+**Fence.** Who may do what, decided on every call rather than once, and recorded afterwards.
+
+Those are the three things an AI model is missing when it arrives in an enterprise, and intelligence is not on the list. The sentence is ObjectStack's, from the "00 · The idea" section of its front page: "What the model lacks is not intelligence: a world, hands, and a fence." This post makes the narrower, checkable claim behind it: an executable business ontology supplies all three from one artifact, and each supply maps to a named runtime mechanism you can read in the source. The table below is that map, with file and line for every cell. After it: what each supply is, one number measured on the bundled CRM example, the strongest alternative stated fairly, and what none of this solves.
+
+## Where the sentence comes from
+
+The front page of objectstack.ai states the idea in three sentences, kept verbatim in the page's source (`apps/docs/app/[lang]/page.tsx`, lines 127–131):
+
+> An enterprise is definition plus execution. When execution is nearly free, it is its definition.
+>
+> What the model lacks is not intelligence: a world, hands, and a fence.
+>
+> An ontology written clearly enough is software. Models change; the ontology stays.
+
+Read the middle sentence as a diagnosis. Every enterprise AI pilot connects a capable model to a company and then discovers, one incident at a time, that the model did not know what an "account" was in this company (no world), could not actually change one (no hands), or changed one it should not have touched (no fence). The usual response is to buy each missing piece separately: a retrieval layer for the world, a function-calling layer for the hands, a policy layer for the fence. That is a reasonable response, and the second half of this post gives it its due. The first and third sentences say why ObjectStack takes a different one: if the definition of the business is written precisely enough to execute, then the same definition is the world, declares the hands, and carries the fence, and it outlives whichever model is reading it this quarter.
+
+## Three supplies, one artifact
+
+The ObjectStack README's one-line definition is "One executable business ontology. AI writes it, the runtime runs it, agents operate it, you own it." The concepts page lists its core as six kinds of thing: objects and fields, relations, actions, permissions, flows, and agent and tool definitions. The claim of this post is that those six kinds sort into the three supplies, and that the runtime turns each into something the agent can use without anyone writing glue. Here is the map. Every source is a file in `objectstack-ai/objectstack` at commit `1ecb08a1` (`origin/main` on 2026-10-16), or a page of its docs, which are built from the same repository.
+
+| The model lacks | Supplied by (in the ontology) | The runtime mechanism, and where it is written |
+| :--- | :--- | :--- |
+| **A world** — the nouns: which entities exist, how each is typed, how they relate | Objects and fields; relations (two of the six kinds) | One typed definition is compiled into `objectstack.json`; from it the runtime derives the database schema, the REST and realtime API, the Console UI and an MCP server (`ontology.mdx:64-70`). The agent reads that world with `list_objects` and `describe_object` (`connect-mcp.mdx:225-227`). |
+| **Hands** — the verbs: what may be done to those nouns | Actions, flows, and the records themselves | The running app is an MCP server at `/api/v1/mcp`, on by default; objects are exposed automatically, actions opt in with `ai: { exposed: true }` (`README.md:161-177`). The opt-in is a schema field that defaults to `false` and requires an LLM-facing description of at least 40 characters (`action.zod.ts:764-771`). |
+| **A fence** — who may do what, on which rows and fields, checked on every call and recorded | Permissions, row-level and field-level security, sharing, audit | Security is middleware registered on the ObjectQL engine, so every engine operation passes through it (`security-plugin.ts:2293-2294`). MCP tools run under the caller's principal through "the SAME permission/RLS-enforcing path the REST API uses" (`mcp-http-tools.ts:7-11`). Audit rows are written by engine hooks on every insert, update and delete (`audit-writers.ts:2180-2185`). |
+
+Where the files live, so the citations can be opened: `README.md` at the repository root; `ontology.mdx` under `content/docs/concepts/` and `connect-mcp.mdx` under `content/docs/ai/`; `action.zod.ts` in `packages/spec/src/ui/`; `security-plugin.ts` in `packages/plugins/plugin-security/src/`; `mcp-http-tools.ts` in `packages/mcp/src/`; `audit-writers.ts` in `packages/plugins/plugin-audit/src/`. Line numbers are those of commit `1ecb08a1`.
+
+The concepts page compresses the right-hand column into one sentence that is worth keeping whole: the runtime "enforces the definition on every call. RBAC, row-level and field-level security, sharing, and audit apply to a REST request, a Console click and an agent's tool call alike. Nothing is reasoned over at runtime: what runs is what was validated."
+
+
+
+The rest of the post walks the three rows.
+
+## The world: a definition the runtime also reads
+
+A model's world has to satisfy two readers at once. The model needs it small and explicit enough to hold whole; the runtime needs it precise enough to execute. Documents satisfy the first reader and not the second: a retrieved policy PDF tells the model what an opportunity is, and nothing checks that the database agrees.
+
+An executable ontology's world is the typed definition itself. The concepts page: the ontology "is the definition of your business that the runtime executes: authored as typed metadata in `objectstack.config.ts`, compiled into the `objectstack.json` artifact." Objects and fields declare the entities and their typed attributes; relations declare lookups and master-detail links. The runtime derives the tables and the endpoints from that definition, and the MCP server's `describe_object` tool answers from the same definition. So the world the agent reads is, by construction, the world that runs. There is no second description to drift.
+
+Two consequences follow, and both are already argued elsewhere on this blog, so they are pointed at rather than repeated. First, the world is bounded: views, dashboards, apps and translations are projections of the ontology, not part of it, which is what lets an agent reason about the business from the core rather than from every screen ([the definition post](/en/blog/what-does-the-ontology-is-the-software-mean/) has the removal test for telling the two apart). Second, the world is validated before it is run: `os validate` rejects a definition that type-checks but would fail silently at runtime, including a missing security posture, so the world an agent is handed has already been refused once for every dangling reference in it.
+
+## The hands: tools the author armed, not tools the model guessed
+
+Hands are the part most enterprise AI stacks already have, in the form of function calling. The difference an executable ontology makes is in who decides which hands exist.
+
+Objects come with hands by default. Because the definition is typed, the runtime serves it as an MCP server: "Objects are tools, actions are tools, permissions decide what an agent may call, and audit records what it did" (`README.md:163-164`). The connect-mcp page lists what an agent gets as "Twelve tools, generated from your metadata": discovery (`list_objects`, `describe_object`, `validate_expression`), reads (`query_records`, `get_record`, `aggregate_records`), writes (`create_record`, `update_record`, `delete_record`), and actions (`list_actions`, `run_action`, `resume_run`). Nobody writes a tool definition for a new object; the object is the tool.
+
+Actions do not come with hands by default, and this is the deliberate part. An action becomes callable by an agent only when its author sets `ai: { exposed: true }` and writes the description the model will choose it by. The schema comment in `action.zod.ts` says why: "This is a deliberate governance gate: in an AI-authoring world the platform's value is that a human can govern exactly which capabilities the agent fleet is allowed to invoke — a half-finished or unreviewed action must never be silently armed." The smallest bundled example, the todo app, arms one like this (`examples/app-todo/src/actions/task.actions.ts`, with the UI-only keys trimmed):
+
+```ts
+export const CompleteTaskAction = defineAction({
+ name: 'complete_task',
+ label: 'Mark Complete',
+ objectName: 'todo_task',
+ type: 'script',
+ target: 'completeTask',
+ ai: {
+ exposed: true,
+ description: 'Mark a todo task as complete. Use when the user says a task is done or finished.',
+ },
+});
+```
+
+The bundled CRM, by contrast, arms none. Its one action, Convert Lead, is a `flow` action with no `ai` block, so an agent connected to that app has every data tool over its six objects and an empty answer from `list_actions`. That is not a gap in the example; it is the rule working. Hands over business logic are granted by a reviewed line in the definition, never assumed from the fact that a button exists.
+
+Why write operations in particular need this one governed definition rather than a second tool path beside the UI is the subject of [the ontology actions post](/en/blog/objectos-action-tools/), and is not repeated here.
+
+## The fence: decided on every call, by the runtime
+
+A fence that lives in the prompt is a request. A fence that lives in a policy service in front of the tools is a gate on calls. The fence an executable ontology carries is on the data path itself, and the distinction decides what a mistake can reach.
+
+The mechanism is middleware. `plugin-security` registers its enforcement on the ObjectQL engine (`ql.registerMiddleware(...)`, `security-plugin.ts:2294`), which is the engine every read and write goes through, whether the request came from a REST route, a Console click or an MCP tool. The MCP tool module says in its own header that it never touches the data engine directly: "all reads/writes go through an injected McpDataBridge that the host wires to the SAME permission/RLS-enforcing path the REST API uses. This module owns the tool shape; the bridge owns execution + security." There is no agent-specific fence to keep in sync with the human one, because there is one fence. Where exactly each check runs, and why filtering the model's output is too late, is argued in [where agent permissions are enforced](/en/blog/objectos-agent-permission-boundaries/).
+
+Three properties of that fence are worth naming, because the alternative stacks usually lack at least one.
+
+**It decides on rows and fields, not only on calls.** Permission sets grant object-level create, read, edit and delete; row-level security filters which records a caller can see; field-level security masks which columns. The security service contract states the failure stance for the row filter plainly: "Access-narrowing answers fail CLOSED ... a resolution failure returns a DENY filter (zero rows), never `undefined`" (`packages/spec/src/contracts/security-service.ts:28-31`). A model that asks for everything gets what its user may see.
+
+**It gates business logic separately, because logic has no backstop.** Object CRUD is bounded by RLS and FLS on every row. An action body is not: once invoked it "executes as TRUSTED app code," so the bridge "gates at invoke time: `ai.exposed` (the author's explicit AI opt-in, ADR-0011) + the ADR-0066 D4 capability gate" (`mcp-http-tools.ts:1128-1133`). Hands and fence meet exactly here: the same line that arms an action is the line the fence checks.
+
+**It records.** Audit writers are engine hooks on `afterInsert`, `afterUpdate` and `afterDelete` (`audit-writers.ts:2180-2185`), so a row changed by an agent's `update_record` lands in the audit log the same way a row changed in the Console does, with the acting identity. The README's fourth gate puts the consequence in one line: "The runtime enforces permissions and audit on every call, so even a wrong app stays inside the fence."
+
+## Measured on the bundled CRM
+
+One number, taken with the command the README prints under "measure it yourself", on `examples/app-crm` at commit `1ecb08a1`:
+
+```bash
+find examples/app-crm/src -name '*.ts' -not -name '*.test.ts' | xargs cat | wc -l
+# 1844
+```
+
+**1,844 lines across 30 files** is the whole application. Sorting its directories into the three supplies:
+
+| Supply | Directory | Lines | What is in it |
+| :--- | :--- | ---: | :--- |
+| World | `src/objects/` | 486 | Six objects (account, contact, lead, opportunity, opportunity line item, activity) with their fields and lookups |
+| Hands | `src/actions/` + `src/flows/` | 240 | One action, Convert Lead, and the screen flow it launches |
+| Fence | `src/security/` | 88 | `sales-positions.ts` is 78 of them: two permission sets, three positions |
+| Plumbing | tool registration, authorization middleware, audit code | 0 | A search for `registerTool`, `middleware`, `authoriz`, `checkPermission` and `audit` across `src/` finds two matches, both in comments |
+
+The rest is projections (views, a dashboard, an app, a page, translations, an analytics dataset) and seed data, which this post is not about.
+
+Call the headline figure **78 lines of fence**. That is the entire authorization declaration of a six-object CRM, and the same 78 lines govern the REST API, the Console and all twelve MCP tools, because all three reach the data through the engine the fence is mounted on. The complementary figure is the zero: the application declares its world, its hands and its fence, and contains no code that wires any of them to the model. The wiring is the runtime's, which is the whole content of the phrase "one artifact."
+
+Two honest footnotes on the measurement. The 78 lines are the app's own declaration; the row filter and field masking they imply are computed by the runtime from `sharingModel` on each object and from those permission sets, so "the fence" in the running system is larger than its declaration, as it should be. And this CRM, as noted above, exposes no action to AI, so its hands over business logic are zero until an author arms one.
+
+## The alternative, stated fairly
+
+The common way to supply the three things is a stack: retrieval over documents and schemas for the world, function calling (or a tool server you write) for the hands, and a policy engine or gateway in front of the tools for the fence. It deserves a fair hearing, because it is the right answer in several situations.
+
+It works with the systems you already run. Nothing is migrated; the retriever indexes what exists and the tools wrap APIs that already exist. Each layer is best of breed and swappable, so a better retriever or a stricter policy engine can be dropped in without touching the others. The patterns are well understood, the vendors are many, and a team that already owns a tool gateway has most of the fence in place. For an agent whose job is to read across a dozen legacy systems and write to none, this stack is probably what you want, and an executable ontology over those systems is read-only and early.
+
+What it does not solve is the thing the front page's first sentence is about: the three supplies are three artifacts, with three owners, and nothing checks that they agree.
+
+| | RAG + function calling + a policy layer | One executable ontology |
+| :--- | :--- | :--- |
+| **World** | A corpus the model reads; the systems do not read it | The definition the runtime executes; `describe_object` answers from it |
+| **Hands** | Tool schemas written by hand, one per operation, maintained beside the systems | Objects are tools automatically; actions opt in with one reviewed line |
+| **Fence** | A gate on tool calls, usually with a service account's authority behind each tool | Middleware on the data path, under the calling user's permissions, rows and fields included |
+| **Drift** | Three descriptions of the business, each able to be stale | One artifact, validated before it runs |
+| **Audit** | The call is logged; the row change is the downstream system's problem | The row change is logged with the identity, on every path |
+
+The fence row is the one that matters most in an incident. A policy layer in front of a `get_customer` tool can decide whether the agent may call it. It usually cannot decide which rows the agent's user is allowed to see inside the result, because the tool runs with whatever credential the integration was given. Row-level and field-level security on the data path answers that question for every caller, and answers it the same way for a human and an agent.
+
+## What this does not solve
+
+A post about a fence should say where the fence ends.
+
+**It does not supply judgment.** The fence makes a wrong call refusable and traceable; it does not make the call right. A model can still pick the wrong tool, misread a field or ask for an action it should not want. The world and the fence bound the damage. Intelligence, the thing the model does bring, is still what chooses.
+
+**The opt-in gate guards the doors the runtime owns.** The `ai.exposed` gate is enforced at the action door reached from the MCP `run_action` tool. The spec's own note is explicit that "REST `/actions` is NOT `ai.exposed`-gated and sits OUTSIDE this gate, so a human in front of that route is still yours to arrange" (`packages/spec/src/ai/tool.zod.ts:95-98`). Permissions still apply on that route; the AI opt-in does not.
+
+**Read audit is narrower than write audit.** Every insert, update and delete is recorded. Recording record-detail views is a per-object opt-in, and list and search results are not audited (`packages/plugins/plugin-audit/src/audit-plugin.ts:38-49`). An agent that reads widely leaves a smaller trail than one that writes.
+
+**The world is the apps the runtime runs.** For systems it does not run, federating an external datasource is read-only by default and described as early. The three supplies cover what the ontology executes; the rest of the estate still needs the stack above, or a migration.
+
+**An exposed action is trusted code.** The `run_action` tool says so to the model in its own description: the action body "runs as trusted application code with the app's full data authority." Arming an action is therefore a review decision, not a toggle, and `requiresConfirmation: true` exists for the ones that should ask a human first.
+
+## Hosted, or on your own infrastructure
+
+Everything above is the open stack, Apache-2.0, in one repository: the definition is a file you hold. The README then adds: "Want the same loop hosted, in the browser, nothing to install? That's ObjectOS, the commercial runtime environment built on ObjectStack." ObjectOS runs hosted in the browser with nothing to install (ObjectOS Cloud) or self-managed on your own infrastructure (ObjectOS Enterprise), and on either edition you can export your ontology and run it on the open-source ObjectStack runtime. The three supplies travel with the artifact, on every host it runs on.
+
+## Point your agent at it
+
+None of this requires taking the mapping on faith; the running app will show it to any MCP client.
+
+1. Scaffold a project with `npm create objectstack@latest my-app`. The scaffolder writes an `AGENTS.md` and installs the skills bundle, so a coding agent starts with the protocol's rules loaded, and [how to point your agent at ObjectStack](/en/blog/how-to-point-your-agent-at-objectstack/) covers the rule file and the tool server.
+2. Ask the agent for the world: a few objects with fields and a lookup between them. Ask it to run `npm run validate`, and read the diff before the Console.
+3. Start the app with `npx os dev --ui` and point any MCP client at `http://localhost:3000/api/v1/mcp`. The agent connects as a user, through the deployment's own OAuth server or an API key, and `describe_object` returns the world you just reviewed.
+4. Arm one hand: give one action `ai: { exposed: true }` with a description, validate again, and watch `list_actions` go from empty to one.
+5. Test the fence with a second user who lacks a permission the first has, and read the refusal and the audit row.
+
+The [Connect an MCP Client](https://objectstack.ai/docs/ai/connect-mcp) page has every client's one-liner, and the [Business Ontology](https://objectstack.ai/docs/concepts/ontology) page is the authority on the definition itself. Hand both to your agent. The world, the hands and the fence are in the same file it is about to write.
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hans.mdx b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hans.mdx
new file mode 100644
index 0000000..8091b06
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hans.mdx
@@ -0,0 +1,177 @@
+---
+title: AI 模型进了企业还缺什么?一个世界、一双手、一道围栏
+description: 缺的不是智力。模型进到一家公司,缺一个可以推理的世界、一双能动手的手、一道围住动作的围栏。一份可执行的业务本体同时供给这三样;文中一张带出处的表,把每一样对到运行时里供给它的机制。
+author: ObjectStack Team
+date: 2026-11-03
+status: published
+topic: ai-agents
+audience: it
+solutions: []
+industries: []
+cover: ./cover.svg
+tags:
+ - AI Agent
+ - 可执行业务本体
+ - MCP
+ - Agent 权限
+---
+
+**世界**:这家企业里有什么,每样东西是什么类型,彼此怎么连。
+
+**双手**:Agent 可以对这个世界做哪些操作,以它能调用的工具的形式给出。
+
+**围栏**:谁可以做什么,每一次调用都判一次而不是只判一次,事后留下记录。
+
+这三样,是 AI 模型进到一家企业时缺的东西;智力不在其中。这句话出自 ObjectStack 的首页,「00 · The idea」那一节:「What the model lacks is not intelligence: a world, hands, and a fence.」(模型缺的不是智力,而是一个世界、一双手和一道围栏。)本文要做的,是把这句话背后那条更窄、可核验的主张讲清楚:一份可执行的业务本体,用同一个工件同时供给这三样,而且每一样都能对到运行时里一个有名有姓的机制,源码里读得到。下面那张表就是这份对照,每个格子都给到文件和行号。表之后依次是:三样东西各自是什么;在自带的 CRM 示例上量出来的一个数字;把最强的替代方案公平地摆出来;以及这一切解决不了什么。
+
+## 这句话从哪里来
+
+objectstack.ai 的首页用三句话陈述这个想法,页面源码里原样保留(`apps/docs/app/[lang]/page.tsx` 第 127–131 行):
+
+> An enterprise is definition plus execution. When execution is nearly free, it is its definition.
+>
+> What the model lacks is not intelligence: a world, hands, and a fence.
+>
+> An ontology written clearly enough is software. Models change; the ontology stays.
+
+三句话的意思依次是:企业等于定义加执行,当执行几乎免费时,企业就是它的定义;模型缺的不是智力,而是一个世界、一双手和一道围栏;一份写得足够清楚的本体就是软件,模型会换,本体留下。
+
+把中间那句当作一份诊断来读。几乎每一个企业 AI 试点,都是把一个很能干的模型接进公司,然后一次事故一次事故地发现:模型不知道「客户」在这家公司里到底指什么(没有世界);它其实改不动一个客户记录(没有手);或者它改了一条不该碰的记录(没有围栏)。常见的应对是把缺的三样分别买齐:一层检索供给世界,一层函数调用供给双手,一层策略引擎供给围栏。这是合理的应对,本文后半会给它应有的篇幅。而第一句和第三句说的,是 ObjectStack 为什么走另一条路:如果业务的定义写得精确到可以直接执行,那同一份定义就是世界,就声明了双手,也自带围栏——而且不管这个季度读它的是哪个模型,它都在。
+
+## 三样供给,一个工件
+
+ObjectStack README 的一行定义是「一份可执行的业务本体。AI 编写它,运行时运行它,Agent 操作它,你拥有它。」概念页把它的核心列为六类东西:对象与字段、关系、动作、权限、流程、Agent 与工具定义。本文的主张是:这六类正好归入三样供给,而运行时把每一样都变成 Agent 直接可用的东西,中间不需要任何人写胶水代码。下面是对照表。所有出处都是 `objectstack-ai/objectstack` 仓库在提交 `1ecb08a1`(2026-10-16 的 `origin/main`)上的文件,或者从同一仓库构建出来的文档页。
+
+| 模型缺的 | 本体里供给它的 | 运行时机制,以及写在哪里 |
+| :--- | :--- | :--- |
+| **一个世界**——名词:有哪些实体,每个是什么类型,彼此什么关系 | 对象与字段;关系(六类中的两类) | 一份类型化定义编译成 `objectstack.json`;运行时从它推导出数据库结构、REST 与实时 API、Console 界面和一个 MCP 服务器(`ontology.mdx:64-70`)。Agent 用 `list_objects` 和 `describe_object` 读这个世界(`connect-mcp.mdx:225-227`)。 |
+| **一双手**——动词:可以对这些名词做什么 | 动作、流程,以及记录本身 | 运行中的应用就是一个 MCP 服务器,位于 `/api/v1/mcp`,默认开启;对象自动暴露,动作要用 `ai: { exposed: true }` 主动开启(`README.md:161-177`)。这个开关是一个 schema 字段,默认 `false`,开启时必须附一段不少于 40 个字符、面向模型的描述(`action.zod.ts:764-771`)。 |
+| **一道围栏**——谁可以做什么、对哪些行哪些字段,每次调用都查,查完留痕 | 权限、行级与字段级安全、共享、审计 | 安全是注册在 ObjectQL 引擎上的中间件,引擎的每一次操作都要经过它(`security-plugin.ts:2293-2294`)。MCP 工具以调用者的身份运行,走的是「与 REST API 相同的权限/RLS 强制路径」(`mcp-http-tools.ts:7-11`)。审计行由引擎钩子在每一次插入、更新、删除时写入(`audit-writers.ts:2180-2185`)。 |
+
+这些文件在哪里,方便按出处翻开:`README.md` 在仓库根;`ontology.mdx` 在 `content/docs/concepts/`,`connect-mcp.mdx` 在 `content/docs/ai/`;`action.zod.ts` 在 `packages/spec/src/ui/`;`security-plugin.ts` 在 `packages/plugins/plugin-security/src/`;`mcp-http-tools.ts` 在 `packages/mcp/src/`;`audit-writers.ts` 在 `packages/plugins/plugin-audit/src/`。行号以提交 `1ecb08a1` 为准。
+
+概念页把右边那一列压成一句话,值得整句保留:运行时「在每一次调用上强制执行这份定义。RBAC、行级与字段级安全、共享和审计,对一个 REST 请求、一次 Console 点击和一次 Agent 的工具调用一视同仁。运行时不做任何推理:跑的就是校验过的。」(原文:enforces the definition on every call. RBAC, row-level and field-level security, sharing, and audit apply to a REST request, a Console click and an agent's tool call alike. Nothing is reasoned over at runtime: what runs is what was validated.)
+
+
+
+接下来逐行展开这张表。
+
+## 世界:一份运行时也在读的定义
+
+模型的世界要同时满足两个读者。模型需要它足够小、足够明确,能一次装进上下文整体把握;运行时需要它足够精确,能直接执行。文档只满足第一个读者:一份检索出来的制度 PDF 能告诉模型「商机」是什么,但没有任何东西检查数据库是否同意。
+
+可执行本体的世界,就是那份类型化定义本身。概念页说,本体「是你的业务里那份由运行时执行的定义:以类型化元数据写在 `objectstack.config.ts` 里,编译成 `objectstack.json` 工件」。对象与字段声明实体及其类型化属性;关系声明查找和主从链接。运行时从这份定义推导出表和接口,MCP 服务器的 `describe_object` 工具也从这同一份定义作答。于是 Agent 读到的世界,在构造上就是正在运行的那个世界。没有第二份描述可以漂移。
+
+由此推出两个结论,这个博客上都已经有专文论证,这里只指向,不重复。第一,世界是有边界的:视图、仪表盘、应用和翻译是本体的投影,不是它的一部分,这正是 Agent 能从核心而不是从每一个屏幕出发推理业务的原因([那篇定义文章](/zh-Hans/blog/what-does-the-ontology-is-the-software-mean/)里有一条「删除测试」用来区分二者)。第二,世界先校验后运行:`os validate` 会拒绝那些类型检查通过、运行时却会静默失败的定义,包括缺失的安全姿态;所以交到 Agent 手里的世界,已经为其中每一处悬空引用被拒绝过一次。
+
+## 双手:由作者武装的工具,不是模型猜出来的工具
+
+双手是大多数企业 AI 技术栈已经有的部分,形态就是函数调用。可执行本体带来的差别,在于由谁决定哪些手存在。
+
+对象默认带手。因为定义是类型化的,运行时把它作为 MCP 服务器提供出来:「对象是工具,动作是工具,权限决定 Agent 可以调用什么,审计记录它做了什么。」(`README.md:163-164`,原文 Objects are tools, actions are tools, permissions decide what an agent may call, and audit records what it did.)connect-mcp 页面把 Agent 拿到的东西列为「十二个工具,由你的元数据生成」:发现(`list_objects`、`describe_object`、`validate_expression`),读取(`query_records`、`get_record`、`aggregate_records`),写入(`create_record`、`update_record`、`delete_record`),以及动作(`list_actions`、`run_action`、`resume_run`)。没有人为新对象写工具定义;对象就是工具。
+
+动作默认不带手,这是刻意设计的部分。一个动作只有在作者写下 `ai: { exposed: true }`、并写好模型据以选择它的描述之后,才成为 Agent 可调用的工具。`action.zod.ts` 里的 schema 注释说明了原因:「这是一道刻意设置的治理闸门:在一个由 AI 编写的世界里,平台的价值就在于人可以精确管住 Agent 群被允许调用哪些能力——一个半成品的、未经评审的动作,绝不能被静默地武装起来。」(原文:This is a deliberate governance gate: in an AI-authoring world the platform's value is that a human can govern exactly which capabilities the agent fleet is allowed to invoke — a half-finished or unreviewed action must never be silently armed.)最小的自带示例 todo 应用,是这样武装一个动作的(`examples/app-todo/src/actions/task.actions.ts`,去掉了只与界面相关的键):
+
+```ts
+export const CompleteTaskAction = defineAction({
+ name: 'complete_task',
+ label: 'Mark Complete',
+ objectName: 'todo_task',
+ type: 'script',
+ target: 'completeTask',
+ ai: {
+ exposed: true,
+ description: 'Mark a todo task as complete. Use when the user says a task is done or finished.',
+ },
+});
+```
+
+自带的 CRM 则一个也没有武装。它唯一的动作「Convert Lead」是一个 `flow` 类型的动作,没有 `ai` 块,所以连上这个应用的 Agent 拥有六个对象上的全部数据工具,而 `list_actions` 返回空。这不是示例的缺口,这是规则在起作用:对业务逻辑的手,由定义里一行经过评审的代码授予,绝不因为界面上有个按钮就被默认拥有。
+
+为什么偏偏写操作需要这一份受治理的定义,而不是在界面旁边另开一条工具通路,是[本体动作那篇](/zh-Hans/blog/objectos-action-tools/)的主题,这里不重复。
+
+## 围栏:由运行时在每一次调用上裁决
+
+写在提示词里的围栏,是一个请求。架在工具前面的策略服务里的围栏,是一道针对调用的闸。可执行本体自带的围栏在数据路径上,这个区别决定了一次错误能够到达多远。
+
+机制是中间件。`plugin-security` 把它的强制执行注册在 ObjectQL 引擎上(`ql.registerMiddleware(...)`,`security-plugin.ts:2294`),而引擎是每一次读写都必经的地方,不管请求来自 REST 路由、Console 点击还是 MCP 工具。MCP 工具模块在自己的文件头里就声明它从不直接触碰数据引擎:「所有读写都经过一个注入的 McpDataBridge,由宿主接到与 REST API 相同的权限/RLS 强制路径上。这个模块只负责工具的形状;桥负责执行与安全。」没有一道专给 Agent 的围栏需要和给人的那道保持同步,因为只有一道围栏。每一处检查到底在哪里运行、为什么事后过滤模型输出已经太晚,[Agent 权限在哪里强制执行](/zh-Hans/blog/objectos-agent-permission-boundaries/)一文有完整论证。
+
+这道围栏有三个性质值得点名,因为替代方案通常至少缺其中一个。
+
+**它裁决的是行和字段,不只是调用。** 权限集授予对象级的增、读、改、删;行级安全过滤调用者能看到哪些记录;字段级安全遮住哪些列。安全服务契约把行过滤的失败姿态写得很直白:「收窄访问的回答失败时关闭……解析失败返回一个 DENY 过滤器(零行),绝不返回 `undefined`」(`packages/spec/src/contracts/security-service.ts:28-31`)。一个什么都想要的模型,拿到的是它的用户被允许看到的。
+
+**它单独把守业务逻辑,因为逻辑背后没有兜底。** 对象的增删改查在每一行上都被 RLS 和 FLS 框住。动作体不是:一旦被调用,它「作为受信任的应用代码执行」,所以桥「在调用时把关:`ai.exposed`(作者明确的 AI 开启,ADR-0011)加上 ADR-0066 D4 的能力闸」(`mcp-http-tools.ts:1128-1133`)。双手和围栏正是在这里相遇:武装一个动作的那一行,就是围栏检查的那一行。
+
+**它留记录。** 审计写入器是挂在 `afterInsert`、`afterUpdate`、`afterDelete` 上的引擎钩子(`audit-writers.ts:2180-2185`),所以 Agent 用 `update_record` 改过的一行,和在 Console 里改过的一行,以同样的方式、带着操作者身份落进审计日志。README 的第四道闸把后果写成一句:「运行时在每一次调用上强制权限和审计,所以哪怕是一个写错了的应用,也留在围栏之内。」(原文:The runtime enforces permissions and audit on every call, so even a wrong app stays inside the fence.)
+
+## 在自带的 CRM 上量一个数
+
+一个数字,用 README「measure it yourself」一节印出来的那条命令,在提交 `1ecb08a1` 的 `examples/app-crm` 上量得:
+
+```bash
+find examples/app-crm/src -name '*.ts' -not -name '*.test.ts' | xargs cat | wc -l
+# 1844
+```
+
+**30 个文件、1,844 行**,是整个应用。把它的目录归入三样供给:
+
+| 供给 | 目录 | 行数 | 里面是什么 |
+| :--- | :--- | ---: | :--- |
+| 世界 | `src/objects/` | 486 | 六个对象(客户、联系人、线索、商机、商机明细、活动)及其字段和查找关系 |
+| 双手 | `src/actions/` + `src/flows/` | 240 | 一个动作「Convert Lead」,以及它启动的屏幕流程 |
+| 围栏 | `src/security/` | 88 | 其中 `sales-positions.ts` 占 78 行:两个权限集、三个岗位 |
+| 管道 | 工具注册、鉴权中间件、审计代码 | 0 | 在 `src/` 下搜索 `registerTool`、`middleware`、`authoriz`、`checkPermission` 和 `audit`,只有两处命中,都在注释里 |
+
+其余是投影(视图、一个仪表盘、一个应用、一个页面、翻译、一个分析数据集)和种子数据,不在本文范围内。
+
+把头条数字叫作 **78 行围栏**。这是一个六对象 CRM 的全部授权声明,而同样这 78 行管着 REST API、Console 和全部十二个 MCP 工具,因为三者都通过围栏所在的那个引擎触达数据。与之互补的数字是那个零:应用声明了它的世界、它的双手和它的围栏,却不含一行把它们接到模型上的代码。接线是运行时的事,这正是「一个工件」这四个字的全部内容。
+
+关于这次测量,两条诚实的脚注。78 行是应用自己的声明;它们所隐含的行过滤和字段遮蔽,由运行时根据每个对象上的 `sharingModel` 和这些权限集算出来,所以运行中的系统里,「围栏」比它的声明要大,这也是应该的。还有,如前所述,这个 CRM 没有向 AI 暴露任何动作,所以在作者武装一个动作之前,它在业务逻辑上的手是零。
+
+## 把替代方案公平地摆出来
+
+供给这三样东西的常见做法是一个技术栈:对文档和 schema 做检索供给世界,函数调用(或者你自己写一个工具服务)供给双手,一个策略引擎或网关架在工具前面供给围栏。它值得被公平对待,因为在好几种情形下它就是正确答案。
+
+它能和你已经在跑的系统一起工作。什么都不用迁移;检索器索引已有的东西,工具包装已有的 API。每一层都是各自领域里最好的、可替换的,换一个更好的检索器或更严的策略引擎,不必动其他层。这些模式人人熟悉,供应商众多,一个已经有工具网关的团队,围栏的大半已经就位。如果 Agent 的工作是横跨十几个遗留系统读取、却不写入任何一个,这个技术栈大概就是你要的——而架在那些系统之上的可执行本体,目前是只读的、早期的。
+
+它解决不了的,正是首页第一句话说的那件事:三样供给是三个工件,三个主人,没有任何东西检查它们是否一致。
+
+| | 检索 + 函数调用 + 策略层 | 一份可执行本体 |
+| :--- | :--- | :--- |
+| **世界** | 模型读的一个语料库;系统不读它 | 运行时执行的那份定义;`describe_object` 从它作答 |
+| **双手** | 手写的工具 schema,一个操作一个,在系统旁边另行维护 | 对象自动成为工具;动作用一行经过评审的代码开启 |
+| **围栏** | 架在工具调用上的闸,每个工具背后通常是一个服务账号的权限 | 数据路径上的中间件,以调用用户的权限运行,连行和字段一起管 |
+| **漂移** | 对业务的三份描述,每一份都可能过期 | 一个工件,先校验后运行 |
+| **审计** | 记下了调用;行的变更是下游系统的事 | 行的变更带着身份被记录,每条路径都一样 |
+
+出事的时候,围栏那一行最要紧。架在 `get_customer` 工具前面的策略层,可以裁决 Agent 能不能调用它。它通常裁决不了结果里哪些行是 Agent 的用户被允许看的,因为工具是用集成拿到的那份凭据在跑。数据路径上的行级和字段级安全,对每一个调用者都回答这个问题,而且对人和 Agent 的回答是同一个。
+
+## 这些解决不了什么
+
+一篇讲围栏的文章,应该说清围栏到哪里为止。
+
+**它不供给判断力。** 围栏让一次错误调用可以被拒绝、可以被追溯,但不会让这次调用变对。模型仍然可能选错工具、读错字段,或者要求一个它本不该想要的动作。世界和围栏框住损害的范围;而选择,仍然由模型确实带来的那样东西——智力——来做。
+
+**开启闸门只把守运行时拥有的那些门。** `ai.exposed` 这道闸在 MCP 的 `run_action` 工具所到达的动作门上强制执行。spec 自己的注释说得明白:「REST `/actions` 不受 `ai.exposed` 把守,在这道闸之外,所以那条路由前面要不要有个人,仍然由你安排。」(`packages/spec/src/ai/tool.zod.ts:95-98`)那条路由上权限照常生效;AI 开启不生效。
+
+**读审计比写审计窄。** 每一次插入、更新、删除都有记录。记录单条记录的详情查看是按对象逐个开启的,列表和搜索结果不审计(`packages/plugins/plugin-audit/src/audit-plugin.ts:38-49`)。一个大量读取的 Agent,留下的痕迹比一个写入的少。
+
+**世界只到运行时所运行的应用为止。** 对它不运行的系统,联邦一个外部数据源默认只读,并被标明为早期。三样供给覆盖的是本体所执行的部分;其余的 IT 资产仍然需要上面那个技术栈,或者一次迁移。
+
+**暴露出去的动作是受信任的代码。** `run_action` 工具在它自己的描述里就对模型说了:动作体「作为受信任的应用代码运行,拥有应用的全部数据权限」。所以武装一个动作是一项评审决定,不是一个开关;对那些应该先问人的动作,有 `requiresConfirmation: true`。
+
+## 托管,或者放在你自己的基础设施上
+
+上面的一切都是开放栈,Apache-2.0,在同一个仓库里:定义是你手里的一个文件。README 接着说:「想把同一个循环托管起来、在浏览器里用、什么都不用安装?那就是 ObjectOS——建立在 ObjectStack 之上的商业运行环境。」ObjectOS 既可托管在浏览器中、无需安装(ObjectOS Cloud),也可自管部署在你自己的基础设施上(ObjectOS Enterprise);无论哪个版本,你都可以导出本体,拿到开源的 ObjectStack 运行时上运行。三样供给随着工件一起走,它跑在哪台主机上都一样。
+
+## 让你的 Agent 指向它
+
+上面这张对照表不需要靠信任来接受;运行中的应用会把它展示给任何一个 MCP 客户端。
+
+1. 用 `npm create objectstack@latest my-app` 搭一个项目。脚手架会写好 `AGENTS.md` 并安装技能包,编码 Agent 一开始就带着协议规则;工具服务器怎么接,见文末的 Connect an MCP Client 页面。
+2. 向 Agent 要一个世界:几个带字段的对象,对象之间有一个查找关系。让它跑 `npm run validate`,先看 diff,再看 Console。
+3. 用 `npx os dev --ui` 启动应用,把任意 MCP 客户端指向 `http://localhost:3000/api/v1/mcp`。Agent 以一个用户的身份连进来——走部署自己的 OAuth 服务器,或者一把 API key——`describe_object` 返回的就是你刚评审过的那个世界。
+4. 武装一只手:给一个动作加上 `ai: { exposed: true }` 和一段描述,再校验一次,看着 `list_actions` 从空变成一个。
+5. 用第二个用户测围栏:让他缺一项第一个用户有的权限,读那条拒绝,再读那条审计记录。
+
+[Connect an MCP Client](https://objectstack.ai/docs/ai/connect-mcp) 页面有每种客户端的一行命令,[Business Ontology](https://objectstack.ai/docs/concepts/ontology) 页面是定义本身的权威出处。把两页都交给你的 Agent。世界、双手和围栏,就在它即将写下的同一个文件里。
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hant.mdx b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hant.mdx
new file mode 100644
index 0000000..c17342f
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/index.zh-Hant.mdx
@@ -0,0 +1,178 @@
+---
+# @generated zh-Hant from zh-Hans (s2twp) — edit the zh-Hans file; delete this line to hand-maintain.
+title: AI 模型進了企業還缺什麼?一個世界、一雙手、一道圍欄
+description: 缺的不是智力。模型進到一家公司,缺一個可以推理的世界、一雙能動手的手、一道圍住動作的圍欄。一份可執行的業務本體同時供給這三樣;文中一張帶出處的表,把每一樣對到執行時裡供給它的機制。
+author: ObjectStack Team
+date: 2026-11-03
+status: published
+topic: ai-agents
+audience: it
+solutions: []
+industries: []
+cover: ./cover.svg
+tags:
+ - AI Agent
+ - 可執行業務本體
+ - MCP
+ - Agent 權限
+---
+
+**世界**:這家企業裡有什麼,每樣東西是什麼型別,彼此怎麼連。
+
+**雙手**:Agent 可以對這個世界做哪些操作,以它能呼叫的工具的形式給出。
+
+**圍欄**:誰可以做什麼,每一次呼叫都判一次而不是隻判一次,事後留下記錄。
+
+這三樣,是 AI 模型進到一家企業時缺的東西;智力不在其中。這句話出自 ObjectStack 的首頁,「00 · The idea」那一節:「What the model lacks is not intelligence: a world, hands, and a fence.」(模型缺的不是智力,而是一個世界、一雙手和一道圍欄。)本文要做的,是把這句話背後那條更窄、可核驗的主張講清楚:一份可執行的業務本體,用同一個工件同時供給這三樣,而且每一樣都能對到執行時裡一個有名有姓的機制,原始碼裡讀得到。下面那張表就是這份對照,每個格子都給到檔案和行號。表之後依次是:三樣東西各自是什麼;在自帶的 CRM 示例上量出來的一個數字;把最強的替代方案公平地擺出來;以及這一切解決不了什麼。
+
+## 這句話從哪裡來
+
+objectstack.ai 的首頁用三句話陳述這個想法,頁面原始碼裡原樣保留(`apps/docs/app/[lang]/page.tsx` 第 127–131 行):
+
+> An enterprise is definition plus execution. When execution is nearly free, it is its definition.
+>
+> What the model lacks is not intelligence: a world, hands, and a fence.
+>
+> An ontology written clearly enough is software. Models change; the ontology stays.
+
+三句話的意思依次是:企業等於定義加執行,當執行幾乎免費時,企業就是它的定義;模型缺的不是智力,而是一個世界、一雙手和一道圍欄;一份寫得足夠清楚的本體就是軟體,模型會換,本體留下。
+
+把中間那句當作一份診斷來讀。幾乎每一個企業 AI 試點,都是把一個很能幹的模型接進公司,然後一次事故一次事故地發現:模型不知道「客戶」在這家公司裡到底指什麼(沒有世界);它其實改不動一個客戶記錄(沒有手);或者它改了一條不該碰的記錄(沒有圍欄)。常見的應對是把缺的三樣分別買齊:一層檢索供給世界,一層函式呼叫供給雙手,一層策略引擎供給圍欄。這是合理的應對,本文後半會給它應有的篇幅。而第一句和第三句說的,是 ObjectStack 為什麼走另一條路:如果業務的定義寫得精確到可以直接執行,那同一份定義就是世界,就聲明瞭雙手,也自帶圍欄——而且不管這個季度讀它的是哪個模型,它都在。
+
+## 三樣供給,一個工件
+
+ObjectStack README 的一行定義是「一份可執行的業務本體。AI 編寫它,執行時執行它,Agent 操作它,你擁有它。」概念頁把它的核心列為六類東西:物件與欄位、關係、動作、權限、流程、Agent 與工具定義。本文的主張是:這六類正好歸入三樣供給,而執行時把每一樣都變成 Agent 直接可用的東西,中間不需要任何人寫膠水程式碼。下面是對照表。所有出處都是 `objectstack-ai/objectstack` 倉庫在提交 `1ecb08a1`(2026-10-16 的 `origin/main`)上的檔案,或者從同一倉庫構建出來的文件頁。
+
+| 模型缺的 | 本體裡供給它的 | 執行時機制,以及寫在哪裡 |
+| :--- | :--- | :--- |
+| **一個世界**——名詞:有哪些實體,每個是什麼型別,彼此什麼關係 | 物件與欄位;關係(六類中的兩類) | 一份型別化定義編譯成 `objectstack.json`;執行時從它推匯出資料庫結構、REST 與即時 API、Console 介面和一個 MCP 伺服器(`ontology.mdx:64-70`)。Agent 用 `list_objects` 和 `describe_object` 讀這個世界(`connect-mcp.mdx:225-227`)。 |
+| **一雙手**——動詞:可以對這些名詞做什麼 | 動作、流程,以及記錄本身 | 執行中的應用就是一個 MCP 伺服器,位於 `/api/v1/mcp`,預設開啟;物件自動暴露,動作要用 `ai: { exposed: true }` 主動開啟(`README.md:161-177`)。這個開關是一個 schema 欄位,預設 `false`,開啟時必須附一段不少於 40 個字元、面向模型的描述(`action.zod.ts:764-771`)。 |
+| **一道圍欄**——誰可以做什麼、對哪些行哪些欄位,每次呼叫都查,查完留痕 | 權限、行級與欄位級安全、共享、審計 | 安全是註冊在 ObjectQL 引擎上的中介軟體,引擎的每一次操作都要經過它(`security-plugin.ts:2293-2294`)。MCP 工具以呼叫者的身份執行,走的是「與 REST API 相同的權限/RLS 強制路徑」(`mcp-http-tools.ts:7-11`)。審計行由引擎鉤子在每一次插入、更新、刪除時寫入(`audit-writers.ts:2180-2185`)。 |
+
+這些檔案在哪裡,方便按出處翻開:`README.md` 在倉庫根;`ontology.mdx` 在 `content/docs/concepts/`,`connect-mcp.mdx` 在 `content/docs/ai/`;`action.zod.ts` 在 `packages/spec/src/ui/`;`security-plugin.ts` 在 `packages/plugins/plugin-security/src/`;`mcp-http-tools.ts` 在 `packages/mcp/src/`;`audit-writers.ts` 在 `packages/plugins/plugin-audit/src/`。行號以提交 `1ecb08a1` 為準。
+
+概念頁把右邊那一列壓成一句話,值得整句保留:執行時「在每一次呼叫上強制執行這份定義。RBAC、行級與欄位級安全、共享和審計,對一個 REST 請求、一次 Console 點選和一次 Agent 的工具呼叫一視同仁。執行時不做任何推理:跑的就是校驗過的。」(原文:enforces the definition on every call. RBAC, row-level and field-level security, sharing, and audit apply to a REST request, a Console click and an agent's tool call alike. Nothing is reasoned over at runtime: what runs is what was validated.)
+
+
+
+接下來逐行展開這張表。
+
+## 世界:一份執行時也在讀的定義
+
+模型的世界要同時滿足兩個讀者。模型需要它足夠小、足夠明確,能一次裝進上下文整體把握;執行時需要它足夠精確,能直接執行。文件只滿足第一個讀者:一份檢索出來的制度 PDF 能告訴模型「商機」是什麼,但沒有任何東西檢查資料庫是否同意。
+
+可執行本體的世界,就是那份型別化定義本身。概念頁說,本體「是你的業務裡那份由執行時執行的定義:以型別化後設資料寫在 `objectstack.config.ts` 裡,編譯成 `objectstack.json` 工件」。物件與欄位宣告實體及其型別化屬性;關係宣告查詢和主從連結。執行時從這份定義推匯出表和介面,MCP 伺服器的 `describe_object` 工具也從這同一份定義作答。於是 Agent 讀到的世界,在構造上就是正在執行的那個世界。沒有第二份描述可以漂移。
+
+由此推出兩個結論,這個部落格上都已經有專文論證,這裡只指向,不重複。第一,世界是有邊界的:檢視、儀表盤、應用和翻譯是本體的投影,不是它的一部分,這正是 Agent 能從核心而不是從每一個螢幕出發推理業務的原因([那篇定義文章](/zh-Hant/blog/what-does-the-ontology-is-the-software-mean/)裡有一條「刪除測試」用來區分二者)。第二,世界先校驗後執行:`os validate` 會拒絕那些型別檢查通過、執行時卻會靜默失敗的定義,包括缺失的安全姿態;所以交到 Agent 手裡的世界,已經為其中每一處懸空引用被拒絕過一次。
+
+## 雙手:由作者武裝的工具,不是模型猜出來的工具
+
+雙手是大多數企業 AI 技術棧已經有的部分,形態就是函式呼叫。可執行本體帶來的差別,在於由誰決定哪些手存在。
+
+物件預設帶手。因為定義是型別化的,執行時把它作為 MCP 伺服器提供出來:「物件是工具,動作是工具,權限決定 Agent 可以呼叫什麼,審計記錄它做了什麼。」(`README.md:163-164`,原文 Objects are tools, actions are tools, permissions decide what an agent may call, and audit records what it did.)connect-mcp 頁面把 Agent 拿到的東西列為「十二個工具,由你的後設資料生成」:發現(`list_objects`、`describe_object`、`validate_expression`),讀取(`query_records`、`get_record`、`aggregate_records`),寫入(`create_record`、`update_record`、`delete_record`),以及動作(`list_actions`、`run_action`、`resume_run`)。沒有人為新物件寫工具定義;物件就是工具。
+
+動作預設不帶手,這是刻意設計的部分。一個動作只有在作者寫下 `ai: { exposed: true }`、並寫好模型據以選擇它的描述之後,才成為 Agent 可呼叫的工具。`action.zod.ts` 裡的 schema 註釋說明了原因:「這是一道刻意設定的治理閘門:在一個由 AI 編寫的世界裡,平臺的價值就在於人可以精確管住 Agent 群被允許呼叫哪些能力——一個半成品的、未經評審的動作,絕不能被靜默地武裝起來。」(原文:This is a deliberate governance gate: in an AI-authoring world the platform's value is that a human can govern exactly which capabilities the agent fleet is allowed to invoke — a half-finished or unreviewed action must never be silently armed.)最小的自帶示例 todo 應用,是這樣武裝一個動作的(`examples/app-todo/src/actions/task.actions.ts`,去掉了只與介面相關的鍵):
+
+```ts
+export const CompleteTaskAction = defineAction({
+ name: 'complete_task',
+ label: 'Mark Complete',
+ objectName: 'todo_task',
+ type: 'script',
+ target: 'completeTask',
+ ai: {
+ exposed: true,
+ description: 'Mark a todo task as complete. Use when the user says a task is done or finished.',
+ },
+});
+```
+
+自帶的 CRM 則一個也沒有武裝。它唯一的動作「Convert Lead」是一個 `flow` 型別的動作,沒有 `ai` 塊,所以連上這個應用的 Agent 擁有六個物件上的全部資料工具,而 `list_actions` 返回空。這不是示例的缺口,這是規則在起作用:對業務邏輯的手,由定義裡一行經過評審的程式碼授予,絕不因為介面上有個按鈕就被預設擁有。
+
+為什麼偏偏寫操作需要這一份受治理的定義,而不是在介面旁邊另開一條工具通路,是[本體動作那篇](/zh-Hant/blog/objectos-action-tools/)的主題,這裡不重複。
+
+## 圍欄:由執行時在每一次呼叫上裁決
+
+寫在提示詞裡的圍欄,是一個請求。架在工具前面的策略服務裡的圍欄,是一道針對呼叫的閘。可執行本體自帶的圍欄在資料路徑上,這個區別決定了一次錯誤能夠到達多遠。
+
+機制是中介軟體。`plugin-security` 把它的強制執行註冊在 ObjectQL 引擎上(`ql.registerMiddleware(...)`,`security-plugin.ts:2294`),而引擎是每一次讀寫都必經的地方,不管請求來自 REST 路由、Console 點選還是 MCP 工具。MCP 工具模組在自己的檔案頭裡就宣告它從不直接觸碰資料引擎:「所有讀寫都經過一個注入的 McpDataBridge,由宿主接到與 REST API 相同的權限/RLS 強制路徑上。這個模組只負責工具的形狀;橋負責執行與安全。」沒有一道專給 Agent 的圍欄需要和給人的那道保持同步,因為只有一道圍欄。每一處檢查到底在哪裡執行、為什麼事後過濾模型輸出已經太晚,[Agent 權限在哪裡強制執行](/zh-Hant/blog/objectos-agent-permission-boundaries/)一文有完整論證。
+
+這道圍欄有三個性質值得點名,因為替代方案通常至少缺其中一個。
+
+**它裁決的是行和欄位,不只是呼叫。** 權限集授予物件級的增、讀、改、刪;行級安全過濾呼叫者能看到哪些記錄;欄位級安全遮住哪些列。安全服務契約把行過濾的失敗姿態寫得很直白:「收窄訪問的回答失敗時關閉……解析失敗返回一個 DENY 過濾器(零行),絕不返回 `undefined`」(`packages/spec/src/contracts/security-service.ts:28-31`)。一個什麼都想要的模型,拿到的是它的使用者被允許看到的。
+
+**它單獨把守業務邏輯,因為邏輯背後沒有兜底。** 物件的增刪改查在每一行上都被 RLS 和 FLS 框住。動作體不是:一旦被呼叫,它「作為受信任的應用程式碼執行」,所以橋「在呼叫時把關:`ai.exposed`(作者明確的 AI 開啟,ADR-0011)加上 ADR-0066 D4 的能力閘」(`mcp-http-tools.ts:1128-1133`)。雙手和圍欄正是在這裡相遇:武裝一個動作的那一行,就是圍欄檢查的那一行。
+
+**它留記錄。** 審計寫入器是掛在 `afterInsert`、`afterUpdate`、`afterDelete` 上的引擎鉤子(`audit-writers.ts:2180-2185`),所以 Agent 用 `update_record` 改過的一行,和在 Console 裡改過的一行,以同樣的方式、帶著操作者身份落進審計日誌。README 的第四道閘把後果寫成一句:「執行時在每一次呼叫上強制權限和審計,所以哪怕是一個寫錯了的應用,也留在圍欄之內。」(原文:The runtime enforces permissions and audit on every call, so even a wrong app stays inside the fence.)
+
+## 在自帶的 CRM 上量一個數
+
+一個數字,用 README「measure it yourself」一節印出來的那條命令,在提交 `1ecb08a1` 的 `examples/app-crm` 上量得:
+
+```bash
+find examples/app-crm/src -name '*.ts' -not -name '*.test.ts' | xargs cat | wc -l
+# 1844
+```
+
+**30 個檔案、1,844 行**,是整個應用。把它的目錄歸入三樣供給:
+
+| 供給 | 目錄 | 行數 | 裡面是什麼 |
+| :--- | :--- | ---: | :--- |
+| 世界 | `src/objects/` | 486 | 六個物件(客戶、聯絡人、線索、商機、商機明細、活動)及其欄位和查詢關係 |
+| 雙手 | `src/actions/` + `src/flows/` | 240 | 一個動作「Convert Lead」,以及它啟動的螢幕流程 |
+| 圍欄 | `src/security/` | 88 | 其中 `sales-positions.ts` 佔 78 行:兩個權限集、三個崗位 |
+| 管道 | 工具註冊、鑑權中介軟體、審計程式碼 | 0 | 在 `src/` 下搜尋 `registerTool`、`middleware`、`authoriz`、`checkPermission` 和 `audit`,只有兩處命中,都在註釋裡 |
+
+其餘是投影(檢視、一個儀表盤、一個應用、一個頁面、翻譯、一個分析資料集)和種子資料,不在本文範圍內。
+
+把頭條數字叫作 **78 行圍欄**。這是一個六物件 CRM 的全部授權宣告,而同樣這 78 行管著 REST API、Console 和全部十二個 MCP 工具,因為三者都通過圍欄所在的那個引擎觸達資料。與之互補的數字是那個零:應用聲明瞭它的世界、它的雙手和它的圍欄,卻不含一行把它們接到模型上的程式碼。接線是執行時的事,這正是「一個工件」這四個字的全部內容。
+
+關於這次測量,兩條誠實的腳註。78 行是應用自己的宣告;它們所隱含的行過濾和欄位遮蔽,由執行時根據每個物件上的 `sharingModel` 和這些權限集算出來,所以執行中的系統裡,「圍欄」比它的宣告要大,這也是應該的。還有,如前所述,這個 CRM 沒有向 AI 暴露任何動作,所以在作者武裝一個動作之前,它在業務邏輯上的手是零。
+
+## 把替代方案公平地擺出來
+
+供給這三樣東西的常見做法是一個技術棧:對文件和 schema 做檢索供給世界,函式呼叫(或者你自己寫一個工具服務)供給雙手,一個策略引擎或閘道器架在工具前面供給圍欄。它值得被公平對待,因為在好幾種情形下它就是正確答案。
+
+它能和你已經在跑的系統一起工作。什麼都不用遷移;檢索器索引已有的東西,工具包裝已有的 API。每一層都是各自領域裡最好的、可替換的,換一個更好的檢索器或更嚴的策略引擎,不必動其他層。這些模式人人熟悉,供應商眾多,一個已經有工具閘道器的團隊,圍欄的大半已經就位。如果 Agent 的工作是橫跨十幾個遺留系統讀取、卻不寫入任何一個,這個技術棧大概就是你要的——而架在那些系統之上的可執行本體,目前是隻讀的、早期的。
+
+它解決不了的,正是首頁第一句話說的那件事:三樣供給是三個工件,三個主人,沒有任何東西檢查它們是否一致。
+
+| | 檢索 + 函式呼叫 + 策略層 | 一份可執行本體 |
+| :--- | :--- | :--- |
+| **世界** | 模型讀的一個語料庫;系統不讀它 | 執行時執行的那份定義;`describe_object` 從它作答 |
+| **雙手** | 手寫的工具 schema,一個操作一個,在系統旁邊另行維護 | 物件自動成為工具;動作用一行經過評審的程式碼開啟 |
+| **圍欄** | 架在工具呼叫上的閘,每個工具背後通常是一個服務賬號的權限 | 資料路徑上的中介軟體,以呼叫使用者的權限執行,連行和欄位一起管 |
+| **漂移** | 對業務的三份描述,每一份都可能過期 | 一個工件,先校驗後執行 |
+| **審計** | 記下了呼叫;行的變更是下游系統的事 | 行的變更帶著身份被記錄,每條路徑都一樣 |
+
+出事的時候,圍欄那一行最要緊。架在 `get_customer` 工具前面的策略層,可以裁決 Agent 能不能呼叫它。它通常裁決不了結果裡哪些行是 Agent 的使用者被允許看的,因為工具是用整合拿到的那份憑據在跑。資料路徑上的行級和欄位級安全,對每一個呼叫者都回答這個問題,而且對人和 Agent 的回答是同一個。
+
+## 這些解決不了什麼
+
+一篇講圍欄的文章,應該說清圍欄到哪裡為止。
+
+**它不供給判斷力。** 圍欄讓一次錯誤呼叫可以被拒絕、可以被追溯,但不會讓這次呼叫變對。模型仍然可能選錯工具、讀錯欄位,或者要求一個它本不該想要的動作。世界和圍欄框住損害的範圍;而選擇,仍然由模型確實帶來的那樣東西——智力——來做。
+
+**開啟閘門只把守執行時擁有的那些門。** `ai.exposed` 這道閘在 MCP 的 `run_action` 工具所到達的動作門上強制執行。spec 自己的註釋說得明白:「REST `/actions` 不受 `ai.exposed` 把守,在這道閘之外,所以那條路由前面要不要有個人,仍然由你安排。」(`packages/spec/src/ai/tool.zod.ts:95-98`)那條路由上權限照常生效;AI 開啟不生效。
+
+**讀審計比寫審計窄。** 每一次插入、更新、刪除都有記錄。記錄單條記錄的詳情檢視是按物件逐個開啟的,列表和搜尋結果不審計(`packages/plugins/plugin-audit/src/audit-plugin.ts:38-49`)。一個大量讀取的 Agent,留下的痕跡比一個寫入的少。
+
+**世界只到執行時所執行的應用為止。** 對它不執行的系統,聯邦一個外部資料來源預設只讀,並被標明為早期。三樣供給覆蓋的是本體所執行的部分;其餘的 IT 資產仍然需要上面那個技術棧,或者一次遷移。
+
+**暴露出去的動作是受信任的程式碼。** `run_action` 工具在它自己的描述裡就對模型說了:動作體「作為受信任的應用程式碼執行,擁有應用的全部資料權限」。所以武裝一個動作是一項評審決定,不是一個開關;對那些應該先問人的動作,有 `requiresConfirmation: true`。
+
+## 託管,或者放在你自己的基礎設施上
+
+上面的一切都是開放棧,Apache-2.0,在同一個倉庫裡:定義是你手裡的一個檔案。README 接著說:「想把同一個迴圈託管起來、在瀏覽器裡用、什麼都不用安裝?那就是 ObjectOS——建立在 ObjectStack 之上的商業執行環境。」ObjectOS 既可託管在瀏覽器中、無需安裝(ObjectOS Cloud),也可自管部署在你自己的基礎設施上(ObjectOS Enterprise);無論哪個版本,你都可以匯出本體,拿到開源的 ObjectStack 執行時上執行。三樣供給隨著工件一起走,它跑在哪臺主機上都一樣。
+
+## 讓你的 Agent 指向它
+
+上面這張對照表不需要靠信任來接受;執行中的應用會把它展示給任何一個 MCP 客戶端。
+
+1. 用 `npm create objectstack@latest my-app` 搭一個專案。腳手架會寫好 `AGENTS.md` 並安裝技能包,編碼 Agent 一開始就帶著協議規則;工具伺服器怎麼接,見文末的 Connect an MCP Client 頁面。
+2. 向 Agent 要一個世界:幾個帶欄位的物件,物件之間有一個查詢關係。讓它跑 `npm run validate`,先看 diff,再看 Console。
+3. 用 `npx os dev --ui` 啟動應用,把任意 MCP 客戶端指向 `http://localhost:3000/api/v1/mcp`。Agent 以一個使用者的身份連進來——走部署自己的 OAuth 伺服器,或者一把 API key——`describe_object` 返回的就是你剛評審過的那個世界。
+4. 武裝一隻手:給一個動作加上 `ai: { exposed: true }` 和一段描述,再校驗一次,看著 `list_actions` 從空變成一個。
+5. 用第二個使用者測圍欄:讓他缺一項第一個使用者有的權限,讀那條拒絕,再讀那條審計記錄。
+
+[Connect an MCP Client](https://objectstack.ai/docs/ai/connect-mcp) 頁面有每種客戶端的一行命令,[Business Ontology](https://objectstack.ai/docs/concepts/ontology) 頁面是定義本身的權威出處。把兩頁都交給你的 Agent。世界、雙手和圍欄,就在它即將寫下的同一個檔案裡。
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies-en.svg b/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies-en.svg
new file mode 100644
index 0000000..604b057
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies-en.svg
@@ -0,0 +1,78 @@
+
diff --git a/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies.svg b/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies.svg
new file mode 100644
index 0000000..11ae2d0
--- /dev/null
+++ b/content/blog/what-do-ai-models-lack-in-the-enterprise/three-supplies.svg
@@ -0,0 +1,78 @@
+