| title | v9.0.0 |
|---|---|
| description | Analytics single-form cutover (ADR-0021), honest chart taxonomy, canonical OS_* settings env vars, Google sign-in, and a smarter AI build experience in Console. |
Released June 10, 2026. All @objectstack/* packages are published at 9.0.0. This is a major
release: the analytics authoring surface completes its cutover to the dataset
semantic layer, the chart taxonomy is trimmed to what actually renders, and
settings environment variables move to their canonical OS_* form.
TL;DR for upgraders: if your app defines dashboards, reports, or list
charts with inline queries (object + aggregate + field names), you must
migrate them to named datasets. If you configure settings via environment
variables, rename them to OS_<NAMESPACE>_<KEY>. Everything else is additive.
The inline analytics author surface is removed from @objectstack/spec. Every
dashboard widget, report, and list chart must now bind a semantic dataset
and select dimensions/measures by name. Define a metric once, reference it
everywhere.
Removed from the spec:
| Schema | Removed properties | Now required |
|---|---|---|
DashboardWidget |
object, categoryField, categoryGranularity, valueField, aggregate, measures (and the WidgetMeasure type) |
dataset + values |
Report |
top-level and joined-block objectName, columns, groupingsDown, groupingsAcross, filter |
dataset + values (rows are the dimensions) |
ListChart |
xAxisField, yAxisFields, aggregation, groupByField |
dataset + values |
Migration:
- For each inline query, create a dataset with
defineDataset(...)declaring its dimensions and measures. See the Analytics Datasets guide. - Point the widget/report/chart at it:
dataset: "<name>", pickvalues(measure names) anddimensions/rows(dimension names). - Presentation-scope filtering goes through the widget's
filter, which is applied as the dataset'sruntimeFilter. - A flat record listing (the former
tabularreport or inline list) is not an analytics dataset — model it as an object-bound ListView (ADR-0017).
Eight chart types that only ever rendered as their base chart are removed, so the taxonomy no longer advertises variants the renderer doesn't draw. Update any widget or series using a removed type to its base:
| Removed type | Use instead |
|---|---|
grouped-bar, stacked-bar, bi-polar-bar |
bar |
stacked-area |
area |
step-line, spline |
line |
pyramid |
funnel |
bubble |
scatter |
Kept: bar / horizontal-bar / column, line / area, pie / donut /
funnel, scatter, treemap / sankey, radar, table / pivot, and the
single-value performance family (metric / kpi / gauge / solid-gauge /
bullet). Removed variants can return behind an opt-in renderer once a real
renderer and data model back them.
@objectstack/service-settings no longer accepts unprefixed aliases for
settings-namespace environment overrides. Rename your deployment variables:
| Before | After |
|---|---|
AI_OPENAI_BASE_URL (or ai.openai_base_url) |
OS_AI_OPENAI_BASE_URL |
FEATURE_FLAGS_AI_ENABLED |
OS_FEATURE_FLAGS_AI_ENABLED |
The general rule: OS_ + namespace + key, upper-snake-cased. See the
Environment Variables guide.
The package authored BPMN-style workflow shapes the ObjectStack automation
engine does not execute (ADR-0020, ADR-0031). If you imported it in a custom
UI, the replacements ship already: flow authoring is the metadata-admin
FlowCanvas (engine-registry-driven palette) in @object-ui/app-shell, run
history is FlowRunsPanel, and approval UI comes from the framework's
@objectstack/plugin-approvals.
Three @objectstack/service-analytics improvements make charts and reports
human-readable with no frontend work:
- Dimension display labels. A
selectdimension shows its option label (Backlog, notbacklog); alookup/master_detaildimension shows the related record's display name instead of its foreign-key id. Resolution happens server-side inqueryDataset. - Date dimensions bucket and format by granularity. A monthly trend chart
now yields one point per month with sort-stable labels (
2026,2026-Q2,2026-04) — no more raw epoch milliseconds on the axis. - Measure label and format travel with the result.
AnalyticsResult.fields[]gains optionallabelandformat, so a chart can display "Tasks" and "$616,000" while keeping raw numbers for plotting.
Two reliability upgrades to @objectstack/service-automation's durable pause
(ADR-0019):
- Nested durable pause. A pausing node (approval, screen, wait) inside a subflow used to fail the parent run. The whole chain now suspends as linked runs: the child's screen surfaces through the parent, resume signals delegate down to the suspended child, and a completed child auto-resumes its parent.
- Wait timers re-arm after a cold boot. A timer
waitscheduled its wake-up in process memory, so a restart left the suspended run paused forever. The wake deadline is now persisted with the run; on boot the service resumes overdue runs immediately and re-schedules future ones.
Whether a seed draft's rows actually materialized used to depend on which
route you published through — the per-ref publish (used by the Studio home
banner) never applied them, yielding "Published!" with empty tables. Seed
application now lives in the protocol itself (@objectstack/objectql), so
every publish path converges on it and reports the outcome under
seedApplied. A seed problem never fails the publish.
ToolExecutionContext.onProgress(part) lets a long-running tool report
progress before it returns, emitted as custom data-* parts on the UI message
stream (this is what powers the live build tree in Console's Build-with-AI).
Existing tools that never emit behave exactly as before.
@objectstack/plugin-auth binds the auth settings namespace to better-auth
runtime configuration and exposes an extension hook for provider packages.
Google sign-in works out of the box — configure it in Setup →
Authentication or via deployment-level GOOGLE_CLIENT_ID /
GOOGLE_CLIENT_SECRET. See Auth & SSO.
The CLI ships @ai-sdk/openai, @ai-sdk/anthropic, and @ai-sdk/google as
direct dependencies. These were previously only optional peer dependencies of
@objectstack/service-ai, so a globally-installed CLI couldn't resolve them at
runtime — configuring an OpenAI-compatible provider (DeepSeek, DashScope,
SiliconFlow, OpenRouter, Cloudflare, which all normalize to provider=openai
and dynamically import @ai-sdk/openai) failed with "Could not build adapter
for provider=…". Bundling them makes those providers work out of the box.
Note: later releases moved the provider SDKs back to a host-install model — in the current CLI they are not bundled. The
aisettings namespace states that provider SDK packages (e.g.@ai-sdk/openai) must be installed on the host for the chosen provider to load, and the AI runtime runs through the host-declared@objectstack/service-aiplugin, which auto-detects the provider from environment variables (AI_GATEWAY_MODEL,OPENAI_API_KEY, …).
The Console build frozen into @objectstack/console 9.0.0 picks up the
dataset cutover end-to-end, plus a round of AI-builder and designer
improvements:
- Dataset widgets render as their true chart type — pie, donut, funnel, line, area, scatter, radar, treemap, sankey, table, and pivot all route to their real renderer, and metric cards display the measure's label and format.
- Reports render the dataset form (ADR-0021), including matrix and joined variants; widget filters apply as dataset runtime filters.
- Flow designer aligned with the engine vocabulary, with a runs panel for inspecting executions; toolbar flow/script actions now resolve the selected record correctly.
- Build-with-AI: a live build tree streams progress while the agent scaffolds an app, finished apps can auto-publish in chat, seed-data results are surfaced, and the consumer panel no longer dumps raw tool JSON.
- Marketplace: when cloud-bound, the Installed view shows what Cloud has installed into the environment (see the Cloud section below).
- Forms: conditional rules in inline grids can now reference parent-record
fields (
parent.<field>scope). - Pages:
PageViewgains a console action runtime, so page-embedded actions behave like their grid/detail counterparts. - Charts: crowded bar-chart x-axis labels angle and truncate instead of overlapping.
ObjectStack Cloud versions independently of this release train and deploys continuously; developer-facing changes are summarized here when a framework release lands.
The deployment story for cloud-bound apps is now publish, then install:
os package publish puts a package version in the cloud catalog, and you
install it into an environment from that environment's Marketplace in
Console — installing is an explicit step, no longer a side effect of a publish
flag. The environment's Installed view reflects what Cloud has installed,
so packages installed via the CLI show up there too.
Coming in the next framework release: published packages default to organization visibility, so they appear in your own environments' Marketplace immediately, with private visibility reserved for targeted distribution.
- Publishing pending drafts by ref so package-less drafts can't get stuck in the metadata-admin publish queue.
- New projects scaffolded by
create-objectstackstart cleanly under pnpm. - Setup → System Settings menu labels and pages are fully translated.
FlowRunnercloses cleanly when a terminal resume fails instead of leaving a dead dialog.- The AI service treats a stored or env-locked
provider=memoryas an explicit override, while manifest defaults keep boot-time provider auto-detection intact.
- Update all
@objectstack/*dependencies to^9.0.0(they are version-locked — upgrade them together). - Migrate inline dashboard widgets, reports, and list charts to named datasets (guide).
- Replace removed chart types with their base family (table above).
- Rename settings env vars to the
OS_<NAMESPACE>_<KEY>form. - Re-run your app's spec validation (
os validate) — it will flag any metadata still using removed properties.