ObjectOS
Resources

Changelog & Versioning

How ObjectOS is versioned, what changes between releases, and what's supported.

Versioning policy

ObjectOS follows Semantic Versioning: MAJOR.MINOR.PATCH.

Version bumpWhat it meansWhat to do
Patch (14.7.0 → 14.7.1)Bug fixes, no behavior changeRoll forward, no app changes needed
Minor (14.6 → 14.7)New features, backward-compatibleRoll forward, optionally adopt new features
Major (13 → 14)Breaking changes documented in release notesRead the migration guide before upgrading

All @objectstack/* packages release together with a synchronized version number — they're tested as a matrix, not independently.

Compatibility matrix

ComponentCompatibility rule
ObjectOS image ↔ compiled artifactSame minor version. A 14.7.x image runs a 14.7.x artifact; a 14.7 artifact may use features unavailable in a 14.0 image. The protocol handshake (PROTOCOL_VERSION, 12.0+) rejects incompatible packages at install time.
ObjectOS ↔ CLISame minor version recommended. The CLI in npm i -g writes scaffolds pinned to its own version.
ObjectOS ↔ database driverDriver pinned by image build; verify Postgres ≥ 13 / MongoDB ≥ 5 / Turso (any current).
Node.js20 LTS or newer. 22 LTS recommended for new deployments.

Support windows

BranchStatusUntil
14.x (current)Active development; new features and fixesAt least 12 months after 15.0 ships
13.xSecurity fixes onlyEOL on 15.0 release
≤ 12.xUnsupportedAlready EOL

Critical security fixes are backported to the current and previous major. Everything else lands on main.

Release notes

Released ObjectOS versions and their CHANGELOG entries are published at:

Subscribe to releases on GitHub to get notified.

Recent highlights

16.0

@objectstack 16.0.0 converges the developer surface and makes declared metadata honest: one blessed name for the caller's org, real multi-approver governance, time-relative automations that actually fire, and a platform-wide sweep that turns silently-ignored metadata into loud errors at authoring time. Full notes: docs.objectstack.ai/docs/releases. What moved:

  • tenantId alias removed from hook/action ctx (16.0, breaking) — read the caller's org as ctx.user.organizationId / ctx.session.organizationId in every *.hook.ts / *.action.ts body (the value is unchanged; ctx.user is undefined for system writes). The driver-layer tenancy axis (ExecutionContext.tenantId) is a different concept and is untouched.
  • Approvals: quorum, per-group sign-off (会签), and a metadata-driven inbox — approval steps support M-of-N quorum (minApprovals) and one-approver-from-each-group steps, tallied against an open-time snapshot with OOO substitution; a single rejection still vetoes, and thresholds clamp so misconfiguration can never deadlock. Decisions carry file attachments, progress ("2 of 3 · finance pending") is computed server-side, and approve / reject / reassign / send-back / request-info / remind / recall / resubmit are declared type:'api' actions on sys_approval_request — the Console renders them through its generic action runtime instead of hand-written buttons.
  • Time-relative automations — a flow start node can declare timeRelative (offsetDays: [60, 30, 7] or withinDays); a daily sweep launches the flow once per matching record, so "remind me 60 days before the contract ends" finally just works — no more date-equality conditions that only fire on a lucky edit.
  • Filtered roll-upssummaryOperations.filter lets a parent total aggregate only the matching child rows, and re-aggregates when a child moves in or out of the predicate.
  • Strict dashboard widgets (16.0, breaking) — DashboardWidgetSchema is .strict(): an undeclared key (typo or removed inline-analytics key) is a parse error naming the key and pointing at the dataset shape (dataset + dimensions + values) instead of silently rendering nothing.
  • MCP: stdio gets an identity, agents get a linter — stdio auto-start moves to its own OS_MCP_STDIO_ENABLED switch (default off) and requires an OS_MCP_STDIO_API_KEY=osk_... principal, fail-closed, resolved through the same authorization chain as HTTP (RLS/FLS/tenant apply; no system bypass). A new validate_expression tool lets agents lint a formula against the real object schema before saving it.
  • Enforce-or-remove sweep (16.0, breaking) — declared-but-unenforced metadata is now loud: dead field/object/agent props are removed or tombstoned with guidance, hook events collapse 18 → 8, validation rules lose the never-evaluated 'delete' event, webhook undelete / api triggers are removed, and unknown requires capability tokens are rejected at authoring (the aiStudio / aiSeat aliases are gone — use kebab-case ai-studio / ai-seat).
  • Engine-owned system rows are read-only through the generic data API (ADR-0103) — jobs, notifications, approval-runtime rows, sharing rows, audit trails, secrets, and the like are locked to get/list, with a fail-closed guard rejecting user-context writes through /data. Third-party system objects that legitimately take user writes must declare userActions.
  • Date logic stops lyingrecord.due_date == today() now matches (temporal equality comparisons are rewritten to coerce the field operand), while date arithmetic in formulas (end - start + 1, today() + 30) becomes a build-time error pointing at daysBetween / daysFromNow / addDays / addMonths — those expressions always faulted to null at runtime anyway.
  • Bulk user import defaults to passwordPolicy: 'auto' — rows with a deliverable channel (real email + wired email service, or phone + SMS invite path) are invited; only unreachable rows get a one-time temporary password (must_change_password). Pass passwordPolicy: 'none' explicitly for the old identity-only behavior; per-row outcomes are on rows[].delivery.

14.x

ObjectOS One and the bundled server shipped on @objectstack 14.7.0. The runtime boot contract is unchanged — createStandaloneStack takes the same artifact, environment, and database settings — but 13.0 and 14.0 both land breaking changes in the authorization vocabulary, so review your permission metadata before rolling forward from ≤ 12.x. Full notes: docs.objectstack.ai/docs/releases. What moved in 14.x:

  • ADR-0090 vocabulary convergence completed (14.0, breaking) — book.audience gates on { permissionSet } (was { profile }), PortalSchema.profilespositions, RLSUserContextSchema.rolepositions (string array), sys_record_share.recipient_type: 'role''position'.
  • Object capability flags are enforced (14.0, breaking-ish) — the enable.* flags went from parsed-but-unused to real gates. activities and feeds are opt-out (default true; feeds: false rejects comments with 403 FEEDS_DISABLED), trackHistory drives the History tab, and files is opt-in (403 FILES_DISABLED until enable: { files: true }).
  • Member baseline lost delete (14.2, breaking) — member_default no longer grants record deletion; re-grant per object through position-distributed permission sets.
  • Admin user management & phone auth (14.3) — direct user creation (POST /api/v1/auth/admin/create-user, one-time passwords with forced rotation), bulk import (rows/CSV/XLSX, dry-run, upsert), opt-in phone sign-in with SMS OTP via @objectstack/plugin-sms (Aliyun / Twilio), and an sms notification channel.
  • Data-lifecycle contract (14.4, ADR-0057) — objects declare lifecycle (class, retention, rotation, archive); the default-on LifecycleService reaps, rotates, and archives platform data (sys_activity 14 days, sys_audit_log 90 days hot). Disable with OS_LIFECYCLE_DISABLED=1; tune via lifecycle.retention_overrides. 14.5 removed the per-plugin retentionDays / retentionSweepMs options (JobRunRetention, NotificationRetention) in favor of lifecycle declarations, and split lifecycle-classed system data into a dedicated telemetry datasource (OS_TELEMETRY_DB); os db clean reclaims SQLite space.
  • Effective-dated grants & delegation (14.4, ADR-0091) — position and permission-set assignments support valid_from / valid_until windows (fail-closed, no background job), and delegatable positions let holders self-delegate for a bounded window (≤ 30 days, reason required, never admin scopes).
  • MCP scope ceiling (14.5, ADR-0090 D10) — OAuth-connected agents run under effective_permission = scope_ceiling ∩ user_grants (data:read / data:write / actions:execute), failing closed.
  • Security fixes (14.4–14.5) — FLS keys must be object-qualified (bare keys silently matched nothing; now lint-rejected with autofix); settings and share-link routes no longer trust spoofable x-user-id-style headers; analytics queries are scoped to the caller's read filter.

13.x — Permission Model v2

@objectstack 13.0 restructured authorization (ADR-0090). Breaking:

  • Roles and Profiles converge on Positionssys_role* tables, RoleSchema / defineRole, metadata kinds role / profile, and ExecutionContext.roles[] are gone; positions are flat and hierarchy moved to the business-unit tree. Sharing recipients renamed (roleposition, role_and_subordinatesunit_and_subordinates).
  • Custom objects default to private — an owner-carrying object with no explicit sharingModel is now private; the read / read_write / full OWD aliases were removed. Declare sharingModel: 'public_read_write' to restore prior behavior.
  • RBAC link-table writes gated — writes to sys_user_position, sys_position_permission_set, sys_user_permission_set, and sys_permission_set require tenant admin or a delegated-admin scope.

And new: everyone / guest audience anchors, delegated administration (PermissionSet.adminScope), the explain() engine with per-layer attribution, the access-matrix snapshot gate for os compile, self-serve OAuth 2.1 for MCP clients, author-time security lints (validateSecurityPosture), per-operation Object.requiredPermissions maps, and package namespace-prefix enforcement. Never-enforced schemas (compliance / masking / global-RLS configs) were removed outright.

12.x

@objectstack 12.0 hardened the API default posture:

  • Anonymous data access denied by default (breaking) — api.requireAuth now defaults to true; anonymous /data/* requests get 401. Public-data deployments must opt out explicitly with api: { requireAuth: false } (boot warning). Share links, public forms, /auth, and /health are unaffected.
  • Enforced protocol handshakePROTOCOL_VERSION + checkProtocolCompat() reject incompatible packages at install time.
  • Adaptive record surfaces — records derive page vs. modal/drawer display from field complexity; FormField.span goes responsive ('auto' / 'full'); related lists gain 'primary' tab promotion.
  • Package-shipped permissions — packages declare default permission sets that materialize at boot with provenance tracking.
  • Build-time lintslint-view-refs, validateListViewMode, validateFormLayout, and destructive-operation RBAC mapping gate compilation.

10.x

The 10.x train shipped on @objectstack 10.0 – 10.2. Every breaking change landed in the multi-org tenancy layer, so a single-tenant ObjectOS deployment rolled forward from 9.x with no config changes. What moved:

  • Row-level org scoping split into its own plugin (10.0, breaking) — the organization_id auto-stamp, per-org seed replay, and default-org bootstrap moved out of @objectstack/plugin-security into the opt-in @objectstack/plugin-org-scoping. Single-org deployments are leaner (no wildcard RLS to strip on every query), and OS_MULTI_TENANT=true still auto-registers the plugin ahead of plugin-security, so projects driven by the CLI need no code changes. Per ADR-0002, a tenant is physical isolation (one Environment = one database); organization_id is logical scoping inside one DB, so it earns its own plugin.
  • No more automatic personal workspaces (10.0, breaking) — plugin-security no longer creates a "<User>'s Workspace" org for every new user. Users now accept an invitation or explicitly create their first organization (the Slack / Linear / GitHub-Orgs model). The first registered user — auto-promoted to platform admin — still gets a single Default Organization in multi-tenant mode so their session resolves RLS; single-tenant deployments create no orgs.
  • record form field type (ADR-0014) — Record<string, X> properties (such as an object's fields map) are now editable as first-class form fields in Studio instead of leaking through as raw JSON, and the object preview pane mounts the real ObjectGrid renderer — what you preview is what ships.
  • Pluggable embeddings via IEmbedder — a new embedder protocol plus @objectstack/embedder-openai; the knowledge / RAG adapters now consume IEmbedder and were renamed to drop the plugin- prefix.
  • Public Forms — anonymous Web-to-Lead / Web-to-Case forms served at /f/:slug, a unified FormPage (public /f/:slug + internal /forms/:name), a type: 'form' action variant, and defaultDetailForm on ObjectSchema.
  • Cloud identity splitos cloud login is now separate from os login, the cloud control plane moved to a private repo (a leaner OSS runtime), and objectstack init again scaffolds a project that builds and boots.

9.x

The 9.x train ran on @objectstack 9.0 – 9.11 before the 10.0 cutover. The runtime boot contract is unchanged from 8.0 — createStandaloneStack still takes the same artifact, environment, and database settings — so an 8.0 deployment rolls forward without config changes. The author-facing surface is what moved:

  • Analytics datasets are the single author surface (9.0, breaking) — dashboard widgets, reports, and list-charts now bind a semantic dataset (defineDataset(...)) and select dimensions/measures by name. The old inline query fields (object/valueField/aggregate on widgets, objectName/columns/groupingsDown on reports, xAxisField/yAxisFields on list-charts) were removed. Migration: move the inline query into a defineDataset and reference it by name. ChartTypeSchema also dropped 8 variant types that only rendered as their base (stacked-barbar, splineline, bubblescatter, …).
  • Stricter build-time validation (9.6–9.7) — os compile now fails on bare field references (amount instead of record.amount), unknown CEL functions, and wrong flow-value interpolation syntax, each with a did-you-mean hint. A stack that previously "built but was silently wrong" now fails loudly — re-run os compile after upgrading and fix what it flags.
  • Number-field formulas compute mixed arithmetic (9.7) — record.amount / 100 and record.price * 2 now evaluate instead of silently yielding null; the / 100.0 float-literal workaround is no longer needed.
  • Object-level REST gating, now enforced (ADR-0049) — an object's apiEnabled: false removes it from the REST surface, and an apiMethods whitelist restricts which operations are reachable. Previously parsed but not enforced.
  • Package documentation as metadata + book navigation (9.3–9.6) — src/docs/*.md register as doc metadata; the book element (ADR-0046) declares a derived-membership navigation spine, served at GET /api/v1/meta/book/:name/tree with audience gating.
  • os package install (9.3) — install a package into a running runtime from a catalog id or an inline air-gapped artifact, authenticating with --email / --password.
  • Approvals (9.3) — send-back-for-revision (maxRevisions, default 3), jobs-backed SLA auto-escalation, list search/pagination, and session-less bilingual approve/reject confirm links.
  • Inbound webhook flow triggers (9.3) — a type: 'api' flow mounts an HMAC-verified POST /api/v1/automation/hooks/:flowName/:hookId endpoint with idempotent, queue-backed ingestion.
  • Notification retention defaults on (9.5) — notification history auto-prunes at 90 days; set the messaging retentionDays: 0 to keep history forever.
  • CLI bundles AI provider SDKs (9.0) — OpenAI-compatible providers (DeepSeek, DashScope, SiliconFlow, OpenRouter, Cloudflare) work out of the box on a globally-installed CLI.

One flow-authoring behavior change to note: a create_record node's outputVariable now holds the created record object (was the bare id), so update {var} references that expected an id to {var.id}.

8.0.x

ObjectOS One and the bundled server shipped on @objectstack 8.0.1.

  • MCP over Streamable HTTP — every deployment can act as a network-reachable Model Context Protocol server. Opt in with OS_MCP_SERVER_ENABLED=true; the endpoint is served at /api/v1/mcp with fail-closed auth (anonymous requests are rejected). The plugin was renamed @objectstack/plugin-mcp-server@objectstack/mcp.
  • Self-serve API keysPOST /api/v1/keys mints a show-once sys_api_key. The REST data and metadata APIs (/api/v1/data, /api/v1/meta) now authenticate API keys through the same verifier as MCP, running under the key owner's permissions and record-level security.
  • Field-level conditional rulesvisibleWhen, readonlyWhen, and requiredWhen are enforced server-side by ObjectQL, not just in the form UI.
  • Reusable RLS read filtersecurity.getReadFilter(object, context) exposes the record-access read scope; analytics datasets, dashboards, and reports bridge to it and fail closed when the scope cannot be applied.
  • Standalone host stack — the runtime ships a single-tenant createStandaloneStack host; the 7.x cloud-connected, hostname-routed createObjectOSStack wrapper was removed. A cloud deployment now points OS_ARTIFACT_FILE at a published artifact URL.

5.0 — projectenvironment rename (shipped)

The runtime concept formerly called Project was renamed to Environment throughout. Affected:

  • CLI flags: --environment / -e
  • HTTP paths: /api/v1/environments/:environmentId/...
  • Headers: X-Environment-Id
  • Env vars: OS_ENVIRONMENT_ID (OS_PROJECT_ID kept as a deprecated alias)
  • DB columns: environment_id
  • JSON schemas: EnvironmentArtifact

Upgrading

See Upgrade and Rollback for the mechanical steps. Pre-flight:

  1. Read the CHANGELOG entry for every minor between your current and target version.
  2. Run os diff <old-artifact> <new-artifact> to surface breaking schema changes.
  3. Run os doctor against the target version.
  4. Bring up one canary instance before rolling the fleet.
  5. Have a rollback plan for both the image tag and the artifact version (they roll independently).

Reporting regressions

If a patch or minor breaks something previously working, file a bug at github.com/objectstack-ai/objectos/issues with the version you upgraded from / to. We treat regressions as the highest-priority class of bug.

On this page