Skip to content

feat(cli): make the AI service opt-in via a declared dependency (Community-Edition support)#2311

Merged
os-zhuang merged 2 commits into
mainfrom
feat/ce-ai-opt-in
Jun 25, 2026
Merged

feat(cli): make the AI service opt-in via a declared dependency (Community-Edition support)#2311
os-zhuang merged 2 commits into
mainfrom
feat/ce-ai-opt-in

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Why

A self-host Community Edition runtime (framework + the MIT console, without the cloud AI package) should serve no AI but still support MCP. Today it can't: the CLI auto-registers the headless AIServicePlugin whenever the ai tier is enabled (default) and @objectstack/service-ai is merely resolvable. In a workspace/monorepo the package is hoist-resolvable even when an app doesn't declare it, so every app gets the AI service — discovery reports services.ai: available and the agent runtime serves any metadata-defined agents — even CE apps that ship no AI.

(Surfaced from the objectui side: the console gates its AI UI on the live agent catalog, but a CE runtime still reported services.ai available with agents served, so the AI surface didn't hide.)

What

1. AI is opt-in via a declared dependency (packages/cli/src/commands/serve.ts). Auto-register the AI service only when the host app declares @objectstack/service-ai or @objectstack/service-ai-studio — gating on a declared dep, not mere resolvability, so it's reliable in a monorepo.

const wantsAiService =
  hostDeclaresDependency('@objectstack/service-ai')
  || hostDeclaresDependency('@objectstack/service-ai-studio');
if (!hasAIPlugin && tierEnabled('ai') && wantsAiService) {  }
  • CE app declares neither → no AI service, no agents, services.ai: { enabled:false, status:'unavailable' } → the console hides its AI surface.
  • MCP unaffected — separate capability (requires: ['mcp']), no service-ai dependency, bridges data/metadata regardless; only optionally bridges the AI tool registry when the ai service is present.
  • Cloud path fixed — AI Studio attaches personas via the base service's ai:ready hook, so declaring Studio now implies (and loads) the base service. Previously a Studio-only app would have loaded neither.
  • app-showcase/app-crm now declare @objectstack/service-ai (they ship AI agents).

For real standalone apps (outside this monorepo) this is a no-op — they already had to declare deps to resolve them. Only in-monorepo apps relying on hoisting were affected (the two examples, now fixed).

2. config.tiers is now honored (packages/spec/src/stack.zod.ts). ObjectStackDefinitionSchema gains a tiers field, so defineStack no longer strips it. config.tiers (e.g. a list without ai) now actually overrides the --preset default — previously silently dropped by schema validation, which made the --preset help text ("overridden by config.tiers if set") inaccurate. A second, in-place way to disable AI without touching dependencies.

Verified end-to-end (isolated build, fresh runtime)

Scenario services.ai /api/v1/ai/agents AIService MCP
CE — declares neither enabled:false, "unavailable" 404 not loaded loads + serves (OS_MCP_SERVER_ENABLED=true401 auth-gate = live)
declares service-ai enabled:true, "available" serves showcase_assistant loaded
declares only service-ai-studio enabled:true, "available" 200 loaded (base, for ai:ready)
config.tiers without ai (service-ai declared) enabled:false, "unavailable" 404 not loaded (tier wins)

@objectstack/cli + @objectstack/spec build clean (tsc). Changeset included (both minor).

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 25, 2026 2:30am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tooling labels Jun 25, 2026
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cli, @objectstack/runtime, @objectstack/spec.

100 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/cli, packages/runtime, packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/cli, @objectstack/runtime, @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/cli, @objectstack/runtime, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/authentication.mdx (via @objectstack/cli, @objectstack/runtime)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/cloud-deployment.mdx (via @objectstack/runtime)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/external-datasources.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/cli, @objectstack/runtime, packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/cli, @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/plugin-chatbot-integration.mdx (via @objectstack/runtime)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/spec)
  • content/docs/guides/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/guides/project-scoping.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/cli, packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/guides/skills.mdx (via packages/cli, @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/guides/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…nor config.tiers)

The CLI auto-registered the headless AIServicePlugin whenever the `ai` tier was
enabled (default) and @objectstack/service-ai was merely *resolvable*. In a
workspace/monorepo the package is hoist-resolvable even when an app doesn't
declare it, so every app got the AI service — discovery reported services.ai
available and the agent runtime served any metadata-defined agents — including
Community-Edition apps that ship no AI.

Make the DECLARED dependency the AI edition boundary: auto-register AIService
only when the host app declares @objectstack/service-ai OR
@objectstack/service-ai-studio (Studio attaches its personas via the base
service's `ai:ready` hook, so declaring Studio implies the base — load it even
when only Studio is in the deps). A CE app that declares neither gets no AI
service, no agents, and services.ai { enabled:false, status:'unavailable' } in
discovery — so the MIT console hides its AI surface — while MCP and every other
capability are unaffected.

