From 6bc51c9eaa9d12b5d5d4abeb6c05f5416822b82c Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 16 Aug 2026 06:32:36 +0000 Subject: [PATCH] docs(deployment): add os package publish and os package install to the CLI reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `content/docs/deployment/cli.mdx` carried a `####` entry per command across Development, Production, Build & Validate, Schema migrations, Scaffolding, Quality, Authentication and Cloud Environments — but had no entry for the two commands that move a compiled app onto a platform. The only mention of either was one prose line inside `os cloud login`. This matters now because #8910 made `publish-and-preview.mdx` the page that states how a metadata app reaches a platform, on the instruction "link to the CLI reference, do not restate it". The link landed on a reference that did not cover the two commands the page is about. Adds a `### Packages` subsection with `#### os package publish` and `#### os package install`, each with a full flag table and one example per mode, matching how `os migrate` and `os cloud login` are covered. Every flag was read from `packages/cli/src/commands/package/{publish,install}.ts` rather than restated from the card. That found flags the card did not name: publish's full 23-flag surface (the card listed only install's flags), and install's `--timeout` / `OS_CLOUD_TIMEOUT_MS`, `-r`/`-v` short forms, `--version` default `latest`, and the `OS_RUNTIME_EMAIL` / `OS_RUNTIME_PASSWORD` env spellings. `publish-and-preview.mdx` is untouched: it keeps the narrative and the choosing rule; this page carries the flag-level detail. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm --- content/docs/deployment/cli.mdx | 154 ++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/content/docs/deployment/cli.mdx b/content/docs/deployment/cli.mdx index f78d839c4a..a38e95f94c 100644 --- a/content/docs/deployment/cli.mdx +++ b/content/docs/deployment/cli.mdx @@ -1280,6 +1280,160 @@ os environments bind --artifact ./dist/objectstack.json --build is reserved for the server-side reseed endpoint; use it only when that endpoint is available in your deployment. +### Packages + +The two commands that move a compiled app onto a platform. They target +**different systems and authenticate as different identities**: publish uploads +to ObjectStack Cloud (the catalog), install registers an app into a **running +runtime**. + +| Command | Talks to | Description | +|---------|----------|-------------| +| `os package publish [artifact]` | ObjectStack Cloud | Upload a compiled artifact as a versioned package in your organization | +| `os package install ` | A running runtime | Install a package into a live kernel, from that runtime's catalog or from a local artifact | + +For which one to reach for and the preview patterns around them, see +[Publish & preview](/docs/deployment/publish-and-preview). This section is the +flag-level reference. + +#### `os package publish` + +Uploads a compiled artifact as a versioned package in your organization's +catalog. It ensures a `sys_package` row keyed by the manifest id, then snapshots +the artifact into a new `sys_package_version`. Publishing changes nothing that +is already running. + +```bash +os compile +os package publish # dist/objectstack.json → your org +os package publish --manifest-id com.acme.crm --version 1.2.0 +os package publish dist/objectstack.json --visibility org --note "first cut" +os package publish --env env_abc123 --install # publish, then install into an environment +OS_CLOUD_URL=http://localhost:4000 os package publish # against a local control plane +``` + +**The credential is the *cloud* identity.** Resolution order: `--token`, then +`$OS_TOKEN`, then `~/.objectstack/cloud.json` (written by +[`os cloud login`](#os-cloud-login)). It deliberately does **not** fall back to +`~/.objectstack/credentials.json` — that is the runtime identity +[`os login`](#os-login) writes, and the two are different accounts. With no +token at all the command exits `1` and tells you to run `os cloud login`. + +**Options:** + +| Flag | Env equivalent | Purpose | +|---|---|---| +| `artifact` (positional) | — | Path to the compiled artifact (default `dist/objectstack.json`) | +| `-s, --server ` | `OS_CLOUD_URL` | Control-plane URL. Default `https://cloud.objectos.ai`, or the URL recorded by `os cloud login` | +| `-t, --token ` | `OS_CLOUD_API_KEY` | Bearer token; `$OS_TOKEN` and `~/.objectstack/cloud.json` are the fallbacks | +| `--manifest-id ` | `OS_PACKAGE_MANIFEST_ID` | Reverse-domain package id. Default: `artifact.manifest.id`, else `local.` + a slug of the artifact name | +| `-v, --version ` | — | Version to publish. Default: `artifact.manifest.version`, else `0.0.0-dev.` + a timestamp | +| `--display-name ` | — | Name shown in the Marketplace (default `artifact.manifest.name`) | +| `--description ` | — | Short package description | +| `--category ` | — | Marketplace category slug (`crm`, `hr`, `devtools`, …) | +| `--visibility ` | — | `org` (default, installable across your organization) · `private` (explicit grants only) · `marketplace` (public after review) | +| `--org ` | `OS_ORG_ID` | `owner_org_id`. Required with a bearer key in service mode; ignored in user mode | +| `--env ` | `OS_ENVIRONMENT_ID` | Environment to install the new version into | +| `--install` | — | Auto-install into `--env` after publishing. Passed without `--env` it reports the mistake and publishes without installing | +| `--seed-sample-data` | — | Include sample data in that auto-install | +| `--pre-release` | — | Mark the version as a pre-release (also inferred — see below) | +| `--submit` | — | Submit the new version for marketplace review. Needs `--visibility marketplace` and a complete listing | +| `--auto-approve` | — | Platform admin only: skip the review queue and publish straight to the public catalog | +| `--readme ` | — | Inline marketplace README. Mutually exclusive with `--readme-file` | +| `--readme-file ` | — | README file, read at publish time. Mutually exclusive with `--readme` | +| `--icon-url ` | — | Public `http(s)` icon URL. Mutually exclusive with `--icon-file` | +| `--icon-file ` | — | Local PNG/JPEG/WebP/SVG (≤256 KB) uploaded to the icon CDN, which returns a stable URL and rewrites `icon_url` for you. Mutually exclusive with `--icon-url` | +| `--homepage-url ` | — | Public project / docs URL, surfaced in the catalog | +| `--license ` | — | SPDX identifier (`Apache-2.0`, `MIT`, …) | +| `-n, --note ` | — | Release notes | +| `--timeout ` | `OS_CLOUD_TIMEOUT_MS` | HTTP timeout in milliseconds, default `120000`. `0` disables it | + +**`objectstack.manifest.json` supplies the listing fields.** When that file is +present in the working directory, publish reads `manifestId`, `displayName`, +`description`, `category`, `tagline`, `iconUrl`, `homepageUrl`, `license`, +`readmePath` and a `translations` map from it, so a listing need not be retyped +as flags on every publish. **CLI flags always win.** A per-locale `readme` entry +may be inlined markdown or a path resolved against the manifest's own directory +(`README.zh-CN.md`). Publishing without the file is fully supported — it stays +flag-driven. + +**The namespace travels with the artifact and no flag overrides it.** +`manifest.namespace` is read off the compiled artifact and sent with the publish +payload, because the publish-time exclusivity gate (ADR-0048 addendum §A.2) +must check the object-name prefix the package actually ships — a reservation +naming a different string than the artifact installs would be worse than none. +A malformed value is refused before any network call; to change it, edit +`manifest.namespace` in `objectstack.config.ts` and rebuild. An artifact that +declares no namespace publishes fine. + +**Pre-release is inferred as well as flagged.** A version containing `-alpha`, +`-beta`, `-rc`, `-dev`, `-preview`, `-staging` or `-pr` is marked a pre-release +whether or not you pass `--pre-release` — so the generated +`0.0.0-dev.` + timestamp default never lands as a stable version. + +A `422` on version publish is marketplace policy rejecting the listing. The +command prints each violation and names the flags that fix them, rather than +leaving them in the server log. + +#### `os package install` + +Installs a package into a **running** runtime through its local install +endpoint (ADR-0008 Phase 3): the app is registered into the live kernel, and the +manifest is cached on the runtime host so the install re-registers on every boot +and survives restarts. This is the other half of publish — publish uploads to +the cloud, install puts an app into a runtime. + +Two modes, chosen by the shape of the argument: + +```bash +# catalog mode — the TARGET runtime resolves the version from its own catalog +os package install com.acme.crm --version 1.2.0 --runtime https://app.example.com + +# air-gapped mode — the artifact is read locally and sent inline; no catalog, works offline +os package install ./dist/objectstack.json +``` + +The argument is read as a **file path** when it ends in `.json`, starts with +`./`, `../` or `/`, or names something that exists in the working directory. +Anything else is a catalog id. The last clause is the one to know: a bare +catalog id that happens to match a file in the working directory is installed +from that file instead. + +**The credential is the *runtime* identity, not your cloud login.** The target +runtime authenticates the call with its own session, so `--email` / `--password` +(or `OS_RUNTIME_EMAIL` / `OS_RUNTIME_PASSWORD`) name an account **on that +runtime**. A `401` means exactly that, and the command says so; `os cloud login` +credentials do not apply here. + +**Options:** + +| Flag | Env equivalent | Purpose | +|---|---|---| +| `package` (positional, required) | — | Package manifest id (`com.acme.crm`) **or** a path to a compiled artifact JSON | +| `-r, --runtime ` | `OS_RUNTIME_URL` | Base URL of the runtime to install **into** (default `http://localhost:3000`) | +| `-v, --version ` | — | Version to install in catalog mode (default `latest`). Air-gapped mode takes the version from the artifact | +| `--email ` | `OS_RUNTIME_EMAIL` | Account email on the target runtime | +| `--password ` | `OS_RUNTIME_PASSWORD` | Account password on the target runtime | +| `--confirm-global-uniques` | — | Affirm this app's installation-wide `unique` constraints are genuinely platform-wide — see below | +| `--timeout ` | `OS_CLOUD_TIMEOUT_MS` | HTTP timeout in milliseconds, default `120000`. `0` disables it | + +**`--confirm-global-uniques` answers a stop; it does not force one past.** +Installing an app that declares installation-wide (`unique: 'global'`) +constraints into a runtime whose tenancy posture is `isolated` stops with +`UNIQUE_SCOPE_CONFIRMATION_REQUIRED`, and the command prints the offending +constraints so you can decide per entry (ADR-0120 D5e). Passing the flag records +an affirmative fact — *these constraints really are platform-wide* — into the +install manifest, alongside the posture it was given under, a timestamp and the +confirming identity when the seam knows one; [`os doctor`](#os-doctor) then stops +re-reporting the affirmed constraints, so the advisory does not become a +recurring nag. It is deliberately not called `--force`, and deliberately not +default-on. The other answer is to edit the app's metadata to +`unique: 'organization'` and rebuild. + +A `404` means the target runtime does not mount `MarketplaceInstallLocalPlugin` +(from `@objectstack/cloud-connection`). The endpoint is opt-in, so a runtime +composed without it will not accept installs. + ## Configuration The CLI looks for `objectstack.config.ts` (or `.js`, `.mjs`) in the current directory: