Skip to content

Latest commit

 

History

History
1199 lines (1059 loc) · 95 KB

File metadata and controls

1199 lines (1059 loc) · 95 KB

Changelog

All notable changes to the ObjectStack Protocol will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Added

  • os auth login / register / me now work against multi-project servers@objectstack/client was sending requests to better-auth's /sign-in/email, /sign-up/email, /sign-out, /get-session without an Origin header, which better-auth rejected with MISSING_OR_NULL_ORIGIN: Missing or null Origin against the default trustedOrigins: ['http://localhost:*']. Auth methods now send Origin: <baseUrl> automatically. Additionally, the login() and register() response normalizer now accepts both the wrapped { data: { token, user } } shape and better-auth's flat { token, user } shape so the CLI's auth login flow stores the token correctly.
  • os projects bind + os projects create --artifact CLI commands — Third-party developers can now bind a locally-compiled bundle to a multi-project server without raw curl. os projects create --org <id> --name <name> --artifact ./dist/objectstack.json provisions a new project and seeds the bundle in one call (also supports --template <id> for the parity with built-in templates). The new os projects bind <projectId> --artifact <path> updates an existing project's metadata.artifact_path, with --build to run objectstack compile first and --reseed as a placeholder for the future server-side reseed endpoint. Both flags resolve relative paths to absolute and validate the file exists before issuing the API call. Verified end-to-end: project created via CLI, /api/v1/projects/{id}/data/account returns the seeded CRM accounts.
  • Third-party project binding via metadata.artifact_path — Multi-project POST /api/v1/cloud/projects now accepts metadata.artifact_path to bind a locally-compiled bundle (e.g. examples/app-crm/dist/objectstack.json) into a fresh project. Provisioning loads the JSON, registers schemas in the per-project ObjectQL engine, and seeds the bundle's data arrays — same pipeline that built-in templates use. New TemplateSeeder.seedBundle({ projectId, bundle }) method exposes the seeder for arbitrary bundles. Bind errors (read failure, malformed JSON) are recorded as non-fatal metadata.artifactBindError so the project still flips to active. Verified end-to-end: query /api/v1/projects/{id}/data/account returns the seeded CRM accounts.
  • AppBundleResolver for live kernel bindingapps/server now ships createFsAppBundleResolver() in apps/server/server/fs-app-bundle-resolver.ts. Reads sys_project.metadata.artifact_path (or artifact_paths[]) at per-project kernel boot, with optional OBJECTSTACK_PROJECT_ARTIFACTS=projId:path,… env override and OBJECTSTACK_PROJECT_ARTIFACT_ROOT for relative path resolution. Used wherever a project kernel is materialized (trigger / function / metadata API requests). Replaces the previous return [] stub.

Fixed

  • apps/server: GET /api/v1/cloud/templates now returns the full template registry (blank, crm, todo) on Vercel / play.objectstack.ai. Root cause: the dispatcher resolved templates through a template-seeder service registered by MultiProjectPlugin, and on Vercel cold starts that service registration could be missed by the request handler — the dispatcher then silently returned { templates: [], total: 0 }. Added a createTemplatesRoutePlugin that registers /cloud/templates directly on http.server from a static, module-scope listTemplates() snapshot, registered before DispatcherPlugin. Local single-project mode is unchanged.
  • packages/runtime/http-dispatcher.ts: /cloud/templates fallback now logs the resolution error via console.error instead of swallowing it silently, so the underlying cause is visible in production logs.
  • apps/server/objectstack.config.ts: multiProjectPluginProxy.init now wraps the inner init in try/catch and logs failures, preventing one-off init errors from silently leaving the kernel without template-seeder / kernel-manager.
  • apps/server: Multi-project / cloud mode now also serves GET /api/v1/studio/runtime-config (returns { singleProject: false }) via a new createStudioRuntimeConfigPlugin. Eliminates the 404 the Studio SPA logged on first load when OBJECTSTACK_MULTI_PROJECT=true (the default for root pnpm dev). Single-project mode is unchanged.

Added

  • M1 — Project Artifact envelope schema (@objectstack/spec) — Introduced the v0 ProjectArtifactSchema in packages/spec/src/system/project-artifact.zod.ts, the immutable envelope that objectstack compile will produce and ObjectOS will consume at boot. Required fields: schemaVersion (literal '0.1'), projectId, commitId, checksum ({ algorithm, value }), metadata (per-category arrays, passthrough() for forward compatibility), functions (inlined source with optional language/source/hash), and manifest (plugin / driver / engine requirements). Optional builtAt, builtWith, and a reserved payloadRef ({ url, expiresAt, checksum }) for future S3 indirection without an envelope bump. 14 new tests in project-artifact.test.ts. Resolves ROADMAP M1; unblocks M3 (Artifact API) and M4 (ObjectOS artifact loader).

Changed

  • D1 — ObjectOS metadata DB bridge removedMetadataPlugin no longer registers sys_metadata / sys_metadata_history into the ObjectOS manifest and no longer auto-bridges ObjectQL to DatabaseLoader during start(). Runtime metadata is now file/artifact backed; database-backed metadata persistence remains an explicit MetadataManager capability for control-plane services. Updated ROADMAP, North Star, Metadata Service docs, and ObjectStack skills to reflect the boundary.
  • D5 — ManifestSchema.scope enum trimmed to 'cloud' | 'system' | 'project' — Removed the deprecated 'platform' and 'environment' aliases from packages/spec/src/kernel/manifest.zod.ts. No call site in the workspace was setting the deprecated values, so this is a clean break. Resolves ROADMAP D5.
  • D4 — ObjectSchemaBase.namespace removed — Object identity is now single-sourced on name. The deprecated namespace field has been removed from ObjectSchemaBase (packages/spec/src/data/object.zod.ts); legacy inputs that still set namespace are silently stripped by Zod's default object behavior. Package-level namespace (FQN computation, marketplace publishing, DatasourceRoutingRule.namespace) is intentionally retained as an internal mechanic. Five legacy ObjectSchema namespace test blocks were rewritten as a single name-as-identity block. Resolves ROADMAP D4.
  • D7 — Plugin manifest header + objects unified per package — Each plugin / service now exposes a single canonical src/manifest.ts file that both objectstack.config.ts (compile-time) and the runtime *-plugin.ts (manifest.register()) import from. This eliminates a real divergence in plugin-auth and plugin-security whose configs imported from a non-existent ./src/objects/ directory and silently shipped empty object lists at compile time while their runtime registrations were intact. Affected packages: @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/service-tenant. Resolves ROADMAP D7.

