diff --git a/content/docs/getting-started/build-with-claude-code.mdx b/content/docs/getting-started/build-with-claude-code.mdx
index fb88fd8400..942b017eba 100644
--- a/content/docs/getting-started/build-with-claude-code.mdx
+++ b/content/docs/getting-started/build-with-claude-code.mdx
@@ -41,7 +41,7 @@ hand-edits generated glue, and no metadata mistake reaches the browser unchecked
| You need | Why |
|:---|:---|
-| **Node.js 18+** and **pnpm** | Runs the scaffolder and the dev server (see [prerequisites](/docs/getting-started#prerequisites)). |
+| **Node.js 18+** and npm (pnpm / yarn / bun also work) | Runs the scaffolder and the dev server (see [prerequisites](/docs/getting-started#prerequisites)). |
| **[Claude Code](https://claude.com/claude-code)** (or Cursor / Copilot) | Your agent reads `AGENTS.md` + the ObjectStack skills and authors the metadata. |
## 1. Scaffold the project
@@ -63,10 +63,6 @@ The scaffolder does more than copy files. It:
`npm run validate` after every metadata change*.
```
- ╔═══════════════════════════════════╗
- ║ ◆ Create ObjectStack v6.x ║
- ╚═══════════════════════════════════╝
-
◆ New Environment
────────────────────────────────────────
Environment: support-desk
@@ -75,6 +71,12 @@ The scaffolder does more than copy files. It:
…
→ Installing AI skills for your coding agent...
✓ Environment created!
+
+ Next steps:
+ cd support-desk
+ npm install
+ npm run dev # Start development server
+ npm run validate # Verify metadata: schema + predicates + bindings
```
This is why AI authoring is reliable rather than a guessing game: **the agent
@@ -192,9 +194,20 @@ export const TicketViews = defineView({
});
```
+The agent also **wires the new files into `objectstack.config.ts`** — the object
+through the `src/objects/index.ts` barrel, and the action and view via the
+`actions:` / `views:` arrays in `defineStack()`. There is no filename-suffix
+magic: metadata exists in the app only if the config imports it, so if a
+freshly-authored action doesn't show up, the wiring is the first thing to check.
+
This is the same metadata that powers the REST API, the Console UI, **and the MCP
tools exposed to AI** — define it once, and ObjectStack derives the rest.
+
+Every example on this page was authored against `@objectstack/spec` 16.x and
+passes `os validate` verbatim in a freshly scaffolded project.
+
+
## 4. The gate: `os validate` catches AI mistakes
The most common way AI-authored metadata goes wrong is a mistake that **type-checks
@@ -289,6 +302,43 @@ tightening on each pass until the app is right. See
[How AI development works](/docs/getting-started/how-ai-development-works) for why
this stays fast and safe as the app grows.
+
+Beyond the pass/fail gate there's a **quality rubric**: `npx os lint --score`
+prints a 0–100 metadata-quality score (relationship patterns, missing options,
+roll-ups, name fields). Ask the agent to keep the project lint-clean — "run
+`os lint` and fix the warnings" is a perfectly good prompt.
+
+
+## Beyond the first app — one skill per metadata domain
+
+The loop above never changes; what changes is **which skill the agent loads**.
+The bundle ships nine, one per metadata domain, and the agent picks by task
+context (the trigger table lives in your project's `AGENTS.md`). To grow the
+support desk into a full application, keep describing — each row is a real
+prompt you can give verbatim:
+
+| You want | Skill the agent loads | Say something like |
+|:---|:---|:---|
+| Data model — objects, fields, relationships, validations, seeds | `objectstack-data` | "Add an `account` object and link tickets to it with a required lookup. Seed three demo accounts." |
+| Queries & reports over records | `objectstack-query` | "Show me the count of open tickets per priority, using an aggregation." |
+| Views, dashboards, apps, record pages | `objectstack-ui` | "Add a dashboard with a metric for open tickets and a bar chart of tickets by priority." |
+| Business automation — flows, approvals, schedules | `objectstack-automation` | "Every day at 9:00, escalate tickets that have been open more than 48 hours." |
+| Permissions & row-level security | `objectstack-data` (security sections) | "Members should only see their own tickets; support managers see everything." |
+| Formula / conditional-field logic (CEL) | `objectstack-formula` | "Make `resolved_at` required and visible only when status is resolved." |
+| AI agents & tools inside your app | `objectstack-ai` | "Add an AI skill that triages new tickets into a priority." |
+| REST/auth surface tuning | `objectstack-api` | "Restrict the ticket API to read-only for non-members." |
+| Translations | `objectstack-i18n` | "Add a zh-CN translation bundle for the ticket object and app navigation." |
+
+Two habits keep this reliable as the app grows:
+
+- **The gate applies to every domain.** Flows, dashboards, permissions, and
+ translations all go through the same `npm run validate` — the agent should run
+ it after each change, exactly as `AGENTS.md` instructs.
+- **Keep the skills current.** After upgrading `@objectstack/spec`, re-run
+ `npx skills add objectstack-ai/framework/skills --all` so the agent authors
+ against the schemas you actually run. The full catalog is documented in the
+ [AI Skills Reference](/docs/ai/skills-reference).
+
## 7. Your app is natively AI-operable (MCP)
Here's the payoff that a hand-built CRUD app doesn't give you for free: because
diff --git a/content/docs/getting-started/cli.mdx b/content/docs/getting-started/cli.mdx
index aa0fe3cc4a..da12e6dfa2 100644
--- a/content/docs/getting-started/cli.mdx
+++ b/content/docs/getting-started/cli.mdx
@@ -42,7 +42,7 @@ os generate flow onboarding # Add an automation flow
os dev --ui
```
-Open [http://localhost:3000/_console/](http://localhost:3000/_console/) — you'll see the Console UI with a data browser, metadata explorer, and API documentation.
+Open [http://localhost:3000/_console/](http://localhost:3000/_console/) — you'll see the Console UI with a data browser, metadata explorer, and API documentation. Sign in with the seeded dev admin (`admin@objectos.ai` / `admin123`) — `os dev` provisions it automatically on an empty database. The boot banner also prints the app's MCP endpoint (`/api/v1/mcp`) so a coding agent can connect to the running app.
### Validate & Build
@@ -138,8 +138,14 @@ os dev --database file:./data/test.db --auth-secret $(openssl rand -hex 32)
| `-p, --port ` | `OS_PORT` / `PORT` | Listen port (default `3000`). In dev a busy port auto-hops to the next free one; the banner shows the actual port. |
| `--ui` | — | Force Console UI on (already on by default in dev) |
| `--compile` | — | Force compiling `objectstack.config.ts` → `dist/objectstack.json` before starting (auto when the artifact is missing; ignored with `--artifact`) |
+| `--fresh` | — | Ephemeral `OS_HOME` in the OS tempdir (clean DB, uploads, storage), auto-deleted on exit; implies `--seed-admin` |
+| `--seed-admin` / `--no-seed-admin` | — | Seed a dev admin (`admin@objectos.ai` / `admin123`) on an empty DB — default on; override with `--admin-email` / `--admin-password` |
| `-v, --verbose` | — | Verbose output |
+By default `os dev` keeps your data between restarts in a project-local SQLite
+file at `.objectstack/data/dev.db` (created on first run). Pass `--database`,
+set `OS_DATABASE_URL`, or use `--fresh` for a throwaway run.
+
With a file-backed SQLite database, dev also provisions a sibling
`.telemetry.` file registered as the `telemetry` datasource —
lifecycle-classed system data (activity streams, job runs, notifications,
@@ -194,7 +200,8 @@ only gate the **automatic** registration of optional plugins.
The `auth` tier requires `OS_AUTH_SECRET` to be set; otherwise `AuthPlugin`
is skipped with a yellow warning and the `/api/v1/auth/*` endpoints will
-return 404. To take full control, set `tiers` on the stack config:
+return 404. (In `--dev` mode the CLI falls back to an insecure local secret so
+login works out of the box.) To take full control, set `tiers` on the stack config:
```typescript
import { defineStack } from '@objectstack/spec';
@@ -250,9 +257,8 @@ exploration, package management, and runtime metadata diagnostics.
└─────────────────────────────────────────┘
```
-In this framework repo the prebuilt console bundle is served at `/_console/`.
-For source-level Console UI work, run the sibling `../objectui` Vite server and
-point it at a backend on port 3000.
+The prebuilt Console bundle ships with the framework packages and is served at
+`/_console/` — no separate frontend install or build step is needed.
### Production
@@ -260,7 +266,10 @@ point it at a backend on port 3000.
Boots a production server **directly from a compiled `objectstack.json` artifact** — no
`objectstack.config.ts` required. This is the canonical "deploy a built ObjectStack app"
-command: hand a server one JSON file (or a URL pointing at one) and it runs.
+command: hand a server one JSON file (or a URL pointing at one) and it runs. When the cwd
+*does* contain an `objectstack.config.ts` and no artifact exists yet, `os start`
+auto-compiles it first; with no config and no artifact at all it boots an **empty kernel**
+with the Console + marketplace, so you can install apps interactively.
```bash
# Quick start — load ./dist/objectstack.json with sqlite at file:/data/objectstack.db
@@ -297,7 +306,8 @@ os start
| `-d, --database ` | `OS_DATABASE_URL` | `file:…` / `libsql://` / `postgres://` / `mongodb://` / `memory://` |
| `--database-driver ` | `OS_DATABASE_DRIVER` | Force `sqlite` \| `turso` \| `postgres` \| `mongodb` \| `memory` when the URL is ambiguous |
| `--database-auth-token ` | `OS_DATABASE_AUTH_TOKEN` | Auth token for libsql/Turso |
-| `--auth-secret ` | `OS_AUTH_SECRET` | Secret for `@objectstack/plugin-auth`; without it `/api/v1/auth/*` is skipped (server still runs) |
+| `--auth-secret ` | `OS_AUTH_SECRET` / `AUTH_SECRET` | Secret for `@objectstack/plugin-auth`. If neither the flag nor the env var is set, `os start` **auto-generates one** and persists it at `/auth-secret` |
+| `--home ` | `OS_HOME` | Home directory for persistent state (default `/.objectstack` when an `objectstack.config.ts` is present, otherwise `~/.objectstack`) |
| `--environment-id ` | `OS_ENVIRONMENT_ID` | Environment identifier (default `env_local`) |
| `-p, --port ` | `OS_PORT` / `PORT` | Listen port (default `3000`). **Production fails loudly if the port is busy** — see note below. |
| `--ui` / `--no-ui` | — | Mount the Console portal at `/_console/`. Enabled by default (so you can install marketplace apps); pass `--no-ui` to disable it. |
@@ -310,7 +320,7 @@ os start
> (CORS). **Pin the port explicitly** (`OS_PORT=8080 os start`) and keep
> `OS_AUTH_URL` / `OS_TRUSTED_ORIGINS` in sync when you change it.
-**Resolution priority (artifact):** `--artifact` > `OS_ARTIFACT_PATH` > `/dist/objectstack.json`.
+**Resolution priority (artifact):** `--artifact` > `OS_ARTIFACT_PATH` > `/dist/objectstack.json` > `/dist/objectstack.json` > auto-compile from `objectstack.config.ts` (when present) > empty kernel.
**Resolution priority (database):** `--database` > `OS_DATABASE_URL` > `DATABASE_URL` (legacy) > `file:/data/objectstack.db`.
**What it boots:**
@@ -320,7 +330,11 @@ os start
- Runs standalone boot mode with one active environment.
**Authentication:**
-The `auth` capability is auto-loaded only when both (1) the artifact declares `requires: [..., 'auth']` **and** (2) a secret is provided via `--auth-secret` or `OS_AUTH_SECRET`. Without a secret, `AuthPlugin` is **silently skipped with a warning** — the server still boots and serves data/REST routes, only `/api/v1/auth/*` (login/register) is omitted. This is intentional: `os start` is happy to run an unauthenticated, internal-network deployment.
+`os start` always resolves an auth secret — `--auth-secret` > `OS_AUTH_SECRET` /
+`AUTH_SECRET` env > a secret **auto-generated and persisted** at `/auth-secret`
+on first run — so `/api/v1/auth/*` (login/register) and the Console's login flow work
+out of the box, without any manual secret provisioning. Set the env var (or flag)
+explicitly when you deploy across multiple nodes or want to rotate the secret.
**`os start` vs `os serve`:** `os serve` boots from `objectstack.config.ts` (TypeScript source).
@@ -335,6 +349,7 @@ shape they accept. See [Source vs Artifact](#source-vs-artifact) below.
| Command | Description |
|---------|-------------|
| `os compile [config]` | Compile configuration to a JSON artifact (`dist/objectstack.json`) |
+| `os build [config]` | Alias for `os compile` (scaffolded projects wire it as `npm run build`) |
| `os validate [config]` | Validate schema, CEL predicates, and widget bindings — the same gates as `os compile`/`os build`, no artifact emitted |
| `os info [config]` | Display metadata summary (objects, fields, apps, agents, etc.) |
@@ -358,17 +373,24 @@ os compile --json # JSON output for CI pipelines
────────────────────────────────────────
→ Loading configuration...
Config: objectstack.config.ts
- Load time: 104ms
+ Load time: 57ms
+ → Normalizing stack definition...
+ → Lowering inline handlers...
→ Validating protocol compliance...
+ → Validating expressions (ADR-0032)...
+ → Checking dashboard widget bindings (ADR-0021)...
+ → Checking SDUI styling (ADR-0065)...
+ → Checking security posture (ADR-0090 D7)...
+ → Collecting package docs (ADR-0046)...
→ Writing artifact...
- ✓ Build complete (312ms)
+ ✓ Build complete (74ms)
- Data: 10 Objects 217 Fields
- UI: 1 Apps 3 Dashboards 8 Reports 10 Actions
- Logic: 5 Flows 5 Agents 2 APIs
+ Data: 2 Objects 6 Fields
+ UI: 1 Views 1 Actions
+ Runtime: 3 plugins
- Artifact: dist/objectstack.json (48.2 KB)
+ Artifact: dist/objectstack.json (7.6 KB)
```
The resulting `dist/objectstack.json` is a **portable, self-describing deployment unit** —
@@ -434,21 +456,21 @@ os info --json # JSON output for tooling
◆ Info
────────────────────────────────────────
- Enterprise CRM v3.0.0
- com.example.crm
- Namespace: crm
- Type: app
+ My App v0.1.0
+ my-app
+ Minimal ObjectStack environment — a clean slate for building.
+ Namespace: my_app
+ Type: app
- Data: 10 Objects 217 Fields
- UI: 1 Apps 3 Dashboards 8 Reports 10 Actions
- Logic: 5 Flows 5 Agents 2 APIs
+ Data: 2 Objects 6 Fields
+ UI: 1 Views 1 Actions
+ Runtime: 3 plugins
Objects:
- account (16 fields, user) — Account
- contact (24 fields, user) — Contact
- ...
+ my_app_note (2 fields, user) — Note
+ my_app_ticket (4 fields, user) — Ticket
- Loaded in 90ms
+ Loaded in 59ms
```
### Schema migrations
@@ -552,9 +574,21 @@ os create example my-app # Create examples/my-app
| Command | Description |
|---------|-------------|
+| `os lint [config]` | Check metadata for style and convention issues (beyond `validate`'s hard gates) |
| `os test [files]` | Run Quality Protocol test scenarios against a running server |
| `os doctor` | Check development environment health |
+#### `os lint`
+
+Style and convention checks on top of `os validate` — naming, labels, translation coverage — with a 0-100 quality score:
+
+```bash
+os lint # Style / convention checks
+os lint --score # Append a 0-100 metadata quality score (letter-graded)
+os lint --fix # Show what would be fixed (dry-run)
+os lint --json # JSON output for CI
+```
+
#### `os test`
Runs Quality Protocol test scenarios (JSON-based BDD) against a running ObjectStack server.
diff --git a/content/docs/getting-started/common-patterns.mdx b/content/docs/getting-started/common-patterns.mdx
index fe8cefe8e0..91f082b466 100644
--- a/content/docs/getting-started/common-patterns.mdx
+++ b/content/docs/getting-started/common-patterns.mdx
@@ -1,6 +1,6 @@
---
title: Common Patterns
-description: Top 10 patterns for building applications with ObjectStack — CRUD, search, auth, realtime, and more
+description: Top 10 patterns for building applications with ObjectStack — CRUD, views, flows, agents, security, and more
---
# Common Patterns Guide
@@ -8,7 +8,7 @@ description: Top 10 patterns for building applications with ObjectStack — CRUD
This guide covers the most common patterns you will use when building applications with ObjectStack. Each pattern includes a complete, copy-pasteable example.
-**Import:** `import { defineStack, defineView, defineApp, defineFlow, defineAgent } from '@objectstack/spec'`
+**Import:** `import { defineStack, defineView, defineApp, defineFlow, defineAgent, definePermissionSet } from '@objectstack/spec'`
@@ -46,7 +46,8 @@ export default defineStack({
{ label: 'Complete', value: 'complete' },
{ label: 'Archived', value: 'archived' }
]},
- owner: { label: 'Owner', type: 'lookup', reference: 'user' },
+ // Person references target the platform user object `sys_user`
+ owner: { label: 'Owner', type: 'lookup', reference: 'sys_user' },
due_date: { label: 'Due Date', type: 'date' },
budget: { label: 'Budget', type: 'currency', currencyConfig: { precision: 2, defaultCurrency: 'USD' } },
}
@@ -73,7 +74,8 @@ export default defineStack({
{ label: 'Complete', value: 'complete' },
{ label: 'Archived', value: 'archived' }
]},
- owner: { label: 'Owner', type: 'lookup', reference: 'user' },
+ // Person references target the platform user object `sys_user`
+ owner: { label: 'Owner', type: 'lookup', reference: 'sys_user' },
due_date: { label: 'Due Date', type: 'date' },
budget: { label: 'Budget', type: 'currency', currencyConfig: { precision: 2, defaultCurrency: 'USD' } },
},
@@ -134,7 +136,8 @@ Create a parent-child relationship between a master and its detail records. Note
product: { label: 'Product', type: 'lookup', reference: 'product' },
quantity: { label: 'Qty', type: 'number', min: 1, required: true },
unit_price: { label: 'Unit Price', type: 'currency' },
- line_total: { label: 'Line Total', type: 'formula', expression: 'quantity * unit_price' },
+ // Formula expressions are CEL — reference fields through `record.`
+ line_total: { label: 'Line Total', type: 'formula', expression: 'record.quantity * record.unit_price', returnType: 'number' },
}
}
]
@@ -236,7 +239,10 @@ export const crm = defineApp({
## 6. Automated Flow (Record-Triggered)
-Create an automation that fires when a record is created or updated.
+Create an automation that fires when a record changes. The **start node's `config`
+binds the trigger**: `objectName` plus one lifecycle event in `triggerType`
+(`record-after-create`, `record-after-update`, `record-after-delete`, or the
+`record-before-*` forms) — without it the flow never fires.
```typescript
import { defineFlow } from '@objectstack/spec';
@@ -245,15 +251,23 @@ export const assignmentNotification = defineFlow({
name: 'task_assignment_notification',
label: 'Task Assignment Notification',
type: 'record_change',
+ status: 'active', // arm the trigger deliberately (default 'draft' is ambiguous)
nodes: [
- { id: 'start', type: 'start', label: 'Start' },
+ {
+ id: 'start',
+ type: 'start',
+ label: 'Start',
+ // Trigger binding: which object + which lifecycle event launches this flow
+ config: { objectName: 'task', triggerType: 'record-after-update' }
+ },
{
id: 'notify',
type: 'notify',
label: 'Notify Assignee',
config: {
- // String fields use single-brace {…} templates, not {{…}}
- to: '{record.assigned_to.email}',
+ // String fields use single-brace {…} templates, not {{…}}.
+ // `to` takes recipient USER IDs — a lookup value interpolates to the id.
+ to: '{record.assigned_to}',
subject: 'Task Assigned: {record.title}',
body: 'You have been assigned to task "{record.title}".'
}
@@ -289,8 +303,8 @@ Define a multi-step approval flow for records.
{ label: 'Approved', value: 'approved' },
{ label: 'Rejected', value: 'rejected' }
]},
- submitted_by: { label: 'Submitted By', type: 'lookup', reference: 'user' },
- approved_by: { label: 'Approved By', type: 'lookup', reference: 'user' },
+ submitted_by: { label: 'Submitted By', type: 'lookup', reference: 'sys_user' },
+ approved_by: { label: 'Approved By', type: 'lookup', reference: 'sys_user' },
},
enable: {
trackHistory: true,
@@ -301,11 +315,40 @@ Define a multi-step approval flow for records.
name: 'expense_approval',
label: 'Expense Approval',
type: 'record_change',
+ status: 'active',
nodes: [
- { id: 'start', type: 'start', label: 'Start' },
+ {
+ id: 'start',
+ type: 'start',
+ label: 'Start',
+ config: {
+ objectName: 'expense_report',
+ triggerType: 'record-after-update',
+ // Start condition (bare CEL): launch only on the draft → submitted transition
+ condition: "record.status == 'submitted' && previous.status != 'submitted'"
+ }
+ },
{ id: 'check_amount', type: 'decision', label: 'Check Amount' },
- { id: 'auto_approve', type: 'update_record', label: 'Auto Approve' },
- { id: 'request_approval', type: 'notify', label: 'Request Approval' },
+ {
+ id: 'auto_approve',
+ type: 'update_record',
+ label: 'Auto Approve',
+ config: {
+ objectName: 'expense_report',
+ filter: { id: '{record.id}' },
+ fields: { status: 'approved' }
+ }
+ },
+ {
+ id: 'request_approval',
+ type: 'notify',
+ label: 'Request Approval',
+ config: {
+ to: '{record.submitted_by}',
+ subject: 'Expense approval needed: {record.title}',
+ body: 'Expense "{record.title}" needs manual approval.'
+ }
+ },
{ id: 'end', type: 'end', label: 'End' }
],
edges: [
@@ -388,10 +431,15 @@ const page2 = { ...page1, offset: 25 };
const page3 = { ...page1, offset: 50 };
```
-### Cursor-Based (Scalable)
+### Keyset (Scalable)
+
+Instead of skipping N rows, filter past the last row you already received —
+stable under concurrent writes and cheap at any depth. (The query schema also
+reserves a `cursor` property, but it is not executed by the engine — use the
+`where` + `orderBy` + `limit` form below.)
```typescript
-// First page — no cursor yet
+// First page
const firstPage = {
object: 'activity',
fields: ['id', 'type', 'description', 'created_at'],
@@ -399,10 +447,11 @@ const firstPage = {
limit: 50
};
-// Next page — pass the opaque cursor token returned with the previous response
+// Next page — filter past the last row of the previous page
+const lastRow = previousPage[previousPage.length - 1];
const nextPage = {
...firstPage,
- cursor: { /* opaque cursor token from the previous response */ }
+ where: { created_at: { $lt: lastRow.created_at } }
};
```
diff --git a/content/docs/getting-started/quick-reference.mdx b/content/docs/getting-started/quick-reference.mdx
index b47fc9fc5b..5b1ae711a2 100644
--- a/content/docs/getting-started/quick-reference.mdx
+++ b/content/docs/getting-started/quick-reference.mdx
@@ -12,7 +12,7 @@ Fast lookup for the ObjectStack protocols organized by category.
Click on any protocol name to view its complete API reference.
-## Data Protocol (18 schemas)
+## Data Protocol (17 schemas)
Core business logic and data modeling schemas.
@@ -20,24 +20,23 @@ Core business logic and data modeling schemas.
|:---------|:-----------|:------------|:--------|
| **[Field](/docs/references/data/field)** | `field.zod.ts` | Field, FieldType, SelectOption | Field types for data modeling |
| **[Object](/docs/references/data/object)** | `object.zod.ts` | Object, ObjectCapabilities | Object/table definitions |
-| **[Query](/docs/references/data/query)** | `query.zod.ts` | Query, QueryOptions | Query AST with joins, aggregations |
+| **[Query](/docs/references/data/query)** | `query.zod.ts` | Query, QueryAST | Query AST with joins, aggregations |
| **[Filter](/docs/references/data/filter)** | `filter.zod.ts` | QueryFilter, FilterCondition | Advanced filtering operators |
| **[Validation](/docs/references/data/validation)** | `validation.zod.ts` | ValidationRule | Business validation rules |
-| **[Dataset](/docs/references/ui/dataset)** | `dataset.zod.ts` | Dataset, DatasetMode | Reusable dataset definitions |
-| **[Datasource](/docs/references/data/datasource)** | `datasource.zod.ts` | Datasource, DatasourceType | Database connection configs |
+| **[Datasource](/docs/references/data/datasource)** | `datasource.zod.ts` | Datasource, DatasourceCapabilities | Database connection configs |
| **[Analytics](/docs/references/data/analytics)** | `analytics.zod.ts` | Analytics | Data analytics and aggregation |
| **[Mapping](/docs/references/data/mapping)** | `mapping.zod.ts` | FieldMapping | Field transformation mappings |
| **[Hook](/docs/references/data/hook)** | `hook.zod.ts` | Hook, HookEvent | Lifecycle event hooks |
| **[Data Engine](/docs/references/data/data-engine)** | `data-engine.zod.ts` | DataEngine | Data engine configuration |
| **[Driver](/docs/references/data/driver)** | `driver.zod.ts` | Driver, DriverCapabilities | Database driver interface |
-| **[SQL Driver](/docs/references/data/driver-sql)** | `driver-sql.zod.ts` | SQLDriver | SQL-specific driver |
-| **[NoSQL Driver](/docs/references/data/driver-nosql)** | `driver-nosql.zod.ts` | NoSQLDriver | NoSQL-specific driver |
+| **[SQL Driver](/docs/references/data/driver-sql)** | `driver-sql.zod.ts` | SQLDriverConfig, SQLDialect | SQL-specific driver |
+| **[NoSQL Driver](/docs/references/data/driver-nosql)** | `driver-nosql.zod.ts` | NoSQLDriverConfig | NoSQL-specific driver |
| **[Document](/docs/references/data/document)** | `document.zod.ts` | Document | Document-oriented data |
| **[External Lookup](/docs/references/data/external-lookup)** | `external-lookup.zod.ts` | ExternalLookup | External data lookups |
| **Postgres Driver** | `driver/postgres.zod.ts` | PostgresConfig | PostgreSQL configuration |
| **Mongo Driver** | `driver/mongo.zod.ts` | MongoConfig | MongoDB configuration |
-## UI Protocol (10 schemas)
+## UI Protocol (11 schemas)
Presentation layer - views, forms, dashboards, and themes.
@@ -47,6 +46,7 @@ Presentation layer - views, forms, dashboards, and themes.
| **[Page](/docs/references/ui/page)** | `page.zod.ts` | Page, PageComponent | FlexiPage layouts |
| **[App](/docs/references/ui/app)** | `app.zod.ts` | App, NavigationItem | Application navigation structure |
| **[Dashboard](/docs/references/ui/dashboard)** | `dashboard.zod.ts` | Dashboard, DashboardWidget | Dashboard layouts and widgets |
+| **[Dataset](/docs/references/ui/dataset)** | `dataset.zod.ts` | Dataset, DatasetDimension, DatasetMeasure | Semantic-layer datasets for dashboards (ADR-0021) |
| **[Report](/docs/references/ui/report)** | `report.zod.ts` | Report, ReportType | Report definitions |
| **[Action](/docs/references/ui/action)** | `action.zod.ts` | Action, ActionType | UI button actions |
| **[Component](/docs/references/ui/component)** | `component.zod.ts` | PageComponent variants | Reusable UI components |
@@ -62,60 +62,65 @@ Plugin architecture, manifests, and kernel runtime.
|:---------|:-----------|:------------|:--------|
| **[Manifest](/docs/references/kernel/manifest)** | `manifest.zod.ts` | Manifest | Package manifest (objectstack.config.ts) |
| **[Context](/docs/references/kernel/context)** | `context.zod.ts` | KernelContext | Runtime execution context |
-| **[Plugin](/docs/references/kernel/plugin)** | `plugin.zod.ts` | Plugin, PluginHook | Plugin system interface |
+| **[Plugin](/docs/references/kernel/plugin)** | `plugin.zod.ts` | Plugin, PluginLifecycle | Plugin system interface |
| **[Plugin Capability](/docs/references/kernel/plugin-capability)** | `plugin-capability.zod.ts` | PluginCapability | Plugin capability declarations |
-| **[Plugin Lifecycle](/docs/references/kernel/plugin-lifecycle-events)** | `plugin-lifecycle-events.zod.ts` | PluginLifecycleEvents | Plugin lifecycle events |
-| **[Plugin Lifecycle Advanced](/docs/references/kernel/plugin-lifecycle-advanced)** | `plugin-lifecycle-advanced.zod.ts` | PluginLifecycleAdvanced | Advanced lifecycle hooks |
-| **[Plugin Loading](/docs/references/kernel/plugin-loading)** | `plugin-loading.zod.ts` | PluginLoading | Plugin loading and init |
-| **[Plugin Security](/docs/references/kernel/plugin-security-advanced)** | `plugin-security-advanced.zod.ts` | PluginSecurityAdvanced | Plugin sandboxing |
-| **[Plugin Structure](/docs/references/kernel/plugin-structure)** | `plugin-structure.zod.ts` | PluginStructure | Plugin file conventions |
-| **[Plugin Validator](/docs/references/kernel/plugin-validator)** | `plugin-validator.zod.ts` | PluginValidator | Plugin validation |
-| **[Plugin Versioning](/docs/references/kernel/plugin-versioning)** | `plugin-versioning.zod.ts` | PluginVersioning | Version compatibility |
-| **[Service Registry](/docs/references/kernel/service-registry)** | `service-registry.zod.ts` | ServiceRegistry | Service discovery |
-| **[Startup Orchestrator](/docs/references/kernel/startup-orchestrator)** | `startup-orchestrator.zod.ts` | StartupOrchestrator | System startup |
-| **[Events](/docs/kernel/events)** | `events.zod.ts` | Event, EventBus | System event bus |
+| **[Plugin Lifecycle](/docs/references/kernel/plugin-lifecycle-events)** | `plugin-lifecycle-events.zod.ts` | PluginEventBase, EventPhase | Plugin lifecycle events |
+| **[Plugin Lifecycle Advanced](/docs/references/kernel/plugin-lifecycle-advanced)** | `plugin-lifecycle-advanced.zod.ts` | AdvancedPluginLifecycleConfig, PluginHealthCheck | Advanced lifecycle hooks |
+| **[Plugin Loading](/docs/references/kernel/plugin-loading)** | `plugin-loading.zod.ts` | PluginLoadingConfig | Plugin loading and init |
+| **[Plugin Security](/docs/references/kernel/plugin-security-advanced)** | `plugin-security-advanced.zod.ts` | KernelSecurityPolicy, PluginPermission | Plugin sandboxing |
+| **[Plugin Structure](/docs/references/kernel/plugin-structure)** | `plugin-structure.zod.ts` | OpsPluginStructure | Plugin file conventions |
+| **[Plugin Validator](/docs/references/kernel/plugin-validator)** | `plugin-validator.zod.ts` | ValidationResult, PluginMetadata | Plugin validation |
+| **[Plugin Versioning](/docs/references/kernel/plugin-versioning)** | `plugin-versioning.zod.ts` | PluginCompatibilityMatrix, DeprecationNotice | Version compatibility |
+| **[Service Registry](/docs/references/kernel/service-registry)** | `service-registry.zod.ts` | ServiceRegistryConfig, ServiceMetadata | Service discovery |
+| **[Startup Orchestrator](/docs/references/kernel/startup-orchestrator)** | `startup-orchestrator.zod.ts` | StartupOptions, StartupOrchestrationResult | System startup |
+| **[Events](/docs/kernel/events)** | `events.zod.ts` | Event, EventBusConfig | System event bus |
| **[Feature](/docs/references/kernel/feature)** | `feature.zod.ts` | FeatureFlag | Feature flags |
-| **[Metadata Loader](/docs/references/kernel/metadata-loader)** | `metadata-loader.zod.ts` | MetadataLoader | Metadata loading |
-| **[Package Registry](/docs/references/kernel/package-registry)** | `package-registry.zod.ts` | PackageRegistry | Package resolution |
+| **[Metadata Loader](/docs/references/kernel/metadata-loader)** | `metadata-loader.zod.ts` | MetadataLoaderContract | Metadata loading |
+| **[Package Registry](/docs/references/kernel/package-registry)** | `package-registry.zod.ts` | InstalledPackage, InstallPackageRequest | Package resolution |
-## System Protocol (22 schemas)
+## System Protocol (19 schemas)
Runtime environment, logging, jobs, caching, and observability.
| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
-| **[Audit](/docs/references/system/audit)** | `audit.zod.ts` | AuditLog, AuditEvent | Audit trail logging |
+| **[Audit](/docs/references/system/audit)** | `audit.zod.ts` | AuditEvent, AuditConfig | Audit trail logging |
| **[Auth Config](/docs/references/system/auth-config)** | `auth-config.zod.ts` | AuthConfig | Authentication configuration |
| **[Cache](/docs/references/system/cache)** | `cache.zod.ts` | CacheConfig | Caching layer |
-| **[Change Management](/docs/references/system/change-management)** | `change-management.zod.ts` | ChangeManagement | Change tracking |
+| **[Change Management](/docs/references/system/change-management)** | `change-management.zod.ts` | ChangeRequest, RollbackPlan | Change tracking |
| **[Collaboration](/docs/references/system/collaboration)** | `collaboration.zod.ts` | Collaboration | Real-time collab |
-| **Compliance** | `compliance.zod.ts` | Compliance | Regulatory controls |
| **[Encryption](/docs/references/system/encryption)** | `encryption.zod.ts` | Encryption | Encryption & keys |
-| **[HTTP Server](/docs/references/system/http-server)** | `http-server.zod.ts` | HTTPServer | HTTP server config |
+| **[HTTP Server](/docs/references/system/http-server)** | `http-server.zod.ts` | HttpServerConfig, MiddlewareConfig | HTTP server config |
| **[Job](/docs/references/system/job)** | `job.zod.ts` | Job, JobSchedule | Background job queue |
| **[Logging](/docs/references/system/logging)** | `logging.zod.ts` | LoggingConfig | Structured logging |
-| **Masking** | `masking.zod.ts` | Masking | Data masking |
-| **[Message Queue](/docs/references/system/message-queue)** | `message-queue.zod.ts` | MessageQueue | Message queuing |
-| **[Metadata Persistence](/docs/references/system/metadata-persistence)** | `metadata-persistence.zod.ts` | MetadataPersistence | Metadata storage |
+| **[Message Queue](/docs/references/system/message-queue)** | `message-queue.zod.ts` | MessageQueueConfig, TopicConfig | Message queuing |
+| **[Metadata Persistence](/docs/references/system/metadata-persistence)** | `metadata-persistence.zod.ts` | MetadataHistoryRecord, MetadataDiffResult | Metadata storage |
| **[Metrics](/docs/references/system/metrics)** | `metrics.zod.ts` | Metrics | Application metrics |
| **[Migration](/docs/references/system/migration)** | `migration.zod.ts` | Migration | Schema migration |
| **[Notification](/docs/references/system/notification)** | `notification.zod.ts` | Notification | Notifications |
-| **[Object Storage](/docs/references/system/object-storage)** | `object-storage.zod.ts` | ObjectStorage | Object storage |
-| **[Search Engine](/docs/references/system/search-engine)** | `search-engine.zod.ts` | SearchEngine | Full-text search |
-| **[Service Registry](/docs/references/kernel/service-registry)** | `service-registry.zod.ts` | ServiceRegistry | System services |
+| **[Object Storage](/docs/references/system/object-storage)** | `object-storage.zod.ts` | BucketConfig, ObjectMetadata | Object storage |
+| **[Search Engine](/docs/references/system/search-engine)** | `search-engine.zod.ts` | SearchConfig, SearchIndexConfig | Full-text search |
| **[Tracing](/docs/references/system/tracing)** | `tracing.zod.ts` | Tracing | Distributed tracing |
| **[Translation](/docs/references/system/translation)** | `translation.zod.ts` | Translation | i18n support |
| **[Worker](/docs/references/system/worker)** | `worker.zod.ts` | Worker | Background workers |
-## AI Protocol (3 schemas)
+## AI Protocol (11 schemas)
-AI/ML capabilities - agents, models, RAG, and cost tracking.
+AI/ML capabilities - agents, skills, tools, MCP exposure, RAG, and cost tracking.
| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
| **[Agent](/docs/references/ai/agent)** | `agent.zod.ts` | Agent, AITool | AI agent definitions |
+| **[Skill](/docs/references/ai/skill)** | `skill.zod.ts` | Skill, SkillTriggerCondition | Reusable agent skills |
+| **[Tool](/docs/references/ai/tool)** | `tool.zod.ts` | Tool, ToolCategory | Agent tool definitions |
+| **[MCP](/docs/references/ai/mcp)** | `mcp.zod.ts` | MCPServerRef, MCPToolBinding | MCP server exposure and tool bindings |
| **[Model Registry](/docs/references/ai/model-registry)** | `model-registry.zod.ts` | ModelRegistry, ModelProvider | LLM model management |
| **[Conversation](/docs/references/ai/conversation)** | `conversation.zod.ts` | ConversationSession | Conversation management |
+| **[Embedding](/docs/references/ai/embedding)** | `embedding.zod.ts` | EmbeddingModel, VectorStore | Embedding models and vector stores |
+| **[Knowledge Source](/docs/references/ai/knowledge-source)** | `knowledge-source.zod.ts` | KnowledgeSource, KnowledgeRefreshPolicy | RAG ingestion sources |
+| **[Knowledge Document](/docs/references/ai/knowledge-document)** | `knowledge-document.zod.ts` | KnowledgeDocument, KnowledgeChunk | RAG documents and chunks |
+| **[Usage](/docs/references/ai/usage)** | `usage.zod.ts` | AIUsageRecord, TokenUsage | AI usage and cost tracking |
+| **[Solution Blueprint](/docs/references/ai/solution-blueprint)** | `solution-blueprint.zod.ts` | BlueprintObject, BlueprintApp | Blueprint format for AI app generation |
## API Protocol (19 schemas)
@@ -123,20 +128,20 @@ REST/GraphQL endpoints, real-time subscriptions, and discovery.
| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
-| **[Contract](/docs/references/api/contract)** | `contract.zod.ts` | APIContract | API contract definitions |
-| **[Endpoint](/docs/references/api/endpoint)** | `endpoint.zod.ts` | Endpoint, EndpointMethod | REST endpoint configuration |
+| **[Contract](/docs/references/api/contract)** | `contract.zod.ts` | BaseResponse, BulkRequest | API contract definitions |
+| **[Endpoint](/docs/references/api/endpoint)** | `endpoint.zod.ts` | ApiEndpoint, ApiMapping | REST endpoint configuration |
| **[Router](/docs/references/api/router)** | `router.zod.ts` | Router, Route | API routing rules |
| **[OData](/docs/references/api/odata)** | `odata.zod.ts` | ODataQuery | OData protocol support |
-| **[GraphQL](/docs/references/api/graphql)** | `graphql.zod.ts` | GraphQLSchema | GraphQL API config |
-| **[Realtime](/docs/references/api/realtime)** | `realtime.zod.ts` | Subscription, Channel | WebSocket subscriptions |
+| **[GraphQL](/docs/references/api/graphql)** | `graphql.zod.ts` | GraphQLConfig, FederationEntity | GraphQL API config |
+| **[Realtime](/docs/references/api/realtime)** | `realtime.zod.ts` | Subscription, RealtimeEvent | WebSocket subscriptions |
| **[WebSocket](/docs/references/api/websocket)** | `websocket.zod.ts` | WebSocketConfig | WebSocket protocol |
-| **[Discovery](/docs/references/api/discovery)** | `discovery.zod.ts` | ServiceDiscovery | API discovery and metadata |
-| **[Batch](/docs/references/api/batch)** | `batch.zod.ts` | BatchRequest | Batch API processing |
-| **[HTTP Cache](/docs/references/api/http-cache)** | `http-cache.zod.ts` | CacheStrategy | HTTP caching |
+| **[Discovery](/docs/references/api/discovery)** | `discovery.zod.ts` | Discovery, ServiceInfo | API discovery and metadata |
+| **[Batch](/docs/references/api/batch)** | `batch.zod.ts` | BatchConfig, CrossObjectBatchRequest | Batch API processing |
+| **[HTTP Cache](/docs/references/api/http-cache)** | `http-cache.zod.ts` | CacheControl, ETag | HTTP caching |
| **[Errors](/docs/references/api/errors)** | `errors.zod.ts` | ErrorResponse | Error responses |
-| **[Protocol](/docs/references/api/protocol)** | `protocol.zod.ts` | ProtocolDefinition | Protocol definitions |
-| **[REST Server](/docs/references/api/rest-server)** | `rest-server.zod.ts` | RESTServer | REST server config |
-| **[Auth](/docs/references/api/auth)** | `auth.zod.ts` | Auth | API authentication |
+| **[Protocol](/docs/references/api/protocol)** | `protocol.zod.ts` | BatchDataRequest, CheckPermissionRequest | Console/client request-response contracts |
+| **[REST Server](/docs/references/api/rest-server)** | `rest-server.zod.ts` | RestApiConfig, CrudEndpointsConfig | REST server config |
+| **[Auth](/docs/references/api/auth)** | `auth.zod.ts` | LoginRequest, Session | API authentication |
| **[Analytics](/docs/references/api/analytics)** | `analytics.zod.ts` | Analytics | API usage analytics |
| **[Documentation](/docs/references/api/documentation)** | `documentation.zod.ts` | Documentation | API docs generation |
| **[Metadata](/docs/references/api/metadata)** | `metadata.zod.ts` | Metadata | API metadata endpoints |
@@ -152,10 +157,10 @@ Flows, state machines, approvals, and integrations.
| **[Flow](/docs/references/automation/flow)** | `flow.zod.ts` | Flow, FlowNode | Visual workflow builder |
| **[Approval](/docs/references/automation/approval)** | `approval.zod.ts` | ApprovalNodeConfig | Flow approval-node config |
| **[State Machine](/docs/references/automation/state-machine)** | `state-machine.zod.ts` | StateMachine | State machine definitions |
-| **[Webhook](/docs/references/automation/webhook)** | `webhook.zod.ts` | Webhook, WebhookEvent | Outbound webhooks |
+| **[Webhook](/docs/references/automation/webhook)** | `webhook.zod.ts` | Webhook, WebhookReceiver | Outbound webhooks |
| **[ETL](/docs/references/automation/etl)** | `etl.zod.ts` | ETLPipeline | Data transformation pipelines |
| **[Trigger Registry](/docs/references/automation/trigger-registry)** | `trigger-registry.zod.ts` | TriggerRegistry | Event-driven triggers |
-| **[Sync](/docs/references/automation/sync)** | `sync.zod.ts` | SyncConfig | Bi-directional data sync |
+| **[Sync](/docs/references/automation/sync)** | `sync.zod.ts` | DataSyncConfig, SyncMode | Bi-directional data sync |
## Security Protocol (4 schemas)
@@ -179,15 +184,16 @@ User identity, organizations, and position management.
| **[Position](/docs/references/identity/position)** | `position.zod.ts` | Position | Permission-set distribution (岗位, ADR-0090) |
| **[SCIM](/docs/references/identity/scim)** | `scim.zod.ts` | SCIMUser, SCIMGroup | SCIM 2.0 provisioning |
-## Cloud Protocol (4 schemas)
+## Cloud Protocol (5 schemas)
-Marketplace, licensing, and multi-tenancy.
+Environments, marketplace, licensing, and multi-tenancy.
| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
-| **[Marketplace](/docs/references/cloud/marketplace)** | `marketplace.zod.ts` | Package, PackageVersion | Plugin marketplace |
-| **[Plugin Registry](/docs/references/kernel/plugin-registry)** | `plugin-registry.zod.ts` | PluginRegistry | Plugin versioning |
-| **[Plugin Security](/docs/references/cloud/plugin-security)** | `plugin-security.zod.ts` | PluginSecurity | Plugin security policies |
+| **[Environment](/docs/references/cloud/environment)** | `environment.zod.ts` | Environment, EnvironmentType | Deployment environments |
+| **[Marketplace](/docs/references/cloud/marketplace)** | `marketplace.zod.ts` | MarketplaceListing, PackageSubmission | Plugin marketplace |
+| **[Plugin Registry](/docs/references/kernel/plugin-registry)** | `plugin-registry.zod.ts` | PluginRegistryEntry, PluginVendor | Plugin registry entries and quality metrics |
+| **[Plugin Security](/docs/references/cloud/plugin-security)** | `plugin-security.zod.ts` | PluginSecurityProtocol, SBOM | Plugin security policies |
| **[Tenant](/docs/references/cloud/tenant)** | `tenant.zod.ts` | Tenant | Multi-tenancy isolation |
## Integration Protocol (7 schemas)
@@ -204,16 +210,17 @@ External system connectors and adapters.
| **[GitHub](/docs/references/integration/connector)** | `connector/github.zod.ts` | GitHubConnector | GitHub API integration |
| **[Vercel](/docs/references/integration/connector)** | `connector/vercel.zod.ts` | VercelConnector | Vercel deployment |
-## Shared Protocol (4 schemas)
+## Shared Protocol (5 schemas)
Common utilities used across all protocols.
| Protocol | Source File | Key Schemas | Purpose |
|:---------|:-----------|:------------|:--------|
-| **[HTTP](/docs/references/shared/http)** | `http.zod.ts` | HTTPRequest, HTTPResponse | HTTP utilities |
-| **[Identifiers](/docs/references/shared/identifiers)** | `identifiers.zod.ts` | ID formats | Standard ID patterns |
-| **Mapping** | `mapping.zod.ts` | MappingRule | Field mapping utilities |
-| **Connector Auth** | `connector-auth.zod.ts` | ConnectorAuth | Connector auth patterns |
+| **[Expression](/docs/references/shared/expression)** | `expression.zod.ts` | Expression, ExpressionInput | CEL expression values and inputs |
+| **[HTTP](/docs/references/shared/http)** | `http.zod.ts` | HttpRequest, HttpMethod, CorsConfig | HTTP utilities |
+| **[Identifiers](/docs/references/shared/identifiers)** | `identifiers.zod.ts` | SystemIdentifier, SnakeCaseIdentifier | Standard ID patterns |
+| **[Mapping](/docs/references/shared/mapping)** | `mapping.zod.ts` | FieldMapping, TransformType | Field mapping utilities |
+| **[Connector Auth](/docs/references/shared/connector-auth)** | `connector-auth.zod.ts` | ConnectorAuthConfig | Connector auth patterns |
## QA Protocol (1 schema)
diff --git a/content/docs/getting-started/validating-metadata.mdx b/content/docs/getting-started/validating-metadata.mdx
index a2fe8fbca9..aa7b8e26de 100644
--- a/content/docs/getting-started/validating-metadata.mdx
+++ b/content/docs/getting-started/validating-metadata.mdx
@@ -62,7 +62,44 @@ dangling one.
So `os validate` is the fast inner-loop check (no artifact); `os build` is what
you run when you need the deployable artifact. A config that passes `os validate`
-will not fail `os build` on schema/predicate/binding grounds.
+will not fail `os build` on schema/predicate/binding grounds. Both entry points
+also check SDUI styling (ADR-0065), and `os validate` additionally runs a set of
+view- and page-shape checks — list-view navigation modes (ADR-0053), view
+container shape, and JSX/React page sources (ADR-0080/0081) — that catch UI
+metadata which would otherwise be silently dropped.
+
+A clean run walks each gate and reports timing:
+
+```
+◆ Validate
+────────────────────────────────────────
+ → Loading configuration...
+ Config: /path/to/support-desk/objectstack.config.ts
+ Load time: 21ms
+ → Validating against ObjectStack Protocol...
+ → Validating expressions (ADR-0032)...
+ → Checking list-view navigation modes (ADR-0053)...
+ → Checking view container shape...
+ → Checking dashboard widget bindings (ADR-0021)...
+ → Checking SDUI styling (ADR-0065)...
+ → Checking JSX-source pages (ADR-0080)...
+ → Checking React-source pages (ADR-0081)...
+ → Checking React-source page props (ADR-0081)...
+ → Checking source-page styling (ADR-0065)...
+ → Checking capability references (ADR-0066)...
+ → Checking flow trigger wiring...
+ → Checking security posture (ADR-0090 D7)...
+
+ ✓ Validation passed (64ms)
+
+ Support Desk v0.1.0
+ Data: 1 Objects 6 Fields
+ UI: 1 Apps 1 Views 1 Actions
+```
+
+On failure the exit code is non-zero and the error is located and corrective —
+see [the gate in action](/docs/getting-started/build-with-claude-code#4-the-gate-os-validate-catches-ai-mistakes)
+for the bare-reference example verbatim.
`os lint` is a **separate** pass — style and convention checks (snake_case
@@ -79,8 +116,7 @@ npm run typecheck # tsc --noEmit — types against @objectstack/spec
```
**Rule of thumb: never report a metadata change as done until `npm run validate`
-passes.** In the example apps the equivalent is `pnpm --filter validate`
-(`pnpm verify` in `app-showcase`, which chains validate + typecheck + test).
+passes.**
### Checking a single expression
diff --git a/content/docs/getting-started/your-first-project.mdx b/content/docs/getting-started/your-first-project.mdx
index 6008a4a9e0..79a9cc8d31 100644
--- a/content/docs/getting-started/your-first-project.mdx
+++ b/content/docs/getting-started/your-first-project.mdx
@@ -240,6 +240,10 @@ npm run validate
bindings — the classes of mistakes that otherwise fail *silently* at runtime.
See [Validating Metadata](/docs/getting-started/validating-metadata).
+Beyond pass/fail, `npx os lint --score` grades the data model 0–100 against the
+platform's design conventions (relationship patterns, missing select options,
+roll-ups, name fields) — a quick health check as the model grows.
+
## 6. Build the deployable artifact
```bash
@@ -258,6 +262,26 @@ Database URL, auth secret, and environment identity stay *outside* the
artifact and are injected at boot via flags or `OS_*` environment variables —
which is exactly what makes it container-friendly.
+## 7. Hand the project to your agent
+
+You just did by hand what an agent does in seconds — and the scaffolder already
+prepared the project for that handoff: the **skills bundle** is installed (step
+1.3) and `AGENTS.md` routes each task to the right skill and enforces the
+validate gate. Open the project in Claude Code (or Cursor / Copilot) and
+describe the next feature instead of typing it:
+
+> Add a `status` filter to the note list view, a dashboard with a metric of
+> published notes, and a daily flow that archives notes older than 90 days.
+> Run `npm run validate` when done.
+
+Each of those lands in a different metadata domain (UI, dashboards,
+automation) — the agent loads the matching skill per task. The full loop, and a
+per-domain prompt catalog, is on
+[Build with Claude Code](/docs/getting-started/build-with-claude-code#beyond-the-first-app--one-skill-per-metadata-domain).
+If you upgrade `@objectstack/spec` later, re-run
+`npx skills add objectstack-ai/framework/skills --all` to keep the agent in
+sync with the schemas you run.
+
## Next steps