Skip to content

Commit e056c83

Browse files
committed
feat(cloud): rename ProjectStack to RuntimeStack and update configurations for cloud-connected runtime mode
1 parent 6e604a1 commit e056c83

9 files changed

Lines changed: 89 additions & 46 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11-
- **ObjectOS Cloud Runtime mode (default)** — `apps/server` (and any host using `createBootStack`) now boots `project` mode through ObjectStack Cloud (`https://cloud.objectstack.ai` by default) instead of an embedded control-plane DB. The cloud URL is configurable via `OBJECTSTACK_CLOUD_URL` (or `project.cloudUrl` in `objectstack.config.ts`); auth via `OBJECTSTACK_CLOUD_API_KEY` / `project.cloudApiKey`. To opt out and run against a local `control.db` (legacy single-machine dev), set `OBJECTSTACK_CLOUD_URL=local`. New building blocks in `@objectstack/service-cloud`: `ArtifactApiClient` (TTL-cached HTTP client for `GET /api/v1/cloud/resolve-hostname` and `GET /api/v1/cloud/projects/:id/artifact`), `ArtifactEnvironmentRegistry` (replaces `DefaultEnvironmentDriverRegistry` — resolves hostnames over HTTP, falls back to the artifact's default datasource when no runtime block is supplied), and `ArtifactKernelFactory` (boots a kernel directly from `artifact.metadata` with `DriverPlugin + ObjectQLPlugin + MetadataPlugin + AppPlugin`, no `ControlPlaneProxyDriver`). Closes the "Artifact API loader + local cache durability" item under §7 Missing in the North Star.
11+
- **`OBJECTSTACK_MODE=runtime` (renamed from `project`)** — The cloud-connected runtime node mode is now called **`runtime`**, better describing its role as a kernel runtime that pulls metadata from a control plane (instead of hosting its own). The previous mode name `project` is preserved as a deprecated alias (warns at boot). The `BootStackConfig.runtime` config field replaces `BootStackConfig.project`; the old field name is still accepted with a deprecation. **The default `OBJECTSTACK_MODE` also changes from `project` to `standalone`** — the safer, zero-config baseline (runtime-only ObjectQL + REST + Driver). Hosts that want the runtime node behavior must now opt in explicitly with `OBJECTSTACK_MODE=runtime`.
12+
- **`OBJECTSTACK_CLOUD_URL` defaults to local `apps/cloud` (`http://localhost:4000`)** — The runtime mode's default control-plane URL is now the local `apps/cloud` instance, not the hosted `https://cloud.objectstack.ai`. `apps/cloud`'s `dev` / `start` scripts now bind to port 4000 by default (override via `PORT`). Dev workflow: start `apps/cloud` first, then start `apps/server` in runtime mode against it. For the hosted control plane, set `OBJECTSTACK_CLOUD_URL=https://cloud.objectstack.ai`. To disable cloud routing entirely and boot from a local `control.db`, set `OBJECTSTACK_CLOUD_URL=local`.
13+
- **ObjectOS Cloud Runtime building blocks (`@objectstack/service-cloud`)**`ArtifactApiClient` (TTL-cached HTTP client for `GET /api/v1/cloud/resolve-hostname` and `GET /api/v1/cloud/projects/:id/artifact`), `ArtifactEnvironmentRegistry` (replaces `DefaultEnvironmentDriverRegistry` — resolves hostnames over HTTP, falls back to the artifact's default datasource when no runtime block is supplied), and `ArtifactKernelFactory` (boots a kernel directly from `artifact.metadata` with `DriverPlugin + ObjectQLPlugin + MetadataPlugin + AppPlugin`, no `ControlPlaneProxyDriver`). Auth via `OBJECTSTACK_CLOUD_API_KEY` / `runtime.cloudApiKey`. Closes the "Artifact API loader + local cache durability" item under §7 Missing in the North Star.
1214

1315
### Changed
1416
- **`OBJECTSTACK_MODE` redefined into three values** — Boot-mode selection now accepts `project` (default), `cloud`, and `standalone`. The previous semantics — where `standalone` meant "single-project local dev with full Auth + Studio" — moved under `project`. The new `standalone` value is **runtime-only**: ObjectQL + REST + Driver, no Auth, no control plane, no Studio data. Designed for embedding ObjectStack in other frameworks. Aliases `local` / `single-project` continue to map to `project`; `multi-project` continues to map to `cloud`. Default also changed: an unset `OBJECTSTACK_MODE` now resolves to `project` (was: `standalone`).

apps/cloud/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"type": "module",
66
"private": true,
77
"scripts": {
8-
"dev": "objectstack dev",
8+
"dev": "PORT=${PORT:-4000} objectstack dev",
99
"build": "tsup",
10-
"start": "objectstack serve dist/objectstack.config.js --prebuilt",
10+
"start": "PORT=${PORT:-4000} objectstack serve dist/objectstack.config.js --prebuilt",
1111
"doctor": "objectstack doctor",
1212
"typecheck": "tsc --noEmit",
1313
"test": "objectstack test",

apps/server/objectstack.config.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

33
/**
4-
* ObjectStack Server — Host Configuration (local)
4+
* ObjectStack Server — Host Configuration (runtime node)
55
*
66
* Booted by `objectstack dev` / `objectstack serve` (see `package.json`).
77
*
88
* ## Boot modes
99
*
10-
* Selected via the `OBJECTSTACK_MODE` environment variable:
10+
* Selected via the `OBJECTSTACK_MODE` environment variable. Default:
11+
* `standalone`.
1112
*
12-
* - `project` (default) — local single-project deployment. Reuses the
13-
* cloud (multi-project) plugin stack but backs
14-
* it with two SQLite files (`control.db` for
15-
* the control plane, `proj_local.db` for the
16-
* single project's business data).
17-
* Aliases: `local`, `single-project`.
18-
* - `standalone` — runtime-only (ObjectQL + REST + Driver).
13+
* - `standalone` (default) — Runtime-only (ObjectQL + REST + Driver).
14+
* Single artifact, no control plane, no
15+
* auth. Best for embedding ObjectStack into
16+
* another framework or running headless.
17+
* - `runtime` — Cloud-connected runtime node. Resolves
18+
* projects by hostname against ObjectStack
19+
* Cloud (`apps/cloud` on
20+
* `http://localhost:4000` by default — start
21+
* that service first) and boots per-project
22+
* kernels from artifacts pulled over HTTP.
23+
* Override the cloud URL via
24+
* `OBJECTSTACK_CLOUD_URL`. Set it to
25+
* `local` for the legacy two-SQLite shape
26+
* (`control.db` + `proj_local.db`).
27+
* Aliases: `project`, `local`,
28+
* `single-project` (deprecated).
1929
*
20-
* The `cloud` (multi-project, hosted) mode lives in `apps/cloud`.
30+
* The `cloud` (multi-project control plane) mode lives in `apps/cloud`.
2131
*
22-
* All boot orchestration now lives in @objectstack/service-cloud.
23-
* This file only supplies the apps/server-specific knobs (filesystem
24-
* app bundle resolution).
32+
* All boot orchestration lives in `@objectstack/service-cloud`. This
33+
* file only supplies the apps/server-specific knobs (filesystem app
34+
* bundle resolution).
2535
*/
2636

2737
import { resolve as resolvePath, dirname } from 'node:path';
@@ -35,13 +45,14 @@ const localArtifactPath = process.env.OBJECTSTACK_ARTIFACT_PATH
3545
?? resolvePath(serverDir, 'dist/objectstack.json');
3646

3747
const config = await createBootStack({
38-
project: {
48+
runtime: {
3949
dataDir,
4050
artifactPath: localArtifactPath,
4151
appBundles: createFsAppBundleResolver(),
42-
// ObjectStack Cloud runtime is the default; set
43-
// `OBJECTSTACK_CLOUD_URL=local` to fall back to a local control
44-
// DB for offline / single-machine development.
52+
// Default: connect to the local apps/cloud (port 4000). Override
53+
// with `OBJECTSTACK_CLOUD_URL=https://cloud.objectstack.ai` for
54+
// the hosted control plane, or `OBJECTSTACK_CLOUD_URL=local` to
55+
// fall back to a single-machine `control.db` shape.
4556
cloudUrl: process.env.OBJECTSTACK_CLOUD_URL,
4657
cloudApiKey: process.env.OBJECTSTACK_CLOUD_API_KEY,
4758
},

packages/cli/src/commands/serve.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,17 @@ export default class Serve extends Command {
175175
throw new Error(`No default export found in ${args.config}`);
176176
}
177177

178-
// Project mode is the canonical OS dev workflow. Every bare
178+
// Standalone is the default OS dev workflow. Every bare
179179
// `defineStack()` is booted via `@objectstack/service-cloud`'s
180-
// `createBootStack()` (project / cloud / standalone are selected
181-
// by `OBJECTSTACK_MODE`, default `project`). Set
180+
// `createBootStack()` (runtime / cloud / standalone selected by
181+
// `OBJECTSTACK_MODE`, default `standalone`). Set
182182
// `OBJECTSTACK_MODE=off` to fall back to the legacy lightweight
183183
// assembler.
184184
if (shouldBootWithLibrary(config)) {
185185
const { createBootStack } = await import('@objectstack/service-cloud');
186186
const bootResult = await createBootStack({
187187
mode: config.bootMode,
188-
project: config.project,
188+
runtime: config.runtime ?? config.project,
189189
cloud: config.cloud,
190190
standalone: config.standalone,
191191
});

packages/cli/src/utils/plugin-detection.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ export function isHostConfig(config: any): boolean {
3434
* `@objectstack/service-cloud/boot-env`.
3535
*/
3636
const RECOGNISED_MODES = new Set([
37-
'project',
37+
'runtime',
3838
'cloud',
3939
'standalone',
40+
// Deprecated aliases (kept for back-compat — emit a console warning at boot).
41+
'project',
4042
'local',
4143
'single-project',
4244
'multi-project',
@@ -47,7 +49,7 @@ export function shouldBootWithLibrary(config: any): boolean {
4749
const mode = process.env.OBJECTSTACK_MODE?.trim().toLowerCase();
4850
if (mode === 'off' || mode === 'none' || mode === 'legacy') return false;
4951
if (mode && !RECOGNISED_MODES.has(mode)) {
50-
console.warn(`[objectstack] Unknown OBJECTSTACK_MODE=${mode}; falling back to project mode.`);
52+
console.warn(`[objectstack] Unknown OBJECTSTACK_MODE=${mode}; falling back to standalone mode.`);
5153
}
5254
if (config?.bootMode === 'off') return false;
5355
return true;

packages/services/service-cloud/src/boot-stack.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import { z } from 'zod';
1414
import { resolveMode, resolveAuthSecret, resolveBaseUrl } from './boot-env.js';
1515
import type { BootMode } from './boot-env.js';
16-
import { createProjectStack, ProjectStackConfigSchema } from './project-stack.js';
16+
import { createRuntimeStack, RuntimeStackConfigSchema } from './runtime-stack.js';
1717
import { createStandaloneStack, StandaloneStackConfigSchema } from './standalone-stack.js';
1818
import { createCloudStack } from './cloud-stack.js';
1919
import type { CloudStackConfig } from './cloud-stack.js';
@@ -35,9 +35,14 @@ const CloudStackConfigSchema = z.object({
3535

3636
export const BootStackConfigSchema = z.object({
3737
/** Explicit mode override. When unset, resolves from env. */
38-
mode: z.enum(['project', 'cloud', 'standalone']).optional(),
39-
/** Project-mode options (used when mode resolves to `project`). */
40-
project: ProjectStackConfigSchema.optional(),
38+
mode: z.enum(['runtime', 'cloud', 'standalone', 'project']).optional(),
39+
/** Runtime-mode options (used when mode resolves to `runtime`). */
40+
runtime: RuntimeStackConfigSchema.optional(),
41+
/**
42+
* @deprecated Use `runtime`. Kept for back-compat with hosts that
43+
* already pass `project: { … }` to `createBootStack()`.
44+
*/
45+
project: RuntimeStackConfigSchema.optional(),
4146
/** Cloud-mode options (used when mode resolves to `cloud`). */
4247
cloud: CloudStackConfigSchema.optional(),
4348
/** Standalone-mode options (used when mode resolves to `standalone`). */
@@ -57,11 +62,18 @@ export interface BootStackResult {
5762
* Selection precedence:
5863
* 1. `config.mode` (explicit override)
5964
* 2. `OBJECTSTACK_MODE` environment variable
60-
* 3. Default: `'project'`
65+
* 3. Default: `'standalone'`
66+
*
67+
* Note: `'project'` is accepted as a deprecated alias for `'runtime'`
68+
* (renamed v4.x to better describe the mode's role: a runtime node
69+
* connected to ObjectStack Cloud).
6170
*/
6271
export async function createBootStack(config?: BootStackConfig): Promise<BootStackResult> {
6372
const cfg = BootStackConfigSchema.parse(config ?? {});
64-
const mode: BootMode = cfg.mode ?? resolveMode();
73+
const explicitMode: BootMode | undefined = cfg.mode
74+
? (cfg.mode === 'project' ? 'runtime' : cfg.mode as BootMode)
75+
: undefined;
76+
const mode: BootMode = explicitMode ?? resolveMode();
6577

6678
if (mode === 'cloud') {
6779
const cloudCfg = cfg.cloud ?? {};
@@ -84,5 +96,6 @@ export async function createBootStack(config?: BootStackConfig): Promise<BootSta
8496
return createStandaloneStack(cfg.standalone);
8597
}
8698

87-
return createProjectStack(cfg.project);
99+
// runtime (also reached via deprecated `mode: 'project'`)
100+
return createRuntimeStack(cfg.runtime ?? cfg.project);
88101
}

packages/services/service-cloud/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,13 @@ export {
6767
} from './boot-env.js';
6868
export type { BootMode, BootEnv } from './boot-env.js';
6969

70-
export { createProjectStack, ProjectStackConfigSchema, DEFAULT_CLOUD_URL } from './project-stack.js';
71-
export type { ProjectStackConfig, ProjectStackResult } from './project-stack.js';
70+
export { createRuntimeStack, RuntimeStackConfigSchema, DEFAULT_CLOUD_URL } from './runtime-stack.js';
71+
export type { RuntimeStackConfig, RuntimeStackResult } from './runtime-stack.js';
72+
73+
/** @deprecated Use `createRuntimeStack`. */
74+
export { createProjectStack, ProjectStackConfigSchema } from './runtime-stack.js';
75+
/** @deprecated Use `RuntimeStackConfig`/`RuntimeStackResult`. */
76+
export type { ProjectStackConfig, ProjectStackResult } from './runtime-stack.js';
7277

7378
export { createStandaloneStack, StandaloneStackConfigSchema } from './standalone-stack.js';
7479
export type { StandaloneStackConfig, StandaloneStackResult } from './standalone-stack.js';

packages/services/service-cloud/src/objectos-stack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* dispatcher can resolve hostnames and route every request to the
1010
* matching project kernel built from a remote-fetched artifact.
1111
*
12-
* Invoked by `createProjectStack()` whenever `OBJECTSTACK_CONTROL_PLANE_URL`
12+
* Invoked by `createRuntimeStack()` whenever `OBJECTSTACK_CLOUD_URL`
1313
* (or `config.controlPlaneUrl`) is set. The same plugin shape is returned
1414
* as `createCloudStack()` so host configs can swap stacks transparently.
1515
*/

packages/services/service-cloud/src/runtime-stack.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
* Runtime-mode stack factory.
55
*
66
* Default behavior — boots a "runtime node" connected to ObjectStack
7-
* Cloud (`https://cloud.objectstack.ai`). The node fetches per-project
8-
* artifacts over HTTP and routes incoming requests to the matching
9-
* project kernel; no local control-plane database is provisioned.
7+
* Cloud at `http://localhost:4000` (the local `apps/cloud` instance —
8+
* start it before the runtime). For the hosted control plane, set
9+
* `OBJECTSTACK_CLOUD_URL=https://cloud.objectstack.ai`. The node
10+
* fetches per-project artifacts over HTTP and routes incoming requests
11+
* to the matching project kernel; no local control-plane database is
12+
* provisioned.
1013
*
1114
* Local opt-out — set `OBJECTSTACK_CLOUD_URL=local` (or
1215
* `cloudUrl: 'local'`) to fall back to the legacy single-control-plane
@@ -33,12 +36,18 @@ import type { AppBundleResolver } from './project-kernel-factory.js';
3336
import { createObjectOSStack } from './objectos-stack.js';
3437

3538
/**
36-
* Default ObjectStack Cloud base URL used when neither `cloudUrl` nor
37-
* `OBJECTSTACK_CLOUD_URL` is set. Override via the env var or
38-
* `RuntimeStackConfig.cloudUrl`. Set to `local` to disable cloud routing
39-
* and boot from a local `control.db` instead.
39+
* Default ObjectStack Cloud base URL — the local `apps/cloud` instance
40+
* running on port 4000. Override via `OBJECTSTACK_CLOUD_URL` (or
41+
* `RuntimeStackConfig.cloudUrl`) to point at a remote control plane
42+
* (e.g. `https://cloud.objectstack.ai`). Set to `local` to disable
43+
* cloud routing entirely and boot from a local `control.db` instead.
44+
*
45+
* Why a local default? Runtime nodes are designed to be paired with a
46+
* control plane. Defaulting to `localhost:4000` lets contributors run
47+
* `apps/cloud` (the open-source control plane) and `apps/server` (the
48+
* runtime) side-by-side with zero env config — the natural dev loop.
4049
*/
41-
export const DEFAULT_CLOUD_URL = 'https://cloud.objectstack.ai';
50+
export const DEFAULT_CLOUD_URL = 'http://localhost:4000';
4251

4352
export const RuntimeStackConfigSchema = z.object({
4453
/** Auth secret (defaults to env / dev fallback). Local-mode only. */
@@ -56,8 +65,9 @@ export const RuntimeStackConfigSchema = z.object({
5665
/** API prefix (passed through to the cloud preset). */
5766
apiPrefix: z.string().optional(),
5867
/**
59-
* ObjectStack Cloud base URL. Defaults to `https://cloud.objectstack.ai`
60-
* (override via the `OBJECTSTACK_CLOUD_URL` env var or this field).
68+
* ObjectStack Cloud base URL. Defaults to `http://localhost:4000`
69+
* (the local `apps/cloud` dev instance). For the hosted control
70+
* plane, set `OBJECTSTACK_CLOUD_URL=https://cloud.objectstack.ai`.
6171
*
6272
* When non-empty (the default), the runtime stack runs as a
6373
* **cloud-connected runtime node**: no local control-plane database,

0 commit comments

Comments
 (0)