Fixed

  • @objectstack/cli — Studio static plugin no longer breaks after a Studio rebuildcreateStudioStaticPlugin() in packages/cli/src/utils/studio.ts had two latent bugs that caused the browser to fail with Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of "text/html" whenever Studio's bundle hash changed between server start and the request:

    1. index.html was read once at startup and held in memory; a Studio rebuild produced new hashed asset filenames but the cached HTML still referenced the old hashes.
    2. The SPA fallback served index.html for every unmatched path under /_studio/, including /_studio/assets/*. Combined with (1), missing hashed assets would silently respond with HTML — producing the strict-MIME error in the browser. Fix: read index.html fresh on each fallback request, and return real 404 for /_studio/assets/* misses so the rebuild/redeploy mismatch surfaces immediately instead of being masked. Verified end-to-end against localhost:3000/_studio/ after a Studio rebuild.
  • @objectstack/service-tenant — system objects now actually registercreateTenantPlugin() previously declared its control-plane schemas (sys_project, sys_project_credential, sys_project_member, sys_package, sys_package_version, sys_package_installation, sys_tenant_database) via a top-level objects: [...] field on the kernel plugin object. The kernel only consumes plugin.objects for nested plugins inside a parent manifest (packages/objectql/src/engine.tsregisterPlugin()), so plugins added via kernel.use(plugin) had to use the manifest service (as AuthPlugin/SecurityPlugin/SetupPlugin already do). The result was that sys__project etc. were never registered with SchemaRegistry, so ObjectQL.getDriver('sys__project') could not match the namespace: 'sys' → turso datasourceMapping rule (the lookup returned undefined and skipped past the namespace check), silently routing every control-plane write to the default driver — typically the in-memory driver. On Vercel each lambda instance has its own memory, so POST /api/v1/cloud/projects "succeeded" with HTTP 202 but the row evaporated on cold start, causing the subsequent GET /api/v1/cloud/projects/:id to return 404 even though the user/organization writes (registered through the proper path by AuthPlugin) were correctly persisted in Turso. The plugin now registers the same set of objects via ctx.getService('manifest').register({ id: 'com.objectstack.tenant', namespace: 'sys', objects: [...] }) and throws if the manifest service is unavailable, fail-fast instead of silent data loss. Also affected: package install/upgrade endpoints, project credential rotation, project membership reads.

Changed

  • Platform object definitions consolidated in @objectstack/platform-objects — Removed the now-redundant @objectstack/objectos package. Metadata-layer objects (SysObject, SysView, SysAgent, SysTool, SysFlow) are registered directly from @objectstack/platform-objects/metadata, and plugin/service packages no longer re-export platform objects through compatibility objects facades.
  • examples/app-crm — showcase fieldGroups MVP — The CRM reference example (Account, Contact, Opportunity, Lead) now demonstrates the new fieldGroups protocol end to end. Each object declares logical groups (e.g., Basic Information, Financials, Contact Information, Ownership & Status, System) and every field opts in via group: '<key>'. No business logic changed — only field-layout metadata — so existing validations, workflows, indexes, and state machines are unaffected. Useful as a reference when designing multi-group forms and detail pages.

Added

  • Field Groups (fieldGroups) — simplified MVP protocol — Introduced a data-layer protocol for grouping fields on an object in forms, detail pages, and editors. Designed to be AI-generation- and extension-friendly by intentionally minimizing surface area:
    • New ObjectFieldGroupSchema in packages/spec/src/data/object.zod.ts with key (snake_case machine key), label, optional icon, description, defaultExpanded (default true), and visibleOn (expression for conditional visibility). No order property — array declaration order is the display order.
    • ObjectSchema gains an optional fieldGroups: ObjectFieldGroup[]. Group keys are validated to be unique within an object.
    • The existing Field.group: string property on FieldSchema is the sole field→group assignment mechanism. Field → group mapping is derived automatically from metadata registration; in-group display order equals the traversal order of ObjectSchema.fields. Extension packages and runtime code use Field.group uniformly.
    • Supported migrations at this layer: add / rename / delete / reorder groups (by editing the fieldGroups array) and assigning an existing field to a group (by editing Field.group). Explicit per-field in-group ordering is deferred to a future iteration.
    • New ObjectFieldGroup / ObjectFieldGroupInput type exports alongside the schema.
    • Tests: 12 new round-trip cases in packages/spec/src/data/object.test.ts covering minimal/full-group parsing, required fields, snake_case key validation, declaration-order preservation, duplicate-key rejection, Field.group referencing, and ObjectSchema.create() integration.

Added

  • Environment-per-database multi-tenancy (service-tenant v4.1) — Refactored the multi-tenant architecture from "per-organization database" to per-environment database high-isolation, with a hard split between Control Plane (environment registry / addressing / credentials / RBAC) and Data Plane (one physical database per environment). See docs/adr/0002-environment-database-isolation.md for the full rationale and trade-offs.
    • Zod protocol schemas (packages/spec/src/cloud/environment.zod.ts): EnvironmentSchema, EnvironmentDatabaseSchema, DatabaseCredentialSchema, EnvironmentMemberSchema, EnvironmentTypeSchema, EnvironmentStatusSchema, EnvironmentRoleSchema, DatabaseCredentialStatusSchema, ProvisionEnvironmentRequest/ResponseSchema, ProvisionOrganizationRequest/ResponseSchema. TenantDatabaseSchema is now marked @deprecated.
    • Control-plane objects (packages/services/service-tenant/src/objects/): sys_environment (UNIQUE (organization_id, slug)), sys_environment_database (UNIQUE environment_id — exactly one DB per environment), sys_database_credential (rotatable, encrypted, with active / rotating / revoked lifecycle), sys_environment_member (UNIQUE (environment_id, user_id), owner / admin / maker / reader / guest). Every field carries .describe() metadata and every uniqueness constraint is explicit.
    • EnvironmentProvisioningService (packages/services/service-tenant/src/environment-provisioning.ts): provisionOrganization() bootstraps a new org with a default environment and DB in one call; provisionEnvironment() allocates any subsequent dev / test / sandbox / preview environment; rotateCredential() mints a new active credential and revokes the previous one. Pluggable EnvironmentDatabaseAdapter (initial turso; libsql / sqlite / postgres drop in without core changes) and SecretEncryptor hooks.
    • Tenant plugin wiring: createTenantPlugin() now registers the current control-plane objects directly from @objectstack/platform-objects/tenant.
    • v4 → v5 migration skeleton (packages/services/service-tenant/migrations/v4-to-v5-env-migration.ts): idempotent, non-destructive, re-encrypts credentials with the current KMS key, reuses existing physical DBs as each org's new prod environment DB — no data movement required.
    • Tests: 22 new schema round-trip tests in packages/spec/src/cloud/environment.test.ts, 10 new provisioning tests in packages/services/service-tenant/src/environment-provisioning.test.ts covering organization bootstrap, environment creation, default-environment invariants, adapter routing, credential rotation, and encryption hooks.

Changed

  • Polished examples/app-crm dashboards — Rewrote executive, sales, and service dashboards and added a new unified crm overview dashboard, modeled after the reference implementation at objectstack-ai/objectui/examples/crm. The dashboards now use the framework's first-class metadata fields instead of ad-hoc hex strings stuffed into options.color:
    • Semantic colorVariant tokens (success/warning/danger/blue/teal/purple/orange) replace raw hex codes
    • Each widget carries a description, chartConfig (axes, color palette, annotations, interaction), and a header actionUrl/actionType/actionIcon for drill-down
    • Each dashboard declares a structured header with action buttons, a dateRange global time filter, globalFilters (owner / industry / priority lookups), and a refreshInterval
    • KPI metric widgets carry icon, format, and trend indicators (direction + delta + label) in options, mirroring the objectui reference visual style
    • Chart variety expanded: area (revenue trends), donut (lead source / industry), funnel (pipeline by stage), gauge (SLA compliance), horizontal-bar (rep ranking), with proper axis titles and value formatters
    • Table widgets use structured columns: [{ header, accessorKey, format }] instead of bare field-name arrays
    • New examples/app-crm/test/dashboard.test.ts validates every dashboard against DashboardSchema and enforces these conventions

Added

  • Release-readiness documentation pass (42 packages) — Aligned every @objectstack/* package for the formal v4.x release:
    • Canonical README template and package.json publishing checklist committed at docs/internal/PACKAGE_README_TEMPLATE.md
    • New packages/services/service-package/README.md documenting the package registry service
    • All package.json files now carry description, at least 3 keywords, a full repository block with directory, homepage, bugs, engines.node, publishConfig.access: public, and a files whitelist
    • @objectstack/service-tenant (was 0.1.0) and @objectstack/service-package (was 1.0.0) bumped to 4.0.4 in lockstep with the release train
    • Rewrote thin READMEs for core, rest, driver-memory, plugin-security, and all seven framework adapters (express, fastify, hono, nestjs, nextjs, nuxt, sveltekit) to the canonical structure: overview, installation, quick start, key exports, configuration, when/when-not, related packages, and docs links
    • Updated content/docs/guides/packages.mdx and content/docs/concepts/packages.mdx to reflect the actual 42 package inventory and to include service-package and service-tenant

Fixed

  • Studio left metadata list not refreshing on package switch — In apps/studio/src/routes/$package.tsx, the AppSidebar package-switcher's onSelectPackage handler only updated local selectedPackage state. A URL→state useEffect in the same layout then immediately reverted that state back to match the unchanged $package route param, so AppSidebar.loadMetadata (keyed on selectedPackage) never re-ran and the left metadata tree stayed stuck on the previous package. The dropdown now navigates to /$newPackage, making the URL the single source of truth; the URL→state effect then updates selectedPackage normally and the metadata list refreshes for the new package. (apps/studio/src/routes/$package.tsx)
  • Cross-origin auth tokens stripped in @objectstack/hono adapter (follow-up to PR #1178)createHonoApp() was not exposing set-auth-token via Access-Control-Expose-Headers, diverging from plugin-hono-server's CORS wiring. On Vercel deployments (where all traffic flows through createHonoApp()), the browser stripped the header from every response, preventing the better-auth bearer() plugin from delivering rotated session tokens to cross-origin clients. Cross-origin sessions silently broke even after the wildcard fixes in #1177/#1178. The adapter now always includes set-auth-token in exposeHeaders, merged with any user-supplied values, mirroring the invariant established in commit 151dd19c. (packages/adapters/hono/src/index.ts)
  • CORS wildcard patterns in @objectstack/hono adapter (follow-up to PR #1177)createHonoApp() was the third CORS code path that still treated wildcard origins (e.g. https://*.objectui.org) as literal strings when passing them to Hono's cors() middleware. Because apps/server routes all non-OPTIONS requests through this adapter on Vercel, the browser would see a successful preflight (handled by the Vercel short-circuit) followed by a POST/GET response with no Access-Control-Allow-Origin header, blocking every real request. The adapter now imports hasWildcardPattern / createOriginMatcher from @objectstack/plugin-hono-server and uses the same matcher-function branch as plugin-hono-server, so all three Hono-based CORS paths share a single source of truth. (packages/adapters/hono/src/index.ts)
  • CORS wildcard patterns on Vercel deploymentsCORS_ORIGIN values containing wildcard patterns (e.g. https://*.objectui.org,https://*.objectstack.ai,http://localhost:*) no longer cause browser CORS errors when apps/server is deployed to Vercel. The Vercel entrypoint's OPTIONS preflight short-circuit previously matched origins with a literal Array.includes(), treating * as a plain character and rejecting legitimate subdomains. It now shares the same pattern-matching logic as the Hono plugin's cors() middleware via new exports createOriginMatcher / hasWildcardPattern / matchOriginPattern / normalizeOriginPatterns from @objectstack/plugin-hono-server. (apps/server/server/index.ts, packages/plugins/plugin-hono-server/src/pattern-matcher.ts)

Added

  • Claude Code integration (CLAUDE.md) — Added root CLAUDE.md file so that Claude Code automatically loads the project's system prompt when launched in the repository. Content is synced with .github/copilot-instructions.md and includes build/test quick-reference commands, all prime directives, monorepo structure, protocol domains, coding patterns, and domain-specific prompt references. This complements the existing GitHub Copilot instructions and skills/ directory.
  • AI Skills documentation pages — Added two new documentation pages covering the Skills System:
    • content/docs/concepts/skills.mdx — Conceptual overview of the skills architecture, philosophy, and structure
    • content/docs/guides/skills.mdx — Complete reference for all 10 ObjectStack AI skills with usage examples and prompts
    • Updated top-level navigation to include concepts section
    • Added skills links to homepage cards, guides index, and navigation meta files

Changed

  • Skills Module Structure Refactor — Refactored all skills in skills/ directory to follow shadcn-ui's fine-grained layering pattern. Each skill now has:
    • Concise SKILL.md — High-level overview with decision trees and quick-start examples, referencing detailed rules
    • rules/ directory — Detailed implementation rules with incorrect/correct code examples for better AI comprehension
    • evals/ directory — Placeholder for future evaluation tests to validate AI assistant understanding
    • Skills refactored:
      • objectstack-schema (formerly objectstack-data) — Extracted rules for naming, relationships, validation, indexing, field types, and hooks (moved from objectstack-hooks)
      • objectstack-plugin (formerly objectstack-kernel) — Extracted rules for plugin lifecycle, service registry, and hooks/events system
      • objectstack-query — NEW skill for filters, sorting, pagination, aggregation, joins, expand, full-text search, window functions
      • objectstack-hooksDEPRECATED and consolidated into objectstack-schema/rules/hooks.md (hooks are core to data operations)
      • objectstack-ui, objectstack-api, objectstack-automation, objectstack-ai, objectstack-i18n, objectstack-quickstart — Added rules/ and evals/ structure with initial pattern documentation
    • Benefits:
      • Improved maintainability — Detailed rules are separated from high-level overview
      • Better AI comprehension — Incorrect/correct examples make patterns clearer
      • Enhanced testability — evals/ directory ready for skill validation tests
      • Reduced skill overlap — Hooks integrated into data skill where they belong
      • Preserved skill independence — Each skill remains independently installable/referenceable (no global routing required)

Fixed

  • Studio tests: failing CI on main — Fixed several long-standing test-suite issues in @objectstack/studio that broke the Test Core CI job:
    • Broken relative paths — Tests in test/plugins/ used ../src/... but were two levels deep, causing Vite/Vitest to report Failed to resolve import "../src/plugins". Corrected to ../../src/....
    • vitest.config.ts missing required aliases — The dedicated vitest.config.ts only declared the @ alias while vite.config.ts declared ~25 more (e.g. @objectstack/plugin-auth/objects, node built-in stubs). Tests that transitively imported src/mocks/createKernel.ts failed with "./objects" is not exported …. vitest.config.ts now mirrors the full alias set used by vite.config.ts.
    • Removed stale tests against non-existent APIs — Deleted test/components/AppSidebar.test.tsx, test/components/ObjectDataForm.test.tsx, test/components/ObjectDataTable.test.tsx. These were added as scaffolding against APIs that don't match the current components (wrong prop names, missing TanStack Router context) and never passed in CI.
    • Rewrote test/plugins/plugin-system.test.tsx to match the actual PluginRegistry API (getPlugins, getViewers, registerAndActivate, etc.) and PluginRegistryProvider async activation lifecycle.
  • Studio: Package switcher not filtering object list — Fixed a bug where switching packages in the Studio left sidebar did not change the displayed object list. The root cause was in ObjectStackProtocolImplementation.getMetaItems(): after filtering items by packageId via SchemaRegistry.listItems(), the code merged in ALL runtime items from MetadataService without respecting the packageId filter, effectively overriding the filtered results. The same issue existed in HttpDispatcher.handleMetadata() where the MetadataService fallback path also ignored packageId. Both paths now correctly filter MetadataService items by _packageId when a package scope is requested.
  • MetadataPlugin driver bridging fallback — Fixed MetadataPlugin.start() so the driver service scan fallback (driver.*) is reached when ObjectQL returns null (not just when it throws). Previously, setDatabaseDriver was never called in environments where ObjectQL was not loaded.
  • Auth trustedOrigins test alignment — Updated plugin-auth tests to match the auto-default http://localhost:* behavior added in PR #1152 for better-auth CORS support. When no trustedOrigins are configured, the implementation correctly defaults to trusting all localhost ports for development convenience.
  • Docs build: lucide-react module resolution — Added Turbopack resolveAlias in apps/docs/next.config.mjs so MDX content files in content/docs/ (outside the app directory) can resolve lucide-react. Turbopack starts module resolution from the file's directory, which doesn't have access to the app's node_modules/.
  • Client Hono integration test timeout — Fixed afterAll hook timeout in client.hono.test.ts by racing kernel.shutdown() against a 10s deadline. The shutdown can hang when pino's worker-thread flush callback never fires in CI, so the race ensures the hook completes within the 30s vitest limit.
  • CI: Replace pnpm/action-setup@v6 with corepack — Switched all GitHub Actions workflows (ci.yml, lint.yml, release.yml, validate-deps.yml, pr-automation.yml) from pnpm/action-setup@v6 to corepack enable to fix persistent ERR_PNPM_BROKEN_LOCKFILE errors. Corepack reads the exact packageManager field from package.json (including SHA verification), ensuring the correct pnpm version is used in CI. Also bumped pnpm store cache keys to v3 and added a pnpm version verification step.
  • Broken pnpm lockfile — Regenerated pnpm-lock.yaml from scratch to fix ERR_PNPM_BROKEN_LOCKFILE ("expected a single document in the stream, but found more") that was causing all CI jobs to fail. The previous merge of PR #1117 only included workflow cache key changes but did not carry over the regenerated lockfile.
  • service-ai: Fix navigation item labels using deprecated i18n object format — Replaced { key, defaultValue } i18n objects with plain string labels in AIServicePlugin's Setup App navigation contributions, completing the I18nLabelSchema migration from #1054.

Added

  • MCP Runtime Server Plugin (plugin-mcp-server) — New kernel plugin that exposes ObjectStack as a Model Context Protocol (MCP) server for external AI clients (Claude Desktop, Cursor, VS Code Copilot, etc.). Features include:
    • Tool Bridge: All registered AI tools from ToolRegistry (9 built-in tools: list_objects, describe_object, query_records, get_record, aggregate_data, create_object, add_field, modify_field, delete_field) are automatically exposed as MCP tools with correct annotations (readOnlyHint, destructiveHint).
    • Resource Bridge: Object schemas (objectstack://objects/{objectName}), object list (objectstack://objects), record access (objectstack://objects/{objectName}/records/{recordId}), and metadata types (objectstack://metadata/types) exposed as MCP resources.
    • Prompt Bridge: Registered agents (data_chat, metadata_assistant, etc.) exposed as MCP prompts with context arguments (objectName, recordId, viewName).
    • Transport: stdio transport via @modelcontextprotocol/sdk for local AI client integration.
    • Environment Configuration: MCP_SERVER_ENABLED=true to auto-start, MCP_SERVER_NAME and MCP_SERVER_TRANSPORT for customization.
    • Extensibility: mcp:ready kernel hook allows other plugins to extend the MCP server.
    • Studio frontend AI interface remains unchanged — it continues to use REST/SSE via Vercel Data Stream Protocol.

Changed

  • Unified list_objects / describe_object tools (service-ai) — Merged the duplicate list_metadata_objectslist_objects and describe_metadata_objectdescribe_object tool pairs. Both data_chat and metadata_assistant agents now share the same unified tools with full filter, includeFields, snake_case validation, and enableFeatures support. DATA_TOOL_DEFINITIONS is reduced from 5 to 3 (query-only tools), while METADATA_TOOL_DEFINITIONS retains all 6 tools under the unified names. The duplicate ObjectDef/FieldDef type definitions in data-tools.ts are removed.

Fixed

  • MetadataPlugin: Driver bridging for database-backed persistenceMetadataPlugin.start() now discovers registered driver services (driver.*) from the kernel service registry and calls manager.setDatabaseDriver() to enable DatabaseLoader. Previously, no code bridged the kernel's database driver to the MetadataManager, leaving DatabaseLoader unconfigured and metadata persistence limited to the filesystem only.
  • MetadataManager: register() no longer writes to FilesystemLoaderregister() now persists metadata only to datasource: protocol loaders (i.e. DatabaseLoader), skipping file: protocol loaders (FilesystemLoader). Previously, register() broadcast writes to all loaders indiscriminately, causing crashes in read-only environments (e.g. serverless, containerized deployments) when FilesystemLoader.save() attempted to write to disk. The same protocol filter is applied to unregister() for consistency.
  • Agent Chat: Vercel SSE Data Stream support — The agent chat endpoint (/api/v1/ai/agents/:agentName/chat) now returns Vercel AI SDK v6 UI Message Stream Protocol (SSE) by default, matching the general chat endpoint behaviour. Previously, the agent chat route only returned plain JSON, causing DefaultChatTransport (used by @ai-sdk/react useChat) to fail silently — the API responded correctly but the Studio AI Chat Panel rendered no content. The endpoint now uses streamChatWithTools + encodeVercelDataStream for stream !== false requests (the default), and falls back to JSON only when stream: false is explicitly set. Studio's error UI is also enhanced to surface SSE parse failures clearly instead of silent failure.
  • Agent Chat: Vercel AI SDK v6 parts format support — The agent chat endpoint (/api/v1/ai/agents/:agentName/chat) now accepts Vercel AI SDK v6 parts-based message format in addition to the legacy content string format. Previously, sending messages with parts (as useChat v6 does by default) resulted in a 400 error: "message.content must be a string". Shared validation and normalization utilities (validateMessageContent, normalizeMessage) are extracted into message-utils.ts for reuse across both the general chat and agent chat routes.
  • Studio: Code tab now shows CodeExporter — The Code tab in Studio metadata detail pages now correctly renders the CodeExporter component (TypeScript/JSON export with copy-to-clipboard) instead of always showing the JSON Inspector preview. The default plugin now registers two separate viewers: json-inspector for preview mode and code-exporter for code mode.
  • CI Test Failures — Resolved test failures across multiple packages:
    • @objectstack/service-ai: Fixed SDK fallback test by mocking @ai-sdk/openai dynamic import (SDK now available as transitive workspace dependency)
    • @objectstack/nuxt, @objectstack/nextjs, @objectstack/fastify, @objectstack/sveltekit: Added missing prefix argument to dispatch() assertion calls in adapter tests
    • @objectstack/plugin-auth: Updated dependencies assertion and added manifest service mock to match current plugin implementation

Added

  • AIServicePlugin Auto-Detection — AIServicePlugin now automatically detects and initializes LLM providers based on environment variables, eliminating the need for manual adapter configuration in each deployment:

    • Auto-detection priority: AI_GATEWAY_MODELOPENAI_API_KEYANTHROPIC_API_KEYGOOGLE_GENERATIVE_AI_API_KEY
    • Graceful fallback to MemoryLLMAdapter when no provider is configured
    • Comprehensive logging of selected provider and warnings for missing SDKs
    • Supports custom model selection via AI_MODEL environment variable
    • Consistent behavior across CLI, Vercel, Docker, and custom deployments
    • Dynamic import failures are handled as soft errors with automatic fallback (#1067)
  • Metadata Versioning & History — Comprehensive version history tracking and rollback capabilities for metadata items. Key features include:

    • MetadataHistoryRecordSchema defining structure for historical snapshots
    • sys_metadata_history system table for version storage
    • Automatic history tracking in DatabaseLoader with SHA-256 checksum deduplication
    • getHistory(), rollback(), and diff() methods in IMetadataService
    • REST API endpoints: GET /history, POST /rollback, GET /diff
    • HistoryCleanupManager with configurable retention policies (age-based and count-based)
    • Comprehensive test suite covering all history operations

    This aligns ObjectStack with enterprise platforms like Salesforce Setup Audit Trail and ServiceNow Update Sets. See docs/METADATA_HISTORY.md for detailed usage.

  • CLI: Remote API Commands - Added 12 new CLI commands for interacting with remote ObjectStack servers:

    • Authentication: os auth login, os auth logout, os auth whoami
    • Data API: os data query, os data get, os data create, os data update, os data delete
    • Metadata API: os meta list, os meta get, os meta register, os meta delete
    • All commands support --url and --token flags, or use stored credentials from ~/.objectstack/credentials.json
    • Multiple output formats: --format json|table|yaml (yaml available on all commands)
    • Environment variable support: OBJECTSTACK_URL, OBJECTSTACK_TOKEN
    • See REMOTE_API_COMMANDS.md for full documentation

Changed

  • i18n: I18nLabelSchema now accepts string onlylabel, description, title, and other display-text fields across all UI schemas (AppSchema, NavigationArea, PageSchema, DashboardWidgetSchema, ReportSchema, ChartSchema, NotificationSchema, AriaPropsSchema, etc.) now accept only plain strings. The previous string | I18nObject union type has been replaced with z.string(). i18n translation keys will be auto-generated by the framework at registration time; developers only need to provide the default-language string value. Translations are managed through translation files, not inline i18n objects. (#1054)

    Migration: Replace any label: { key: '...', defaultValue: 'X' } with label: 'X'. Existing plain-string labels require no changes.

    Affected plugins updated:

    • @objectstack/plugin-setupsetup-app.ts, setup-areas.ts
    • @objectstack/plugin-auth — navigation item labels
    • @objectstack/plugin-security — navigation item labels
    • @objectstack/plugin-audit — navigation item labels

Documentation

  • README rewrite — Rewrote README.md to accurately reflect the objectstack-ai/framework repository. Updates include: corrected title ("ObjectStack Framework"), updated badges (v4.0.1, 6,507 tests passing), fixed stale clone URL (spec.gitframework.git), added all missing packages (driver-sql, driver-turso, plugin-audit, plugin-setup, service-feed, service-automation, service-ai, service-realtime, service-i18n), updated codebase metrics (27 packages, 200 Zod schema files, 1,600+ exported schemas, 8,750+ .describe() annotations, 6,507 tests passing), and restructured sections to match the current monorepo layout.

Fixed

  • AI Chat agent selector missing data_chat and metadata_assistant — Fixed GET /api/v1/ai/agents returning 404, which caused the Studio AI Chat panel to show only "General Chat". There were two root causes addressed by this fix:
    1. Kernel bootstrap timing (packages/core/src/kernel.ts): 'core' service in-memory fallbacks (e.g. the 'metadata' service) were only injected in validateSystemRequirements() which runs AFTER all plugin start() methods execute. This meant ctx.getService('metadata') always threw during AIServicePlugin.start() when no explicit MetadataPlugin was loaded. Fix: added preInjectCoreFallbacks() called between Phase 1 (init) and Phase 2 (start), ensuring all core service fallbacks are available before any plugin's start() runs.
    2. Shadowed variable (packages/services/service-ai/src/plugin.ts): a redundant second ctx.getService('metadata') call declared a new const metadataService that shadowed the outer let metadataService and failed silently, preventing buildAgentRoutes() from being called even if the metadata service was available. Fix: reuse the already-resolved outer variable. Additionally, added a fallback in DispatcherPlugin.start() that recovers AI routes from the kernel.__aiRoutes cache in case the ai:routes hook fires before the listener is registered (timing edge case).
  • ObjectQLPlugin: cold-start metadata restorationObjectQLPlugin.start() now calls protocol.loadMetaFromDb() after driver initialization and before schema sync, restoring all persisted metadata (objects, views, apps, etc.) from the sys_metadata table into the in-memory SchemaRegistry. Previously, user-created custom objects were lost after kernel cold starts or redeployments because the hydration step was missing. The fix gracefully degrades in in-memory-only or first-run scenarios where sys_metadata does not yet exist.
  • Studio Vercel API routes returning HTML instead of JSON — Adopted the same Vercel deployment pattern used by hotcrm: committed api/[[...route]].js catch-all route so Vercel detects it pre-build, switched esbuild output from CJS to ESM (fixes "type": "module" conflict), and changed the bundle output to api/_handler.js (a separate file that the committed wrapper re-exports). This avoids both Vercel's TS compilation overwriting the bundle (ERR_MODULE_NOT_FOUND) and the "File not found" error from deleting source files during build. Added createRequire banner to the esbuild config so that CJS dependencies (knex/tarn) can require() Node.js built-in modules like events without the "Dynamic require is not supported" error. Added functions.includeFiles in vercel.json to include native addons (better-sqlite3, @libsql/client) that esbuild cannot bundle. Added a build step to copy native external modules from the monorepo root node_modules/ into the studio's local node_modules/, since pnpm's strict mode (unlike hotcrm's shamefully-hoist) doesn't symlink transitive native dependencies into app-level node_modules/. Updated rewrites to match: /api/:path*/api/[[...route]].
  • Studio CORS error on Vercel temporary/preview domains — Changed VITE_SERVER_URL from hardcoded https://play.objectstack.ai to "" (empty string / same-origin) in vercel.json so each deployment — including previews — calls its own serverless function instead of the production API cross-origin. Also added Hono CORS middleware to apps/studio/server/index.ts as a safety net for any remaining cross-origin scenarios; dynamically allows all *.vercel.app subdomains, explicitly listed Vercel deployment URLs, and localhost. Extracted getVercelOrigins() helper to keep CORS and better-auth trustedOrigins allowlists in sync.
  • Client test aligned with removed ai.chat method — Updated @objectstack/client test suite to match the current API surface where ai.chat() was removed in favour of the Vercel AI SDK useChat() hook. The obsolete test that called client.ai.chat() now asserts the method is absent, fixing the CI @objectstack/client#test failure.