Also honor `config.tiers`: ObjectStackDefinitionSchema gains a `tiers` field so
defineStack stops stripping it. `config.tiers` (e.g. a list without `ai`) now
actually overrides the `--preset` default — previously silently dropped by schema
validation, which made the `--preset` help text inaccurate. A second, in-place
lever to disable AI without touching dependencies.

Declare @objectstack/service-ai in the showcase and crm examples (they ship AI
agents) so they keep AI.

Verified e2e in an isolated build:
- app WITHOUT service-ai/studio → discovery AI unavailable, /api/v1/ai/agents
  404, AIService not loaded; MCP server still starts + serves (401 auth-gate).
- app declaring service-ai (or studio-only) → services.ai available + agents served.
- config.tiers without `ai` → AIService not loaded even when service-ai IS declared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang
os-zhuang force-pushed the feat/ce-ai-opt-in branch from 766452a to 91f6252 Compare June 25, 2026 02:00
@os-zhuang os-zhuang changed the title feat(cli): make the AI service opt-in via a declared @objectstack/service-ai dependency (Community-Edition support) feat(cli): make the AI service opt-in via a declared dependency (Community-Edition support) Jun 25, 2026
runtime/security/api-key.ts re-exports @objectstack/core's extractApiKey, which
accepts a Bearer token carrying the `osk_` api-key prefix (for remote MCP
clients — core's own test covers this). This duplicate test in runtime predated
that behavior and asserted the old "Bearer is never an api-key" rule, so it
failed whenever runtime's tests run.

It was latent on main: turbo only runs runtime's tests when runtime or a
dependency changes, and main's recent commits didn't. This PR's
@objectstack/spec change makes spec "changed", so every spec-dependent package's
tests now run — surfacing the pre-existing failure. Align the assertion with
core + the implementation (extractApiKey is re-exported, so they must agree).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added tests and removed tests labels Jun 25, 2026
@os-zhuang
os-zhuang merged commit 4845c12 into main Jun 25, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the feat/ce-ai-opt-in branch June 25, 2026 02:39
os-zhuang added a commit to objectstack-ai/objectui that referenced this pull request Jun 25, 2026
…he agent catalog (#1992)

useAiSurfaceEnabled now keys off discovery's `services.ai` (isAiEnabled) — i.e.
whether the enterprise @objectstack/service-ai capability is present — instead of
a non-empty agent catalog.

service-ai is an enterprise capability; a Community-Edition runtime doesn't ship
it, so the framework doesn't register the AI service and discovery reports
services.ai unavailable → the whole AI surface hides. An install that has
service-ai reports it available → AI shows. The presence of the CAPABILITY gates,
not whether a specific agent is configured yet.

The earlier catalog-based gating was a workaround for the headless service-ai
reporting itself available in CE. The framework now only registers the AI service
when the host app declares @objectstack/service-ai (objectstack-ai/framework#2311),
so discovery is an honest edition signal and the catalog detour is gone.

Everything else from the original gating stays: the centralized hook, the
RequireAiSurface /ai route guard, the gated top-bar link + designer "Ask AI"
buttons, and AiChatPage's graceful empty state.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 25, 2026
…ability) (#2317)

* chore: bump objectui to 8a3b351a5a32

fix(console): gate the AI surface on the service-ai capability, not the agent catalog (#1992)

objectui@8a3b351a5a320e6769a1616e85a6fd05aabd3279

* chore(showcase): remove the AI agent — service-ai is an enterprise capability

The showcase defined a `showcase_assistant` agent + a skill + two tools, all of
which need the enterprise `@objectstack/service-ai` runtime to be served. The
open-source showcase shouldn't require an enterprise capability, so drop the AI
block entirely:

- delete `src/agents/index.ts` (agent + skill + tools) and its config wiring
  (`agents` / `skills` / `tools`);
- remove the `@objectstack/service-ai` dependency (added in #2311 to back the
  agent — no longer needed);
- drop the descriptive `ai` entry from the coverage map and update the seed test
  (`agents.length` 1 → 0).

The showcase now boots as a Community-Edition shape: no AI service is registered,
discovery reports `services.ai` unavailable, and `/api/v1/ai/agents` 404s — so
the console hides its AI surface. `tsc --noEmit` + all 39 showcase tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 25, 2026
…ity (#2319)

Mirror the showcase change (#2317): the open-source CRM example shouldn't define
an AI agent that requires the enterprise @objectstack/service-ai runtime.

- delete src/agents/ (SalesAssistantAgent + DealManagementSkill + LookupContactTool)
  and its config wiring (agents / skills) plus the unused referenceMetadata export;
- remove the @objectstack/service-ai dependency (added in #2311 to back the agent).

crm now boots as a Community-Edition shape: no AI service registered, discovery
reports services.ai unavailable, /api/v1/ai/agents 404. tsc --noEmit + all 29 crm
tests pass.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 6, 2026
fix(components): also toast form submit errors so they're visible past the fold (#2311)

objectui@ffad2a13790c589de88323b932617a2cba93129c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant