Skip to content

Commit a5e280f

Browse files
docs(skills): teach os environments use-runtime and os mcp connect (#31225)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xKoxHJ3zQQdUAbBUgta4iFN)_ Fixes #31143 Clause-②: no Metadata-protocol: none `dispatch-gates --tier` reads a MANDATORY model tier for `skills/**` (clause ① of the model-tiering ruling); it is waived by the standing order of the maintainer in this project (2026-11-03), and this card ran on the project's default model. The dispatching seat runs the contract review. **Cross-seat note:** `content/docs/deployment/cli.mdx` and `content/docs/deployment/publish-and-preview.mdx` are folded into this `domain:skills` card by the triage (6708594558), so the skill and the docs say the same thing. `content/docs/ai/connect-mcp.mdx` § "Claude Code (one command)" (the page that gives the `claude mcp add` line) was confirmed by the seat by name before it was edited. ## 维护者速读 - 改了什么:平台技能 `operations.md` 新增 `os environments use-runtime` 与 `os mcp connect` 两行,`os deploy` 行加自托管目标的流程(构建 → 试运行计划 → 内联安装 → `hotLoaded` 即上线,`--confirm-access-upgrade`),`os package install` 行写明不带 `-u` 时回落到记住的运行时;`cli.mdx` 新增「Deploy to a self-hosted runtime」「To a self-hosted runtime」「MCP / `os mcp connect`」三节并更新 install 的 `-u`/`-t` 默认值;`publish-and-preview.mdx` 加一段;`connect-mcp.mdx` 在手敲 `claude mcp add` 之前先介绍 `os mcp connect`;评测加两例。 - 为什么改:#30888(PR #31137)与 #30889(PR #31149)已合并,文档和技能没教,开发者与 AI 仍手敲地址、令牌和 `claude mcp add`(#31143)。 - 风险与回滚:只改文档、技能文字与 eval;`operations.md` 先删 8 处同文件重述/错述(−594 字节),余额 +53 token 按常设裁决 6513306068 提高该行上限 3287 → 3340;发 `@objectstack/skills` patch;回滚即 revert。 - 先看:`skills/objectstack-platform/references/operations.md` 的 § Environments & deploy 表,以及下方「删减与去处」表(含席位裁定删除的 `os login` / `os register` 两行错述)。 - 两分钟验证:`node scripts/check-skills-token-ratchet.mjs`,预期退出 0,`operations.md 3340 / 3340`。 - 需要你做的:`skills/**` 属 Tier H(人合),需要 `os-zhuang` 或 `hotlong` 的一次 approval,之后席位落地。 ## What changes ### 1. The platform skill (`skills/objectstack-platform/references/operations.md`) ```diff -| `os login` / `logout` / `whoami` | Auth against the ObjectStack cloud control plane | -| `os register` | Register the local stack as a deployable target | +| `os environments use-runtime <url> --token <key>` | Deploy to a self-hosted runtime instead: the key (one it issued) is tried first (`--no-verify` skips), then kept in `~/.objectstack/cloud.json` (0600) across cloud login/logout. `--forget` or `os environments switch` targets the cloud again | -… `--no-wait`; `--wait-timeout <seconds>` (600) | +… `--no-wait`; `--wait-timeout <seconds>` (600). A `use-runtime` target, no `--env`: build, dry-run plan, install, live on `hotLoaded`; `--confirm-access-upgrade <token>` | -| `os package install <manifest-id │ ./dist/objectstack.json> [--version │ -u/--url http://localhost:3000]` | … not the cloud login | +| `os package install <manifest-id │ ./dist/objectstack.json> [--version │ -u/--url]` | … not the cloud login. No `-u`: the `use-runtime` runtime and, with no `-t`/`--email`, its key; else `http://localhost:3000` | +| `os mcp connect` | Register the cloud environment's MCP server (picked as `os deploy` picks it) with Claude Code (`claude mcp add`); `--url <base>` for a self-hosted or local server (named `objectstack`); `--name`; `--print` runs nothing (other clients). Stores no token: the client runs the server's own OAuth | ``` The skill rows stay short and the full sequence lives in the CLI reference (the order's preference). ### 2. The docs - `content/docs/deployment/cli.mdx`: a `use-runtime` row in § Cloud Environments; new § "Deploy to a self-hosted runtime" (examples, the key and its probe, `--no-verify`, storage, which of `use-runtime` / `switch` wins, `--forget`, a flag table); § `os deploy` names the self-hosted target in its lead, gains a `--confirm-access-upgrade` row and a "To a self-hosted runtime" subsection (the four steps and the `d` key); new § MCP / `os mcp connect` (examples, environment resolution, `--url`, names, `--client`, `--print`, failure exits, no token, revoke, a flag table); § `os package install`'s `-u` and `-t` rows now give the remembered runtime as the default. - `content/docs/deployment/publish-and-preview.mdx` § 3 "Install a version": one paragraph on remembering a runtime with `use-runtime` so `os deploy` and the `d` key deploy there, the `os package install` fallback, and how to target the cloud again. - `content/docs/ai/connect-mcp.mdx` § "Claude Code (one command)": one paragraph plus a fence before the hand-typed lines, which stay. ## Code site per taught sentence (`main` `66bf5b4a`) | Taught | Code site | |:--|:--| | `os environments use-runtime <url> --token <key>`; `-t` reads `OS_RUNTIME_TOKEN` | `packages/cli/src/commands/environments/use-runtime.ts` `args.url` (L40–L42), `flags.token` (L45–L49) | | The key is tried first on `GET /api/v1/marketplace/install-local`; 401/403, 404, unreachable refused, nothing recorded | `use-runtime.ts` L93–L100, `probeRuntime` (L142–L178) | | `--no-verify` records anyway (a container not up yet) | `use-runtime.ts` `verify` flag (L50–L54, `allowNo`), header L21–L25 | | URL is an http(s) base URL, no query or fragment | `normalizeRuntimeUrl` (L118–L135) | | `--forget` drops the record; cloud is the target again; not with a url | `use-runtime.ts` L65–L77; `forgetRuntimeTarget` (`packages/cli/src/utils/runtime-target.ts` L65–L69) | | Stored in `~/.objectstack/cloud.json`, 0600, its own record; key sent only to its url | `packages/cli/src/utils/cloud-config.ts` header L31–L44, `getCloudCredentialsPath` L106, `writeFile(..., { mode: 0o600 })` L132; `runtime-target.ts` header L23–L27 | | Cloud logout keeps it; cloud login keeps it | `cloud-config.ts` `deleteCloudConfig` L193–L195, `writeCloudConfig` L187–L190 (header L40–L43) | | `os environments switch <id>` (when recorded in cloud.json) makes the cloud the target again, keeping the runtime | `packages/cli/src/commands/environments/switch.ts` L78–L79; `activateCloudDeployTarget` (`runtime-target.ts` L76–L81) | | `os deploy` with a runtime target and no `--env` deploys there; `--env` names a cloud environment | `packages/cli/src/commands/deploy.ts` L152–L156 | | Self-hosted sequence: build → dry run (plan printed; a runtime that predates it installs anyway, said, exit 1) → install (a register failure is refused here) → `hotLoaded` ⇒ 0 | `deploy.ts` `deployToRuntime` L288–L335, header L49–L71; `install.ts` L511–L522 (dry run ignored ⇒ INSTALLED, exit 1) and L617–L622 (an inline manifest whose register throws is refused `422 PLUGIN_REGISTER_FAILED`) | | `--confirm-access-upgrade <token>` passed through; refused when the target is the cloud | `deploy.ts` flag L138–L142, L157–L164, L320 | | The `d` key runs the same `os deploy`, no cloud login asked | `packages/cli/src/utils/dev-deploy-key.ts` header L26–L31, `deployKeyHint` L74–L75, L118 | | `os package install` with no `-u`: the remembered runtime (its key when no `-t` / `--email` and the url is its own), else `http://localhost:3000` | `runtime-target.ts` `runtimeInstallTarget` L92–L108, `DEFAULT_RUNTIME_INSTALL_URL` L38; `packages/cli/src/commands/package/install.ts` flags L218–L234, L328–L337 | | `os mcp connect` resolves the cloud environment as `os deploy`: `--env`, active, only; none/several refused naming `--env`; a remembered runtime is not consulted | `packages/cli/src/commands/mcp/connect.ts` header L8–L15, `resolveInstallTarget` call L202–L212 (no runtime-target read in the file) | | MCP URL = environment origin + `/api/v1/mcp`; registered under its slug / display name / id, lower-cased, other runs → `-` | `connect.ts` `MCP_ENDPOINT_PATH` L54, `environmentServerName` L78–L84, L234–L235 | | `--url` skips the cloud, adds `/api/v1/mcp`, refuses a URL ending in it, name `objectstack` | `connect.ts` `mcpUrlFromBase` L91–L113, L182–L191; `OBJECTSTACK_MCP_SERVER_NAME = 'objectstack'` (`packages/mcp/src/skill-md.ts` L51) | | `--name` overrides (letters, digits, `-`, `_`) | `connect.ts` flag L143–L145, `SERVER_NAME` L60, L173–L177 | | `--client claude-code` is the only value and the default; runs `claude mcp add --transport http NAME URL` | `connect.ts` `MCP_CLIENTS` L57, flag L146–L150, `claudeMcpAddArgs` L63–L65 | | `--print` prints the endpoint and the line, runs nothing; other clients add the endpoint themselves | `connect.ts` flag L151–L154, header L35–L41, L243–L248 | | `claude` missing or `claude mcp add` failing exits non-zero; remove or pick another `--name` | `connect.ts` L251–L270 | | No token stored; `--token` only finds the environment; sign-in via `/mcp`; revoke in Account → Connect an AI Assistant | `connect.ts` header L24–L33, `token` flag L161–L165, L273–L281 | ## Token readings and every deletion's home `node scripts/check-skills-token-ratchet.mjs` on fresh `main` `66bf5b4a`: `operations.md` **3285 / 3287** (headroom 2). With the teaching added: 3489 (+202 over). After the deletions below and the review's S1 correction: **3340**, 13140 → 13360 bytes (+220 net: −594 cut, +814 added). The remainder, **+53** measured, raises only that file's row 3287 → 3340, pinned at the measurement, under the standing maintainer ruling 2026-10-27, verbatim and untranslated: 「A:先削重复,余额按实测提高」 (ruling record 6513306068 on #27847). No other row changes. (The seat's ruling expected about +47; the extra 6 tokens are an accuracy fix found after it: the MCP row first said "the `os deploy` environment", but with a self-hosted target `os deploy` goes to the runtime while `os mcp connect` still resolves a cloud environment, so the row now says "the cloud environment (picked as `os deploy` picks it)".) Every deletion, with every fact it held and where each survives (seat ruling: cuts 1–7 accepted): | # | Cut (bytes) | Facts it held | Surviving home | |:--|:--|:--|:--| | 1 | `os dev` row: " — idempotent, never overwrites an existing account" (53) | seeding never touches an existing account | the same row, whose "on an **empty** DB only" now reads "with **no login** yet" (review S1: the seed is gated on the absence of a login, not an empty user table, `packages/cli/src/commands/dev.ts` L777–L781; −2 bytes) | | 2 | Verify item 2: "A bare `field` (missing `record.`) fails here." (47) | `os validate` refuses a bare field ref | the section intro (a bare field ref in a predicate faults; "Both are caught at author time by one command") and item 2's `record.<field>` existence check | | 3 | "(`os lint` is a *separate* style/convention pass and does not replace `os validate`.)" (86) | lint is a style/convention pass; it is not the gate | Daily-loop `os lint` row ("Style/convention lint on metadata files") and the rule of thumb ("never report … done until `os validate` passes") | | 4 | Production port row: " — a shifted port breaks reverse-proxy upstreams, better-auth callback URLs, and CORS trusted-origins as opaque 403/502s" (122) | what a shifted port breaks | Production guidance "Keep these in sync when you change the port (mismatch ⇒ better-auth `Invalid origin` 403 / CORS failures)" list: reverse-proxy upstream, `OS_AUTH_URL` / `baseURL` + `callbackURL`, `OS_TRUSTED_ORIGINS`. The word "502" is the one fact not restated. | | 5 | Production guidance: " Don't rely on the `3000` default; it collides easily on shared hosts." (72) | don't rely on the default | "Pin the port explicitly — `PORT=8080 os start`" and the resolution chain showing `3000` as the default | | 6 | Testing: " — with the in-memory driver a full bootstrap is cheap" (58) | a fresh kernel per test is cheap | the section intro: "tests run in milliseconds" | | 7a | Row `os login` / `logout` / `whoami` · "Auth against the ObjectStack cloud control plane" (88) | **misstated**: `os login` authenticates against the runtime server and stores `credentials.json` (`login.ts` L240–L253); cloud auth is `os cloud login` | `content/docs/deployment/cli.mdx` § Authentication; the `os cloud login` row stays in the skill | | 7b | Row `os register` · "Register the local stack as a deployable target" (68) | **misstated**: `os register` creates an account and stores credentials (`register.ts` L64) | `content/docs/deployment/cli.mdx` § Authentication | Cut 6 joins its two lines into one (the deletion spans the line break); no other line is rewrapped. No test or script pins any cut text (grepped `packages/`, `scripts/`, `.claude/`, `skills/`, `content/`; only `packages/skills/dist` and CHANGELOGs carry copies). ## Eval cases (`skills/objectstack-platform/evals/config-plugins-ops.json`) - **21** · "We run ObjectStack's Docker image on our own server at https://objectos.example.com. How do I deploy my app there from the project without typing its URL and key every time?" → `use-runtime <url> --token <key>`, probe and `--no-verify`, `cloud.json` (0600) across login/logout, then `os deploy` / `d`: build, dry-run plan, inline install, live on `hotLoaded`, `--confirm-access-upgrade`; `os package install` fallback; `--forget` / `switch` back. `must_contain`: `os environments use-runtime`, `--token`; `must_not_contain`: `os deploy --url` (no such flag). - **22** · "Connect Claude Code to our ObjectOS Cloud environment's MCP server, and to my local `os dev` server too." → `os mcp connect` (runs `claude mcp add --transport http <name> <url>`, environment as `os deploy` picks it, named after it), `--url http://localhost:3000` registered as `objectstack`, `--name`, `--print` for other clients, no token, `/mcp` sign-in. `must_contain`: `os mcp connect`, `--url`; `must_not_contain`: `--client cursor` (the only client is `claude-code`). Swept the skill's evals for the old claims: no case encodes the cut text, `os login` / `os register`, or the `localhost:3000` install default; case 5's `os lint` and case 17's cloud `os deploy` stay true. ## Other sites found (not edited) - `content/docs/ai/agents.mdx` L99 and `content/docs/getting-started/build-with-claude-code.mdx` L477–L502 still give only the hand-typed `claude mcp add` line; `content/docs/releases/v16.mdx` is release history. - `packages/cli/src/commands/environments/create.ts` (`--activate`) does not call `activateCloudDeployTarget`, so only `os environments switch` returns the deploy target to the cloud; the docs teach only `switch`. Whether `create --activate` should too is a CLI question, not a teaching one. ## Gates Head `4e0b6486` (two commits on merge base `66bf5b4a`; the second is the review delta: S1, N3, N4, N7 and the N6 re-flow of the one ragged `os mcp connect` paragraph). `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives the same **87** commands as at `e15e06e1`; **all 87 exited 0**, 0 NOT MEASURED among them. Each ran with `timeout 900` under `NODE_OPTIONS=--max-old-space-size=8192`, after `pnpm install --frozen-lockfile` and a full `pnpm build` (exit 0). The list with each exit code: `gates-4e0b6486.txt` in the card folder (round 1: `gates-e15e06e1.txt`, 87/87 exit 0). It includes `pnpm check:skill-identifier-liveness`, `pnpm --filter @objectstack/spec run check:skill-refs`, `pnpm check:skill-compatibility`, `node scripts/check-skills-token-ratchet.mjs` (and `--self-test`), `pnpm check:doc-authoring`, `pnpm check:doc-anchors`, `pnpm --filter @objectstack/spec run check:docs`, `pnpm check:cli-command-ids`, `pnpm check:cli-examples-parity` and `node scripts/check-empty-changeset.mjs --base origin/main`. The CI-only steps dispatch-gates names as NOT MEASURED (Build Docs, Build Core, the type-check lanes, dogfood and shard attestation) run in CI. `node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD` exit 0 before the push. <!-- signed: domain:skills#3 · huangyiirene · session_01J8VVAnBUEjCrpMSAcQv3Gp --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 85c0124 commit a5e280f

7 files changed

Lines changed: 223 additions & 18 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the platform skill teaches `os environments use-runtime` and `os mcp connect`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`objectstack-platform`'s operations reference gains two rows and two clauses. `os environments use-runtime <url> --token <key>` makes a self-hosted runtime the deploy target: the key is tried on the runtime first (`--no-verify` skips that), kept in `~/.objectstack/cloud.json` (0600) across cloud login and logout, and `--forget` or `os environments switch` targets the cloud again. The `os deploy` row says how it deploys to that runtime (build, dry-run plan, inline install, live on `hotLoaded`, `--confirm-access-upgrade`), and the `os package install` row says it falls back to that runtime with no `-u`. `os mcp connect` registers an environment's MCP server with Claude Code, `--url` for a self-hosted or local server (named `objectstack`), `--name`, `--print`, and stores no token. Paid by cutting restatement in the same file and two rows that misstated `os login` and `os register`. Two new eval cases cover the commands. The CLI behaviour already shipped; this release only teaches it.

‎content/docs/ai/connect-mcp.mdx‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,23 @@ disappears with it, along with both its Setup and Account navigation entries. Se
2222

2323
Interactive clients use OAuth — each deployment is its own OAuth 2.1
2424
authorization server, so there are no admin-minted credentials to pass around.
25-
The first tool call opens a browser login and you connect **as yourself**:
25+
The first tool call opens a browser login and you connect **as yourself**.
26+
27+
With the ObjectStack CLI, [`os mcp connect`](/docs/deployment/cli#os-mcp-connect)
28+
runs the `claude mcp add` line for you. With no flags it registers your
29+
ObjectOS Cloud environment, picked as `os deploy` picks it, under that
30+
environment's name; `--url` takes
31+
a self-hosted or local server's base URL and registers it as `objectstack`. Claude
32+
Code is the only client it runs (`--client claude-code`); `--print` prints the
33+
endpoint and the line and runs nothing, for any other client. It stores no token:
34+
the client runs the server's own sign-in.
35+
36+
```bash
37+
os mcp connect # your ObjectOS Cloud environment
38+
os mcp connect --url http://localhost:3000 # a self-hosted or local server
39+
```
40+
41+
Or type the line yourself:
2642

2743
```bash
2844
# local dev server

‎content/docs/deployment/cli.mdx‎

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3130,6 +3130,7 @@ spells them, so one consumer reads both commands.
31303130
| `os environments create` | Provision a new environment. With `--activate` (the default) the new environment becomes the active one, recorded in `~/.objectstack/cloud.json` as well when the control plane it talked to is the one `os cloud login` recorded — so [`os package publish --install`](#os-package-publish) can install into it with no `switch` in between |
31313131
| `os environments switch <id>` | Set the active environment for later CLI calls. Recorded in `~/.objectstack/cloud.json` as well when the control plane it talked to is the one `os cloud login` recorded, so [`os package publish --install`](#os-package-publish) can use it |
31323132
| `os environments bind <id>` | Bind a compiled local artifact to an existing environment |
3133+
| `os environments use-runtime <url> --token <key>` | Make a self-hosted runtime the deploy target instead of an ObjectOS Cloud environment — see [Deploy to a self-hosted runtime](#deploy-to-a-self-hosted-runtime) |
31333134

31343135
#### Create an environment from a local artifact
31353136

@@ -3156,12 +3157,53 @@ os environments bind <environment-id> --artifact ./dist/objectstack.json --build
31563157
is reserved for the server-side reseed endpoint; use it only when that endpoint
31573158
is available in your deployment.
31583159

3160+
#### Deploy to a self-hosted runtime
3161+
3162+
`os environments use-runtime` remembers a runtime you operate — ObjectStack's
3163+
Docker image, Community or Enterprise — as the deploy target, so
3164+
[`os deploy`](#to-a-self-hosted-runtime), the `d` key in [`os dev`](#os-dev) and
3165+
[`os package install`](#os-package-install) stop asking for its URL and key.
3166+
3167+
```bash
3168+
os environments use-runtime http://localhost:8080 --token osk_…
3169+
OS_RUNTIME_TOKEN=osk_… os environments use-runtime https://objectos.example.com
3170+
os environments use-runtime --forget # deploy to ObjectOS Cloud again
3171+
```
3172+
3173+
The key is an API key the runtime issued (its **Setup → API Keys**); `-t, --token`
3174+
reads `OS_RUNTIME_TOKEN`. The URL is the runtime's http(s) base URL, with no query
3175+
or fragment. Before anything is written, the key is tried on the runtime's
3176+
install-local endpoint (`GET /api/v1/marketplace/install-local`, which answers
3177+
only an authenticated caller): a key the runtime rejects (`401` / `403`), a
3178+
runtime that does not serve the endpoint (`404`), or one that cannot be reached
3179+
is refused, naming why, and nothing is recorded. `--no-verify` records it anyway,
3180+
for a container that is not up yet.
3181+
3182+
The URL and key are stored in `~/.objectstack/cloud.json` (mode `0600`), the file
3183+
`os cloud login` writes, as their own record: no cloud request reads the key, and
3184+
it is sent only to that runtime's URL. `os cloud logout` keeps the record, and so
3185+
does a new `os cloud login`.
3186+
3187+
Whichever of `use-runtime` and `os environments switch` ran last is the target
3188+
`os deploy` uses. `os environments switch <id>`, when it records the environment
3189+
in `cloud.json` (see the table above), makes ObjectOS Cloud the target again and
3190+
keeps the remembered runtime, so `os package install` still falls back to it.
3191+
`--forget` drops the record.
3192+
3193+
| Flag | Env equivalent | Purpose |
3194+
|---|---|---|
3195+
| `url` (positional) | — | Base URL of the self-hosted runtime (e.g. `http://localhost:8080`) |
3196+
| `-t, --token <key>` | `OS_RUNTIME_TOKEN` | An API key the runtime issued; sent only to this runtime |
3197+
| `--no-verify` | — | Record the runtime without trying the key on it first |
3198+
| `--forget` | — | Forget the remembered runtime; ObjectOS Cloud is the deploy target again. Takes no `url` |
3199+
31593200
### Deploy
31603201

31613202
#### `os deploy`
31623203

31633204
Puts the app in the current directory on your ObjectOS Cloud environment, with
3164-
no flags. It builds the app (the compile [`os build`](#os-compile) runs),
3205+
no flags (or on a [self-hosted runtime](#to-a-self-hosted-runtime) you made the
3206+
target). It builds the app (the compile [`os build`](#os-compile) runs),
31653207
publishes it as `<manifest.version>-dev.<YYYYMMDDHHMMSS>` — a UTC semver
31663208
pre-release, so deploying again never needs a version bump — installs that
31673209
version into your organization's environment, and waits until the environment
@@ -3199,10 +3241,90 @@ is its production, so a deploy is always a deliberate act.
31993241
| `--wait-timeout <seconds>` | — | How long to wait for the environment to serve the new version (default `600`) |
32003242
| `-s, --server <url>` | `OS_CLOUD_URL` | Control-plane URL. Default `https://cloud.objectos.ai`, or the URL recorded by `os cloud login` |
32013243
| `-t, --token <key>` | `OS_CLOUD_API_KEY` | Bearer token; `$OS_TOKEN` and `~/.objectstack/cloud.json` are the fallbacks |
3244+
| `--confirm-access-upgrade <token>` | — | Self-hosted target only: confirm the upgrade's access findings with the finding-set token the runtime's refusal printed (as [`os package install`](#os-package-install)). Refused when the target is ObjectOS Cloud |
32023245
32033246
`os package publish` stays the command for a **release**: it publishes the
32043247
version the manifest declares, with `--install` optional.
32053248
3249+
##### To a self-hosted runtime
3250+
3251+
When [`os environments use-runtime`](#deploy-to-a-self-hosted-runtime) made a
3252+
self-hosted runtime the active target, `os deploy` with no flags deploys there
3253+
instead; `--env` still names an ObjectOS Cloud environment and deploys to it.
3254+
There is no catalog and no version to mint: the build is sent inline to the
3255+
runtime's install-local endpoint by [`os package install`](#os-package-install),
3256+
run in the same process with the remembered URL and key, so its refusals and
3257+
answers are the ones printed.
3258+
3259+
1. **Build** — the same compile as above. A failed build prints its errors, and
3260+
nothing is installed.
3261+
2. **Dry run** — the runtime's upgrade plan of the installed version against this
3262+
build is printed; nothing is installed. A runtime that refuses it, or does not
3263+
serve install-local, stops the deploy with exit `1`. A runtime that predates the
3264+
dry run ignores it and installs: the command says so and exits `1`.
3265+
3. **Install** — with `--confirm-access-upgrade` passed through. The endpoint's
3266+
refusals (an access upgrade to confirm, a package the running kernel cannot
3267+
register, …) stop the deploy with exit `1`.
3268+
4. **Live** — install-local registers the package in the running kernel before it
3269+
answers, so the answer is the verdict: `hotLoaded` prints `Live: … now serves …`
3270+
and exits `0`.
3271+
3272+
The `d` key in [`os dev`](#os-dev) runs the same `os deploy`, so it deploys to the
3273+
runtime too and asks for no cloud login.
3274+
3275+
### MCP
3276+
3277+
#### `os mcp connect`
3278+
3279+
Registers your environment's MCP server with your MCP client in one command. The
3280+
client then runs the environment's own OAuth: on first use it follows the
3281+
server's OAuth discovery, registers itself, and your browser shows the
3282+
environment's sign-in and consent.
3283+
3284+
```bash
3285+
os mcp connect
3286+
os mcp connect --print # print the endpoint and the `claude mcp add` line, run nothing
3287+
os mcp connect --env env_abc123 # your account reaches several environments
3288+
os mcp connect --url http://localhost:3000 # a self-hosted or local server
3289+
```
3290+
3291+
The ObjectOS Cloud environment is resolved exactly as [`os deploy`](#os-deploy)
3292+
resolves it: `--env`, then the active environment for this control plane, then
3293+
your organization's only environment; none or several is refused, naming
3294+
`--env`. A self-hosted runtime `os environments use-runtime` remembered is not
3295+
consulted; name it with `--url`. Its MCP URL is the environment's address, read
3296+
from the control plane, plus `/api/v1/mcp`, and the server is registered under
3297+
the environment's own name (its slug, else its display name, else its id,
3298+
lower-cased with every run of other characters turned into one `-`), so several
3299+
environments can be registered side by side. `--url` skips ObjectOS Cloud: it
3300+
takes the base URL of a self-hosted or local server (the command adds
3301+
`/api/v1/mcp` itself and refuses a URL that already ends in it) and registers it
3302+
as `objectstack`, the name `os dev`'s banner gives it. `--name` overrides either
3303+
name.
3304+
3305+
For Claude Code — the only `--client` value, and the default — the command runs
3306+
`claude mcp add --transport http NAME URL`. `--print` prints the endpoint and that
3307+
line and runs nothing, which is also how to connect any other client: add the
3308+
endpoint as a remote HTTP MCP server in its settings. Then, in Claude Code, run
3309+
`/mcp` and authenticate the server. If `claude` is not on your `PATH`, or
3310+
`claude mcp add` fails (for a name already registered, `claude mcp remove NAME` or
3311+
pick another `--name`), the command exits non-zero.
3312+
3313+
**No token is stored.** The command hands the client the URL alone and writes no
3314+
token into a client config. `-t, --token` (or the `os cloud login` session) is
3315+
used only to find the environment and is never handed to the client. To revoke
3316+
the grant, use the environment's console: **Account → Connect an AI Assistant**.
3317+
3318+
| Flag | Env equivalent | Purpose |
3319+
|---|---|---|
3320+
| `--env <id>` | `OS_ENVIRONMENT_ID` | Environment to connect to (default: the active one for this control plane, then your organization's only one) |
3321+
| `--url <url>` | — | Base URL of a self-hosted or local server; skips ObjectOS Cloud |
3322+
| `--name <name>` | — | Server name in the client: letters, digits, `-` and `_` (default: the environment's name; `objectstack` with `--url`) |
3323+
| `--client <client>` | — | `claude-code`, the default and only value |
3324+
| `--print` | — | Print the endpoint and the command that registers it; run nothing |
3325+
| `-s, --server <url>` | `OS_CLOUD_URL` | Control-plane URL. Default `https://cloud.objectos.ai`, or the URL recorded by `os cloud login` |
3326+
| `-t, --token <key>` | `OS_CLOUD_API_KEY` | Bearer token, used only to find the environment; `$OS_TOKEN` and `~/.objectstack/cloud.json` are the fallbacks |
3327+
32063328
### Packages
32073329
32083330
The two commands that move a compiled app onto a platform. They target
@@ -3389,9 +3511,9 @@ write `-u URL` instead.
33893511
| Flag | Env equivalent | Purpose |
33903512
|---|---|---|
33913513
| `package` (positional, required) | — | Package manifest id (`com.acme.crm`) **or** a path to a compiled artifact JSON |
3392-
| `-u, --url <url>` | `OS_RUNTIME_URL` | Base URL of the runtime to install **into** (default `http://localhost:3000`) |
3514+
| `-u, --url <url>` | `OS_RUNTIME_URL` | Base URL of the runtime to install **into** (default: the runtime [`os environments use-runtime`](#deploy-to-a-self-hosted-runtime) remembered, else `http://localhost:3000`) |
33933515
| `-v, --version <semver>` | — | Version to install in catalog mode (default `latest`). Air-gapped mode takes the version from the artifact |
3394-
| `-t, --token <token>` | `OS_RUNTIME_TOKEN` | A token the target runtime issued (an API key); instead of `--email` / `--password` |
3516+
| `-t, --token <token>` | `OS_RUNTIME_TOKEN` | A token the target runtime issued (an API key); instead of `--email` / `--password`. Default: the key `os environments use-runtime` remembered, when the URL is that runtime's and no `--email` / `--password` is given |
33953517
| `--email <email>` | `OS_RUNTIME_EMAIL` | Account email on the target runtime |
33963518
| `--password <password>` | `OS_RUNTIME_PASSWORD` | Account password on the target runtime |
33973519
| `--confirm-global-uniques` | — | Affirm this app's installation-wide `unique` constraints are genuinely platform-wide — see below |

‎content/docs/deployment/publish-and-preview.mdx‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,18 @@ login. Uninstall (`DELETE /api/v1/marketplace/install-local/:manifestId`) remove
209209
the cached manifest and withdraws the app from the running kernel; its answer
210210
says whether any part stays loaded until the next restart.
211211

212+
**Deploying your working copy to a runtime you operate, again and again?**
213+
Remember it once with
214+
[`os environments use-runtime <url> --token <key>`](/docs/deployment/cli#deploy-to-a-self-hosted-runtime)
215+
(an API key that runtime issued). [`os deploy`](/docs/deployment/cli#to-a-self-hosted-runtime)
216+
— and the `d` key in `os dev`, which runs it — then deploys there with no URL or
217+
key to type: it builds, prints the runtime's upgrade plan from a dry run,
218+
installs the build inline, and reports the app live once the running kernel has
219+
loaded it (`hotLoaded`). `os package install` uses the same runtime when `-u` /
220+
`-t` are not given. `os environments use-runtime --forget`, or an
221+
`os environments switch <id>` recorded for your `os cloud login` control plane,
222+
makes ObjectOS Cloud the target again.
223+
212224
For the full command reference — every flag, every subcommand — see the
213225
[CLI reference](/docs/deployment/cli).
214226

‎scripts/check-skills-token-ratchet.mjs‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,25 @@ export const CEILINGS = new Map([
10621062
// the image pitfall row); the remainder, +179 measured, raises the row,
10631063
// pinned at the measurement. Maintainer ruling 2026-10-27 on the decision card 「skills 修复卡的教学和 eval 都撞 token 天
10641064
// 花板,怎么付?」, tap A, verbatim and untranslated: 「A:先削重复,余额按实测提高」.
1065-
['skills/objectstack-platform/references/operations.md', 3287],
1065+
// 3287 -> 3340: `os environments use-runtime` (a self-hosted runtime as the
1066+
// deploy target: key tried first, `--no-verify`, kept in cloud.json across
1067+
// cloud login/logout, `--forget` / `os environments switch` back to the
1068+
// cloud), the self-hosted `os deploy` sequence and `--confirm-access-upgrade`,
1069+
// `os package install`'s fallback with no `-u`, and `os mcp connect`. Paid
1070+
// first by deleting restatement in the same file (-594 bytes): the `os dev`
1071+
// row's "idempotent, never overwrites" clause (home: the same row, whose
1072+
// "on an empty DB only" now reads "with no login yet", as `os dev` seeds); Verify your work's bare-`field` sentence (home: its
1073+
// intro) and its `os lint` parenthesis (homes: the `os lint` row and the
1074+
// rule of thumb); the Production port row's list of what a shifted port
1075+
// breaks and "Don't rely on the 3000 default" (home: Production guidance);
1076+
// Testing's "a full bootstrap is cheap" (home: its intro); and two rows that
1077+
// misstated `os login` / `os register` (home: content/docs/deployment/cli.mdx
1078+
// § Authentication). 13140 -> 13360 bytes (+220 net: -594 cut, +814 added)
1079+
// -> ceil(13360 / 4) = 3340; headroom was 2 tokens, so the remainder, +53
1080+
// measured, raises the row, pinned at the measurement. Same maintainer
1081+
// ruling, verbatim and untranslated: 「A:先削重复,余额按实测提高」 (ruling
1082+
// record 6513306068 on #27847).
1083+
['skills/objectstack-platform/references/operations.md', 3340],
10661084
['skills/objectstack-platform/references/plugin-development.md', 3137],
10671085
['skills/objectstack-upgrade/references/examples-upgrade.md', 1197],
10681086

‎skills/objectstack-platform/evals/config-plugins-ops.json‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,36 @@
347347
"requires: ['storage', 'settings']"
348348
]
349349
}
350+
},
351+
{
352+
"id": 21,
353+
"prompt": "We run ObjectStack's Docker image on our own server at https://objectos.example.com. How do I deploy my app there from the project without typing its URL and key every time?",
354+
"expected_output": "Remember the runtime once: `os environments use-runtime https://objectos.example.com --token <key>`, with an API key that runtime issued. The key is tried on the runtime before anything is recorded (`--no-verify` skips that), then kept in `~/.objectstack/cloud.json` (0600), across cloud login and logout. From then on `os deploy` (or `d` in `os dev`) deploys there: it builds, prints the runtime's dry-run upgrade plan, installs the build inline, and reports it live when the runtime answers `hotLoaded`; `--confirm-access-upgrade <token>` confirms the access findings a refusal printed. `os package install` falls back to that runtime when `-u` is not given. `os environments use-runtime --forget` or `os environments switch <id>` makes ObjectOS Cloud the target again.",
355+
"files": [],
356+
"assertions": {
357+
"must_contain": [
358+
"os environments use-runtime",
359+
"--token"
360+
],
361+
"must_not_contain": [
362+
"os deploy --url"
363+
]
364+
}
365+
},
366+
{
367+
"id": 22,
368+
"prompt": "Connect Claude Code to our ObjectOS Cloud environment's MCP server, and to my local `os dev` server too.",
369+
"expected_output": "Run `os mcp connect`: it runs `claude mcp add --transport http <name> <url>` for the environment `os deploy` would pick on ObjectOS Cloud (`--env <id>`, else the active one, else your organization's only one), named after that environment. For the local server, `os mcp connect --url http://localhost:3000` registers it as `objectstack`. `--name` overrides the name; `--print` prints the endpoint and the line and runs nothing, which is how to connect another client. No token is stored: in Claude Code run `/mcp` and authenticate, and the server's own sign-in and consent open in the browser.",
370+
"files": [],
371+
"assertions": {
372+
"must_contain": [
373+
"os mcp connect",
374+
"--url"
375+
],
376+
"must_not_contain": [
377+
"--client cursor"
378+
]
379+
}
350380
}
351381
]
352382
}

0 commit comments

Comments
 (0)