Added

  • Metadata Assistant Agent (service-ai) — New metadata_assistant agent definition that binds all 6 metadata management tools (create_object, add_field, modify_field, delete_field, list_objects, describe_object). Includes a tailored system prompt that guides the AI to use snake_case naming, verify existing schemas before modifications, and warn about destructive operations. Configured with react planning strategy (10 iterations, replan enabled) for multi-step schema design conversations.

  • Tool Confirmation Flags — Added requiresConfirmation: true to create_object and delete_field tool definitions. These destructive/creation operations now signal to the frontend that user approval is needed before execution.

  • Frontend Tool Call Display (AiChatPanel) — Enhanced the AI Chat Panel to render tool invocation parts from the Vercel AI SDK v6 stream protocol. Displays tool call status with visual indicators:

    • Calling: Spinner animation with tool name and argument summary
    • Confirmation: Yellow-bordered card with Approve/Deny buttons for requiresConfirmation tools
    • Success: Green success indicator with result preview
    • Error: Red error indicator with error message
    • Denied: Muted indicator for user-denied operations
  • Operation Confirmation Mechanism — Integrated the Vercel AI SDK addToolApprovalResponse hook to support approval/denial workflows for tools marked with requiresConfirmation. When the server sends an approval-requested state, the chat panel shows Approve and Deny buttons. User decisions are sent back to the server to continue or abort the tool execution.

  • Metadata Management Tools (service-ai) — Added 6 built-in AI tools for metadata CRUD operations, each defined as a first-class Tool metadata file using defineTool() from @objectstack/spec/ai:

    • create-object.tool.ts — Creates a new data object with schema validation
    • add-field.tool.ts — Adds a field to an existing object
    • modify-field.tool.ts — Modifies field properties on an object
    • delete-field.tool.ts — Removes a field from an object
    • list-metadata-objects.tool.ts — Lists all registered metadata objects
    • describe-metadata-object.tool.ts — Returns full schema details of an object

    Each .tool.ts file is an independent metadata unit with name, label, description, category, builtIn, and parameters — following the same .object.ts / .view.ts metadata file convention. Handler factories remain in metadata-tools.ts and bind handlers at ai:ready time via registerMetadataTools(registry, { metadataService }). 79 unit tests covering tool metadata properties, handler execution, input validation, error handling, dual registration with data tools, and a full lifecycle test.

  • Agent Skills — skills/ directory (agentskills.io) — Created skills/ folder at repository root following the agentskills.io specification. Five expert-knowledge skills with hand-written SKILL.md files and references/ quick-lookup tables:

    • skills/schema-design/ — Data schema design (Object, Field, Validation, Index)
    • skills/ui-design/ — UI protocol (View, App, Dashboard, Report, Action)
    • skills/automation-design/ — Automation (Flow, Workflow, Trigger, Approval)
    • skills/ai-agent-design/ — AI Agent protocol (Agent, Skill, RAG, Tool)
    • skills/api-design/ — API protocol (REST endpoints, Discovery, Datasource) Each SKILL.md includes YAML frontmatter (name, description, license, metadata), domain rules, usage guidance, best practices, common pitfalls, and code examples. Zod schema files remain the single source of truth; skills reference them for validation.
  • Discovery Schema — ServiceStatus enum & handlerReady field — Added 'registered' status to ServiceInfoSchema to distinguish routes that are declared in the dispatcher table but whose HTTP handler has not been verified. Added optional handlerReady boolean field (omitted = unverified/unknown) so clients can filter handler-ready services before displaying endpoints when the value is explicitly true.

  • Discovery Schema — RouteHealthReportSchema — New schema for automated route/handler coverage reporting at startup. Includes per-route health entries (pass, fail, missing, skip) and summary counters.

  • Dispatcher Schema — DispatcherErrorCode & DispatcherErrorResponseSchema — Semantic error codes (404/405/501/503) with machine-readable type field (ROUTE_NOT_FOUND, METHOD_NOT_ALLOWED, NOT_IMPLEMENTED, SERVICE_UNAVAILABLE) and developer-facing hint strings.

  • Dispatcher Schema — /health route — Added health endpoint to DEFAULT_DISPATCHER_ROUTES.

  • REST API Plugin — handlerStatus field — Added handlerStatus (implemented, stub, planned) to RestApiEndpointSchema to track handler implementation readiness.

  • REST API Plugin — RouteCoverageReportSchema — Schema for adapter-generated coverage reports listing every declared endpoint and its implementation status.

  • ai v6 as a dependency of @objectstack/spec for type re-exports

Removed

  • Removed value field from data API responses — The findData protocol implementation no longer returns the deprecated value field alongside records. Only records is returned, matching the FindDataResponseSchema spec. All downstream consumers (Studio, server example, tests) updated to use records exclusively. OData-specific responses (ODataResponseSchema) retain value per the OData v4 standard — protocol-to-OData adaptation is handled in the HTTP dispatch layer.

Changed

  • AI Chat Protocol Aligned with Vercel AI SDK — Removed custom AI chat protocol types and Zod schemas (AIMessage, AIToolCall, AIStreamEvent, AiChatRequestSchema, AiChatResponseSchema) from @objectstack/spec. The canonical message, tool-call, and streaming types are now re-exported from the Vercel AI SDK (ai v6):
    • ModelMessage replaces AIMessage
    • ToolCallPart replaces AIToolCall
    • ToolResultPart replaces AIToolResult
    • TextStreamPart<ToolSet> replaces AIStreamEvent
    • IAIService and LLMAdapter method signatures now accept ModelMessage[] and return TextStreamPart<ToolSet> for streaming
    • Deprecated type aliases preserved for migration convenience
    • NLQ, Suggest, and Insights protocols (ObjectStack-specific) are retained
  • @objectstack/service-ai migrated to Vercel AI SDK types — All source files and tests now use canonical Vercel types (ModelMessage, ToolCallPart, ToolResultPart, TextStreamPart<ToolSet>) instead of deprecated aliases:
    • ToolRegistry.execute() accepts ToolCallPart and returns ToolExecutionResult (extends ToolResultPart with isError?: boolean)
    • Tool call loop in AIService.chatWithTools() constructs proper AssistantModelMessage and ToolModelMessage with Vercel-format content arrays
    • MemoryLLMAdapter.streamChat() emits Vercel TextStreamPart<ToolSet> events
    • Conversation services serialize/deserialize ModelMessage union to flat DB columns
    • All 158 service-ai tests updated and passing

Fixed

  • Runtime Dispatcher — semantic error differentiationHttpDispatcher.dispatch() now returns typed 404 (ROUTE_NOT_FOUND) with diagnostic info instead of bare { handled: false }. Added routeNotFound() (404) helper method.
  • Runtime Dispatcher — /health handler — Added health endpoint returning status, timestamp, version, and uptime.
  • Runtime Dispatcher — handlerReady in discoverygetDiscoveryInfo() now emits handlerReady: true for services with confirmed handlers and handlerReady: false for unavailable services.
  • Dispatcher Plugin — semantic 404sendResult() now returns ROUTE_NOT_FOUND error type with a hint pointing to the discovery endpoint. Added /health handler registration.
  • Studio — handler-ready filteringuseApiDiscovery() now checks both enabled and handlerReady (or status === 'available' | 'degraded' for backward compatibility) before displaying service endpoints in the UI.

Removed

  • AiChatRequestSchema / AiChatResponseSchema Zod schemas from @objectstack/spec/api — the AI chat wire protocol now uses Vercel AI SDK's data stream format (toDataStreamResponse())
  • aiChat method from IObjectStackAPI and client SDK — consumers should use @ai-sdk/react/useChat directly
  • AI /chat endpoint from DEFAULT_AI_ROUTES plugin REST API definition

Added

  • ai v6 as a dependency of @objectstack/spec for type re-exports
  • Vercel AI Data Stream Protocol support on /api/v1/ai/chat — The chat endpoint now supports dual-mode responses:
    • Streaming (default): When stream is not false, returns Vercel Data Stream Protocol frames (0: text, 9: tool-call, d: finish, etc.), directly consumable by @ai-sdk/react/useChat
    • JSON (legacy): When stream: false, returns the original JSON response
    • Accepts Vercel useChat flat body format (system, model, temperature, maxTokens as top-level fields) alongside the legacy { messages, options }
    • systemPrompt / system field is prepended as a system message
    • Message validation now accepts Vercel multi-part array content
    • RouteResponse.vercelDataStream flag signals HTTP server layer to encode events using the Vercel Data Stream frame format
  • VercelLLMAdapter — Production adapter wrapping Vercel AI SDK's generateText / streamText for any compatible model provider (OpenAI, Anthropic, Google, Ollama, etc.)
  • vercel-stream-encoder.ts — Utilities (encodeStreamPart, encodeVercelDataStream) to convert TextStreamPart<ToolSet> events into Vercel Data Stream wire-format frames
  • 176 service-ai tests passing (18 new tests for stream encoder, route dual-mode, systemPrompt, flat options, array content)

[4.0.1] — 2026-03-31

Fixed

  • Version Alignment Patch — Unified all package versions to 4.0.1. Previously, @objectstack/driver-sql and @objectstack/driver-turso were at 3.3.2, example packages were at 3.0.26, and the root monorepo was at 3.0.8 while all other @objectstack/* packages were at 4.0.0. All packages now share a single, consistent version number aligned with the changeset fixed group configuration.

Added

  • @objectstack/service-realtimesys_presence System Object — Registers the sys_presence system object in the service-realtime package as the canonical Presence domain object. Fields align with the PresenceStateSchema protocol definition (user_id, session_id, status, last_seen, current_location, device, custom_status, metadata). RealtimeServicePlugin now auto-registers the object via the app.com.objectstack.service.realtime service convention. Added SystemObjectName.PRESENCE constant ('sys_presence') to @objectstack/spec/system.
  • @objectstack/service-ai — Data Chatbot: Tool Call Loop & Agent Runtime — Implements an Airtable Copilot-style data conversation Chatbot with full-stack support:
    • AIService.chatWithTools() — automatic multi-round LLM ↔ tool call loop with maxIterations safety limit, parallel tool execution, and forced final response
    • AIResult.toolCalls — new field on the AI result contract so adapters can return tool call requests from the LLM
    • ChatWithToolsOptions — new contract interface extending AIRequestOptions
    • 5 built-in data tools: list_objects, describe_object, query_records, get_record, aggregate_data — with parameter schemas, limit capping (max 200), and error handling
    • registerDataTools(registry, context) — factory to register all data tools against IDataEngine + IMetadataService
    • AgentRuntime — loads agent metadata, builds system prompts from instructions + UI context (objectName, recordId, viewName), resolves agent tool references against the ToolRegistry
    • buildAgentRoutes() — new POST /api/v1/ai/agents/:agentName/chat route with agent lookup, active-check, context injection, and chatWithTools integration
    • DATA_CHAT_AGENT — built-in data_chat agent spec with role, instructions, guardrails, planning config, and tool declarations
    • AIServicePlugin auto-registers data tools and data_chat agent when IDataEngine + IMetadataService are available in the kernel
    • 42 new test cases covering tool call loop, data tools, agent runtime, agent routes, and agent spec validation
  • @objectstack/service-ai — ObjectQL-backed persistent ConversationService — New ObjectQLConversationService implements IAIConversationService using IDataEngine for durable conversation and message storage across service restarts:
    • ai_conversations and ai_messages system object definitions (namespace ai)
    • Full CRUD: create, get, list (with userId/agentId/limit/cursor filters), addMessage (with toolCalls/toolCallId support), and delete (cascade)
    • AIServicePlugin auto-detects IDataEngine in the kernel service registry and uses ObjectQLConversationService when available, falling back to InMemoryConversationService for dev/test environments
    • AIServicePluginOptions.conversationService allows explicit override
    • Plugin registers AI system objects via app.com.objectstack.service-ai service
    • 16 new test cases covering all five interface methods plus edge cases
  • Promoted LLMAdapter interface to @objectstack/spec/contracts — Moved the LLMAdapter adapter contract from @objectstack/service-ai internal types to the canonical protocol layer (packages/spec/src/contracts/llm-adapter.ts). Third-party adapter implementations (OpenAI, Anthropic, Ollama, etc.) can now depend solely on @objectstack/spec for type alignment. service-ai re-exports the interface for backward compatibility.

Fixed

  • Changeset fixed versioning — add driver-sql and driver-turso — Added @objectstack/driver-sql and @objectstack/driver-turso to the changeset fixed versioning group in .changeset/config.json. These packages were missing from the group, causing them to be published as 3.3.2 instead of 4.0.0 during the v4.0.0 release. All future releases will now keep these driver packages in sync with the rest of the ecosystem.
  • ObjectQL build failure — Fixed TypeScript TS2345 errors in packages/objectql/src/protocol.ts where SchemaRegistry.registerItem() calls failed type checking for the keyField parameter. Applied 'name' as any cast consistent with the established codebase pattern.
  • ObjectQL loadMetaFromDb — Fixed metadata hydration for object type records to use SchemaRegistry.registerObject() instead of registerItem(), resolving a mismatch where objects registered via registerItem could not be retrieved via getItem('object', ...).
  • Adapter discovery endpoints — Fixed discovery route in Hono, SvelteKit, Nuxt, Next.js, and Fastify adapters to serve discovery info at the API prefix root (e.g., GET /api) instead of a /discovery subpath. Updated .well-known/objectstack redirects accordingly.
  • Client feed namespace routing — Fixed ObjectStackClient.feed methods to use the data route (/api/v1/data/{object}/{recordId}/feed) instead of a separate /api/v1/feed route, matching the actual server-side routing where feed is a sub-resource of data.

Added

  • @objectstack/service-ai — Unified AI capability service plugin — New kernel plugin providing standardized AI service integration:
    • Registers as kernel 'ai' service conforming to IAIService contract
    • LLM adapter layer with provider abstraction (LLMAdapter interface) and built-in MemoryLLMAdapter for testing/development
    • ToolRegistry for metadata/business tool registration and execution
    • InMemoryConversationService implementing IAIConversationService for multi-turn conversation management with message persistence
    • REST/SSE route self-registration (/api/v1/ai/chat, /api/v1/ai/chat/stream, /api/v1/ai/complete, /api/v1/ai/models, /api/v1/ai/conversations)
    • Plugin lifecycle hooks (ai:ready, ai:routes) for extensibility
  • Expanded IAIService contract — Added streaming (streamChat), tool calling protocol (AIToolDefinition, AIToolCall, AIToolResult, AIMessageWithTools, AIRequestOptionsWithTools, AIStreamEvent), and conversation management (IAIConversationService, AIConversation) to packages/spec/src/contracts/ai-service.ts
  • @objectstack/plugin-setup — Platform Setup App plugin — New internal plugin (packages/plugins/plugin-setup) that owns and finalizes the platform Setup App. Ships four built-in Setup Areas (Administration, Platform, System, AI) as empty skeletons. Other plugins contribute navigation items via the setupNav service during their init phase. At start, SetupPlugin merges all contributions, filters out empty areas, and registers the finalized Setup App as an internal platform app. This establishes clear architectural separation: spec = protocol only, objectql = data/query only, plugins = system feature and UI composition.

Documentation

  • Unified API query syntax documentation with Spec canonical format — Rewrote content/docs/protocol/objectql/query-syntax.mdx and content/docs/guides/contracts/data-engine.mdx to align all examples, interface definitions, and field names with the canonical QuerySchema, FilterConditionSchema, and EngineQueryOptionsSchema from @objectstack/spec. All query examples now use where + MongoDB-style $op object syntax (replacing legacy tuple/filters/三元组 format), orderBy (replacing sort), groupBy (replacing group_by), and aggregations array (replacing aggregate object map). IDataEngine contract documentation updated to reflect the real interface (find/findOne/insert/ update/delete/count/aggregate). Added legacy compatibility sections clearly marking tuple/array syntax as UI-builder input only, with migration guidance.

Changed

  • Studio Vercel deployment — switched from InMemoryDriver to TursoDriver — The Studio serverless API entrypoint (apps/studio/api/index.ts) now uses @objectstack/driver-turso (TursoDriver) instead of @objectstack/driver-memory (InMemoryDriver) for Vercel deployments. In production, the driver connects to a Turso cloud database via TURSO_DATABASE_URL and TURSO_AUTH_TOKEN environment variables (remote mode). For local development without those variables, it falls back to :memory: (ephemeral SQLite). This ensures data persistence across serverless function invocations on Vercel. The browser MSW mock kernel remains unchanged (InMemoryDriver).

Fixed

  • Metadata DB persistence — saveMetaItem() now writes to database — The protocol implementation (ObjectStackProtocolImplementation.saveMetaItem()) now persists metadata to the sys_metadata table via IDataEngine in addition to the in-memory SchemaRegistry. Previously, metadata saved via PUT /api/v1/meta/:type/:name was lost on server restart. Added loadMetaFromDb() bootstrap method to hydrate the registry from the database on startup. getMetaItem() and getMetaItems() now fall back to database queries when items are not found in the in-memory registry. Discovery endpoint metadata status upgraded from degraded to available. Graceful degradation: if the database is unavailable, operations fall back to memory-only mode with a warning.
  • Vercel API always returns HTML — serverless function entrypoint not found — The bundle-api.mjs script was emitting api/index.js at the project root, but vercel.json sets outputDirectory: "dist", so Vercel could not discover the serverless function and fell back to the SPA HTML route for all /api/* requests. Changed esbuild outfile to dist/api/index.js and added explicit functions config in vercel.json with @vercel/node@3 runtime.

Added

  • Batch schema sync for remote DDL in kernel bootstrapObjectQLPlugin.syncRegisteredSchemas() now groups objects by driver and uses syncSchemasBatch() when the driver advertises supports.batchSchemaSync = true. This reduces the number of remote DDL round-trips from roughly N×(2–3) individual calls (introspection + optional PRAGMA + DDL write per object) to a small constant number of batched client.batch() calls, cutting cold-start times from 58+ seconds to under 10 seconds for 100+ objects on remote drivers (e.g. Turso cloud). Falls back to sequential syncSchema() per object for drivers without batch support or if the batched calls fail at runtime. Added batchSchemaSync capability flag to DriverCapabilitiesSchema, optional syncSchemasBatch() to IDataDriver, and RemoteTransport.syncSchemasBatch() using @libsql/client's batch() API.
  • @objectstack/driver-turso — dual transport architecture — TursoDriver now supports three transport modes: local, replica, and remote. Remote mode (url: 'libsql://...') enables pure cloud-only queries via @libsql/client SDK (HTTP/WebSocket) without requiring a local SQLite database or Knex. Transport mode is auto-detected from the URL or can be forced via config.mode. The driver exposes transportMode and isRemote properties for runtime introspection. All IDataDriver methods (CRUD, bulk, transactions, schema sync) work identically across all modes. Added RemoteTransport class, TursoTransportMode type, and support for injecting a pre-configured @libsql/client instance via config.client.

Fixed

  • Vercel deployment — ERR_MODULE_NOT_FOUND for @objectstack/metadata — Fixed incorrect exports paths in @objectstack/metadata package.json that pointed directly to TypeScript source files (src/index.ts, src/node.ts) instead of compiled dist output. Node.js cannot import .ts files at runtime, causing ERR_MODULE_NOT_FOUND on Vercel. Updated main, types, and exports to reference dist files (dist/index.js, dist/index.mjs, dist/node.mjs, etc.). Added a local tsup.config.ts with both entry points (src/index.ts, src/node.ts) and a files field to the package.json. Follows the same pattern as @objectstack/spec.
  • Vercel deployment — ERR_MODULE_NOT_FOUND for @objectstack/service-feed — Fixed incorrect exports paths in package.json for all service packages that declare "type": "module". When tsup builds an ESM package ("type": "module"), it outputs .js for ESM and .cjs for CJS. However, the exports maps incorrectly referenced .mjs (ESM) and .js (CJS) — the convention for packages without "type": "module". This caused Node's ESM resolver to fail with ERR_MODULE_NOT_FOUND when Vercel tried to import dist/index.mjs (which doesn't exist). Affected packages: service-feed, service-automation, service-cache, service-realtime, service-job, service-queue, service-storage, service-analytics.
  • @objectstack/driver-sql DTS build failure — knex type resolution — Fixed a TypeScript declaration build failure caused by knex v3.2.3 declaring a non-existent .d.mts types file in its package.json exports field. With moduleResolution: "bundler", TypeScript could not resolve knex's type declarations, resulting in TS7016 and TS7006 errors during DTS generation. Added a paths mapping in the driver-sql tsconfig.json to direct TypeScript to the correct knex/types/index.d.ts file. This also fixes cascade build failures in all downstream packages that depend on driver-sql.
  • SqlDriver.syncSchema() — physical table name mismatch — Fixed the root cause of the no such table: sys_user error: syncSchema() was ignoring the object parameter (physical table name like sys_user) and using schema.name (FQN like sys__user) for DDL operations. The method now correctly passes the physical table name to initObjects(). Additionally, initObjects() now supports a tableName property as defense-in-depth, preferring it over name when both are present.
  • Login API error — database tables not created — Fixed a critical naming mismatch between the FQN (Fully Qualified Name) used by SchemaRegistry (e.g., sys__user with double underscore) and the physical table name derived by ObjectSchema.create() (e.g., sys_user with single underscore). syncRegisteredSchemas() now uses the tableName property from object definitions for DDL operations, ensuring tables are created with the correct physical name that matches what the auth adapter and SystemObjectName constants expect.
  • SchemaRegistry.getObject() — protocol name resolution — Added a third fallback that matches objects by their tableName property (e.g., getObject('sys_user') now correctly finds the object registered as FQN sys__user). This bridges protocol-layer names (SystemObjectName.USER = 'sys_user') with the registry's FQN naming convention.
  • ObjectQL.resolveObjectName() — physical table name — Now returns schema.tableName (the physical table/collection name) instead of schema.name (the FQN) when available, ensuring driver SQL queries target the correct table.
  • SqlDriver.ensureDatabaseExists() — multi-driver support — Extended database auto-creation to support MySQL (error code ER_BAD_DB_ERROR / errno 1049) alongside PostgreSQL (error code 3D000). SQLite is explicitly skipped (auto-creates files).
  • SqlDriver.createDatabase() — MySQL support — Added MySQL-specific logic that connects without a database specified and uses CREATE DATABASE IF NOT EXISTS.

Added

  • @objectstack/driver-turso plugin — Migrated and standardized the Turso/libSQL driver from @objectql/driver-turso into packages/plugins/driver-turso/. The driver extends SqlDriver from @objectstack/driver-sql — all CRUD, schema, filter, aggregation, and introspection logic is inherited with zero code duplication. Turso-specific features include: three connection modes (local file, in-memory, embedded replica), @libsql/client sync mechanism for embedded replicas, multi-tenant router with TTL-based driver caching, and enhanced capability flags (FTS5, JSON1, CTE, savepoints, indexes). Includes 53 unit tests. Factory function createTursoDriver() and plugin manifest for kernel integration.
  • Multi-tenant routing (createMultiTenantRouter) — Database-per-tenant architecture with automatic driver lifecycle management, tenant ID validation, configurable TTL cache, and onTenantCreate/onTenantEvict lifecycle callbacks. Serverless-safe (no global intervals).

Changed

  • @objectstack/driver-sql — Protected extensibility — Changed private to protected for all internal properties and methods (knex, config, jsonFields, booleanFields, tablesWithTimestamps, isSqlite, isPostgres, isMysql, getBuilder, applyFilters, applyFilterCondition, mapSortField, mapAggregateFunc, buildWindowFunction, createColumn, ensureDatabaseExists, createDatabase, isJsonField, formatInput, formatOutput, introspectColumns, introspectForeignKeys, introspectPrimaryKeys, introspectUniqueConstraints). Enables clean subclassing for driver variants (Turso, D1, etc.) without code duplication.

Fixed

  • @objectstack/driver-sqlcount() returns NaN for zero results — Fixed count() method using || (logical OR) instead of ?? (nullish coalescing) to read the count value. When the actual count was 0, row.count || row['count(*)'] evaluated to Number(undefined) = NaN because 0 is falsy. Now uses row.count ?? row['count(*)'] ?? 0 for correct zero handling.

Changed

  • Unified Data Driver Contract (IDataDriver) — Resolved the split between DriverInterface (core, minimal ~13 methods) and IDataDriver (spec, comprehensive 28 methods). IDataDriver from @objectstack/spec/contracts is now the single authoritative contract for all database driver implementations. DriverInterface is retained as a deprecated type alias for backward compatibility. Both @objectstack/driver-sql and @objectstack/driver-memory now implement IDataDriver directly with full DriverCapabilities support.
  • @objectstack/driver-sql — Added missing IDataDriver methods: findStream, upsert, bulkUpdate, bulkDelete, commit, rollback, dropTable, explain. Aligned supports with full DriverCapabilities schema. updateMany/deleteMany now return number (count) instead of { modifiedCount } / { deletedCount } objects. delete returns boolean.
  • @objectstack/driver-memory — Aligned supports property with full DriverCapabilities schema (added create, read, update, delete, bulkCreate, bulkUpdate, bulkDelete, savepoints, queryCTE, jsonQuery, geospatialQuery, streaming, schemaSync, etc.).

Removed

  • @objectstack/driver-sql — Legacy query key fallbacks — Removed support for deprecated query keys filters (use where), sort (use orderBy), skip (use offset), and top (use limit) from find, updateMany, deleteMany, and count methods. The SQL driver now strictly follows the IDataDriver / QueryAST protocol. All as any casts for legacy key access have been eliminated. Tests updated to use only standard QueryAST keys.

Deprecated

  • DriverInterface — Use IDataDriver from @objectstack/spec/contracts instead. DriverInterface remains as a type alias in both @objectstack/spec/contracts and @objectstack/core for backward compatibility.

Added

  • @objectstack/driver-sql plugin — Migrated the Knex-based SQL driver from @objectql/driver-sql into packages/plugins/driver-sql/. The driver implements the standard DriverInterface from @objectstack/core and imports types from @objectstack/spec/data. Supports PostgreSQL, MySQL, and SQLite (via better-sqlite3). Includes schema sync, introspection, aggregation, window functions, transactions, and full CRUD with both QueryAST and legacy filter format support. All 72 unit tests pass against in-memory SQLite.

Changed

  • Migrate API layer to Hono + Vercel Node adapter — Replaced the vestigial Next.js-style api/[...path].ts catch-all with a proper api/index.ts Hono entrypoint using handle(app) from hono/vercel. Vercel routes now use a rewrite rule (/api/*/api) for native Hono routing, eliminating path-normalisation hacks and catch-all bundling pitfalls. Kernel boot remains lazy (cold-start only) via ensureApp() / ensureKernel() in _kernel.ts.

Fixed

  • Service-analytics build error (TS6133) — Removed unused measure variable in native-sql-strategy.ts that caused the DTS build to fail with noUnusedLocals enabled, blocking the entire CI build pipeline.
  • Next.js adapter test failures — Updated 9 metadata API test assertions to match the current dispatch(method, path, body, queryParams, context) call signature used by the implementation. Tests were still expecting the old dispatch(subPath, context, method, body) signature.
  • Auth plugin test failures — Fixed 2 tests in auth-plugin.test.ts that referenced the wrong AuthManager instance via registerService.mock.calls. Added mockClear() before local plugin init to ensure mock.calls[0] points to the correct AuthManager for the test's plugin instance.
  • SvelteKit adapter test failures — Updated test mock to include dispatch() method and aligned Metadata, Data, Error handling, and toResponse test assertions with the unified catch-all dispatch pattern used by the implementation and all other adapters (e.g. Hono). Removed obsolete handleMetadata/handleData references from the mock.
  • Vercel serverless 404 fix — The previous api/[...path].ts path-normalisation fix is now superseded by the Hono adapter migration above. The new api/index.ts entrypoint combined with Vercel rewrites (/api/*/api) eliminates the routing ambiguity that caused 404s.
  • Kernel cold-start race conditionapi/_kernel.ts uses a shared boot promise so that concurrent cold-start requests wait for the same initialisation rather than launching duplicate boot sequences. Seed-data failures are treated as non-fatal, and the broker shim is validated after bootstrap with automatic reattachment if lost.
  • Broker-resilient metadata handlerHttpDispatcher.handleMetadata() no longer requires a broker upfront. It tries the protocol service and ObjectQL registry first, falling back to the broker only when available. Serverless/lightweight setups without a full message broker now return proper metadata responses instead of throwing 500 errors.

Added

  • @objectstack/service-analytics — New multi-driver analytics service implementing IAnalyticsService. Uses a Strategy Pattern with priority-ordered chain: P1 NativeSQLStrategy (pushes queries as native SQL to Postgres/MySQL drivers), P2 ObjectQLStrategy (translates to ObjectQL aggregate() AST), P3 InMemoryStrategy (delegates to existing MemoryAnalyticsService for dev/test). Includes CubeRegistry for auto-discovery of cubes from manifest definitions and object schema inference, AnalyticsServicePlugin for kernel plugin lifecycle, generateSql() dry-run capability, and queryCapabilities() driver probing for dynamic strategy selection. 34 unit tests covering all strategy branches.
  • Studio system objects visibility — Studio now auto-registers all system objects (sys_user, sys_role, sys_audit_log, etc.) from plugin-auth, plugin-security, and plugin-audit at kernel initialization. The sidebar "System" group dynamically lists all isSystem=true objects with a collapsible "System Objects" section. A filter toggle on the Data group allows showing/hiding system objects from the main object list.
  • ObjectSchema namespace property — New optional namespace field on ObjectSchema for logical domain classification (e.g., 'sys', 'crm'). When set, tableName is auto-derived as {namespace}_{name} by ObjectSchema.create() unless an explicit tableName is provided. This decouples the logical object name from the physical table name and enables unified routing, permissions, and discovery by domain.
  • SystemObjectName constants — Extended with all system objects: ORGANIZATION, MEMBER, INVITATION, TEAM, TEAM_MEMBER, API_KEY, TWO_FACTOR, ROLE, PERMISSION_SET, AUDIT_LOG (in addition to existing USER, SESSION, ACCOUNT, VERIFICATION, METADATA).
  • plugin-auth system objects — Added SysOrganization, SysMember, SysInvitation, SysTeam, SysTeamMember, SysApiKey, SysTwoFactor object definitions with namespace: 'sys'. Existing objects (SysUser, SysSession, SysAccount, SysVerification) migrated to use namespace convention.
  • plugin-security system objects — Added SysRole and SysPermissionSet object definitions.
  • plugin-audit — New plugin package with SysAuditLog immutable audit trail object definition.
  • StorageNameMapping.resolveTableName() — Now supports namespace-aware auto-derivation ({namespace}_{name} fallback when no explicit tableName is set).

Changed

  • ObjectFilterSchema includeSystem default — Changed from false to true. Studio ObjectManager now includes system objects by default. Users can toggle visibility via the Data group filter control.
  • System object naming convention — All system objects now use namespace: 'sys' with short name (e.g., name: 'user' instead of name: 'sys_user'). The sys_ prefix is auto-derived via tableName = {namespace}_{name}. File naming follows sys-{name}.object.ts pattern.
  • plugin-auth object exports — New canonical exports use Sys* prefix (e.g., SysUser, SysSession). Legacy Auth* exports are preserved as deprecated re-exports for backward compatibility.
  • sys_metadata object — Migrated to namespace: 'sys', name: 'metadata' convention (tableName auto-derived as sys_metadata).
  • Locale code fallback — New resolveLocale() helper in @objectstack/core that resolves locale codes through a 4-step fallback chain: exact match → case-insensitive match (zh-cnzh-CN) → base language match (zh-CNzh) → variant expansion (zhzh-CN). Used by createMemoryI18n, HttpDispatcher.handleI18n(), and I18nServicePlugin route handlers.
  • Auto-detection of I18nServicePlugin — Both DevPlugin and CLI serve command now automatically detect translations/i18n config in the stack definition and register I18nServicePlugin from @objectstack/service-i18n when available. Falls back to the core in-memory i18n (with locale resolution) if the package is not installed.
  • Enhanced i18n diagnosticsAppPlugin now emits clear warnings when:
    • Translations exist but no i18n service is registered (guides user to add the plugin).
    • Translations are loaded into a fallback/stub i18n service (recommends production plugin).
  • i18n locale fallback in REST routesHttpDispatcher.handleI18n() translations and labels endpoints now resolve locale codes via fallback when exact match returns empty translations. The response includes requestedLocale when a fallback was used.

Changed

  • DevPlugin i18n stub — Replaced the duplicate createI18nStub() in DevPlugin with createMemoryI18n from @objectstack/core, ensuring locale fallback works consistently in dev mode. DevPlugin now tries I18nServicePlugin before the stub when stack has translations.
  • createMemoryI18n now uses resolveLocale() internally for t() and getTranslations(), enabling locale fallback (e.g. zhzh-CN) without any plugin changes.
  • CLI serve command now auto-registers I18nServicePlugin when config has translations/i18n, mirroring DevPlugin's auto-detection behavior for production environments.

Changed

  • i18n route self-registration — Moved i18n REST endpoint registration from RestServer to I18nServicePlugin (and kernel fallback). The i18n plugin now self-registers /api/v1/i18n/* routes via the kernel:ready hook, following the same autonomous plugin pattern used by AuthPlugin, WorkflowPlugin, and other service plugins. RestServer no longer registers or manages any i18n endpoints, keeping it strictly a protocol-driven gateway.
  • Removed enableI18n flag from RestApiConfig schema (rest-server.zod.ts) — i18n endpoints are now controlled by the i18n service plugin's own registerRoutes option (default: true).
  • Removed registerI18nEndpoints() method from RestServer class.
  • I18nServicePlugin now accepts registerRoutes and basePath options for HTTP route control.
  • i18n endpoints now work independently of RestServer, enabling MSW/mock test environments to serve i18n routes without any REST API gateway dependency.
  • Dispatcher i18n bridge routescreateDispatcherPlugin() now registers i18n HTTP route bridges (GET /i18n/locales, GET /i18n/translations/:locale, GET /i18n/labels/:object/:locale) via HttpDispatcher.handleI18n(), ensuring i18n endpoints work even when only the kernel's memory fallback i18n is active (no explicit I18nServicePlugin loaded). This is consistent with how auth, analytics, packages, storage, and automation services are bridged.

Added

  • i18n as core built-in service — The i18n service is now a core criticality service with automatic in-memory fallback. When no plugin (e.g. I18nServicePlugin) registers an i18n service, the kernel auto-injects createMemoryI18n (in-memory Map-backed II18nService implementation) during validateSystemRequirements(). This ensures /api/v1/i18n/* routes and discovery always report i18n as available, even without plugin-i18n installed.
  • createMemoryI18n fallback factory in @objectstack/core (packages/core/src/fallbacks/memory-i18n.ts) implementing II18nService contract with translation loading, dot-notation key resolution, parameter interpolation, and locale management.

Changed

  • ServiceRequirementDef.i18n upgraded from 'optional' to 'core' — kernel now warns (instead of silently ignoring) when no i18n service is registered, and auto-injects in-memory fallback.
  • SERVICE_CONFIG['i18n'].plugin in protocol.ts corrected from 'plugin-i18n' to 'service-i18n' to match the actual @objectstack/service-i18n package name.
  • Updated kernel-services.mdx documentation to reflect i18n as core/built-in capability.

Fixed

  • AppPlugin getService crash on missing servicesAppPlugin.start() and loadTranslations() now wrap ctx.getService() in try/catch, since the kernel's getService throws when a service is not registered (rather than returning undefined). This was the direct cause of plugin.app.com.example.crm failed to start — the i18n service was not registered, so getService('i18n') threw an unhandled exception.
  • CLI serve: host config AppPlugin mis-wrapserve.ts no longer wraps a host/aggregator config (one that already contains instantiated plugins in its plugins array) with an extra AppPlugin. This prevents the plugin.app.dev-workspace failed to start error and eliminates duplicate plugin registration when running pnpm dev.
  • plugin-auth CJS→ESM interop — Added module and exports fields to @objectstack/plugin-auth package.json so Node.js resolves the ESM build (.mjs) when using dynamic import(), eliminating the ExperimentalWarning: CommonJS module … is loading ES Module warning caused by better-auth being ESM-only.
  • i18n service registration & state inconsistency — Discovery API (getDiscoveryInfo) now uses the same async resolveService() fallback chain that request handlers (handleI18n) use, ensuring the reported service status is always consistent with actual runtime availability.
  • Discovery locale field is now populated from the actual i18n service (getDefaultLocale, getLocales) instead of being hardcoded, so clients get accurate locale information.
  • Updated all framework adapters (Hono, Express, Fastify, Next.js, NestJS, Nuxt, SvelteKit), the dispatcher plugin, and the MSW plugin to await the now-async getDiscoveryInfo().

Added

  • AppPlugin i18n auto-loadingAppPlugin now automatically loads translation bundles from app configs (translations array) into the kernel's i18n service during the start phase, coordinating i18n data loading across server/dev/mock environments.
  • i18n service registration guide in content/docs/guides/kernel-services.mdx documenting service registration patterns, discovery consistency, and AppPlugin auto-loading behavior.

Changed

  • Updated ROADMAP.md for v3.0 release preparation with full codebase scan results
  • Audited all @deprecated items: 14 in spec, 9 in runtime packages (23 total)
  • Identified stale deprecation notices targeting v2.0.0 (current: v2.0.7)
  • Updated metrics: 172 schema files, 191 test files, 5,165 tests, 7,095 .describe() annotations

Deprecated

  • The following items are scheduled for removal in v3.0.0 (see packages/spec/V3_MIGRATION_GUIDE.md):
    • Hub.* barrel re-exports from hub/index.ts
    • location (singular) on ActionSchema — use locations (array)
    • definePlugin() in spec — will move to @objectstack/core
    • createErrorResponse() / getHttpStatusForCategory() in spec — will move to @objectstack/core
    • RateLimitSchema, RealtimePresenceStatus, RealtimeAction aliases
    • Event bus helper functions (createDefaultEventBusConfig, createDefaultDLQConfig, createDefaultEventHandlerConfig)
    • HttpDispatcher class in @objectstack/runtime
    • createHonoApp() in @objectstack/hono

2.0.7 - 2026-02-11

Added

  • Modularized kernel/events.zod.ts (765 lines) into 6 focused sub-modules for better tree-shaking:
    • events/core.zod.ts: Priority, metadata, type definition, base event
    • events/handlers.zod.ts: Event handlers, routes, persistence
    • events/queue.zod.ts: Queue config, replay, sourcing
    • events/dlq.zod.ts: Dead letter queue, event log entries
    • events/integrations.zod.ts: Webhooks, message queues, notifications
    • events/bus.zod.ts: Complete event bus config and helpers
  • Created v3.0 migration guide (packages/spec/V3_MIGRATION_GUIDE.md)

Changed

  • kernel/events.zod.ts now re-exports from sub-modules (backward compatible)
  • Updated all packages to version 2.0.7 with unified versioning

2.0.6 - 2026-02-11

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 2.0.6 with unified versioning

2.0.5 - 2026-02-10

Changed

  • Unified all package versions to 2.0.5
  • Added @objectstack/plugin-auth and @objectstack/plugin-security to the changeset fixed versioning group
  • All packages now release together under the same version number

2.0.4 - 2026-02-10

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 2.0.4 with unified versioning

2.0.3 - 2026-02-10

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 2.0.3 with unified versioning

2.0.2 - 2026-02-10

Changed

  • Exclude generated JSON schema files from git tracking
  • Add packages/spec/json-schema/ to .gitignore (1277 generated files, 5MB)
  • JSON schema files are still generated during pnpm build and included in npm publish
  • Fix studio module resolution logic for better compatibility
  • Updated all packages to version 2.0.2 with unified versioning

2.0.1 - 2026-02-09

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 2.0.1 with unified versioning

0.9.1 - 2026-02-03

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 0.9.1 with unified versioning

0.9.0 - 2026-02-03

Changed

  • Minor version bump for new features and improvements
  • All packages updated to version 0.9.0

0.8.2 - 2026-02-02

Changed

  • BREAKING: Removed view-storage.zod.ts and ViewStorage related types from @objectstack/spec
  • BREAKING: Removed createView, updateView, deleteView, listViews from ObjectStackProtocol interface
  • BREAKING: Removed in-memory View Storage implementation from @objectstack/objectql
  • Updated @objectstack/plugin-msw to dynamically load @objectstack/objectql to avoid hard dependencies

0.8.1 - 2026-02-01

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 0.8.1

0.8.0 - 2026-02-01

Changed

  • Upgrade to Zod v4 and protocol improvements
  • Aligned all protocol definitions with stricter type safety
  • Updated all packages to version 0.8.0

0.7.2 - 2026-01-31

Changed

  • Updated system protocol JSON schemas (events, worker, metadata-loader)
  • Enhanced documentation structure for system protocols
  • Generated comprehensive JSON schema documentation

0.7.1 - 2026-01-31

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 0.7.1

0.6.1 - 2026-01-28

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 0.6.1

0.4.1 - 2026-01-27

Fixed

  • Synchronized plugin-msw version to 0.4.1 (was incorrectly at 0.3.3)
  • Updated runtime peer dependency versions to ^0.4.1 across all plugins
  • Fixed internal dependency version mismatches

0.4.0 - 2026-01-26

Changed

  • Updated all core packages to version 0.4.0

0.3.3 - 2026-01-25

Changed

  • Enhanced GitHub workflows for CI, release, and PR automation
  • Added comprehensive prompt templates for different protocol areas
  • Improved project documentation and automation guides
  • Updated changeset configuration
  • Added cursor rules for better development experience
  • Updated all packages to version 0.3.3

0.3.2 - 2026-01-24

Changed

  • Patch release for maintenance and stability improvements
  • Updated all packages to version 0.3.2

0.3.1 - 2026-01-23

Changed

  • Organized zod schema files by folder structure
  • Improved project documentation

0.3.0 - 2026-01-22

Added

  • Comprehensive documentation structure with CONTRIBUTING.md
  • Documentation hub at docs/README.md
  • Standards documentation (naming-conventions, api-design, error-handling)
  • Architecture deep dives (data-layer, ui-layer, system-layer)
  • Code of Conduct
  • Changelog template
  • Migration guides structure
  • Security and performance guides

Changed

  • Updated README.md with improved documentation navigation
  • Enhanced documentation organization following industry best practices
  • All packages now use unified versioning (all packages released together with same version number)

0.1.1 - 2026-01-20

Added

  • Initial protocol specifications
  • Zod schemas for data, UI, system, AI, and API protocols
  • JSON schema generation
  • Basic documentation site with Fumadocs
  • Example implementations (CRM, Todo)

Template for Future Releases

## [X.Y.Z] - YYYY-MM-DD

### Added
- New features or capabilities

### Changed
- Changes to existing functionality

### Deprecated
- Features that will be removed in upcoming releases

### Removed
- Features that have been removed

### Fixed
- Bug fixes

### Security
- Security-related changes

How to Use This Changelog

For Contributors

When making changes:

  1. Add entries under [Unreleased] section
  2. Choose the appropriate category: Added, Changed, Deprecated, Removed, Fixed, Security
  3. Write clear, concise descriptions of your changes
  4. Link to PRs or issues where applicable: - Feature description (#PR_NUMBER)

Example:

### Added
- New encrypted field type for sensitive data (#123)
- Support for PostgreSQL window functions in query protocol (#124)

### Fixed
- Validation error when using lookup fields with filters (#125)

For Maintainers

When releasing a new version:

  1. Create a new version section from the [Unreleased] content
  2. Move entries from [Unreleased] to the new version section
  3. Add release date in YYYY-MM-DD format
  4. Tag the release in git: git tag -a v0.2.0 -m "Release v0.2.0"
  5. Update links at the bottom of the file

Versioning Guide

Following Semantic Versioning:

  • MAJOR version (X.0.0): Incompatible API changes
  • MINOR version (0.X.0): Add functionality in a backward compatible manner
  • PATCH version (0.0.X): Backward compatible bug fixes

Categories

  • Added: New features, protocols, schemas, or capabilities
  • Changed: Changes to existing functionality
  • Deprecated: Features marked for removal (but still working)
  • Removed: Features that have been removed
  • Fixed: Bug fixes
  • Security: Security vulnerability fixes or improvements

Breaking Changes

Mark breaking changes clearly:

### Changed
- **BREAKING**: Renamed `maxLength` to `maxLen` in FieldSchema (#126)
  Migration: Update all field definitions to use `maxLen` instead of `maxLength`

Release Process

  1. Update CHANGELOG.md with release notes
  2. Update version in package.json files
  3. Run pnpm changeset version to update package versions
  4. Commit changes: git commit -m "chore: release vX.Y.Z"
  5. Create git tag: git tag -a vX.Y.Z -m "Release vX.Y.Z"
  6. Push: git push && git push --tags
  7. Run pnpm release to publish packages