You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
docs(deployment): the CLI reference has no entry for os package publish or os package install — the two commands that move an app onto a platform #8965
Found while implementing #8910 (PR #8962). Filed unassigned; not fixed there — out of that card's file surface.
The gap
content/docs/deployment/cli.mdx is the command reference: its ## Commands section carries a #### entry per command across Development, Production, Build & Validate, Schema migrations, Scaffolding, Quality, Authentication and Cloud Environments. Two shipped commands are absent from it entirely:
os package publish — packages/cli/src/commands/package/publish.ts
os package install — packages/cli/src/commands/package/install.ts
Measured on origin/main at d6e80b28b: the only occurrence of either string in cli.mdx is prose at line 1192 ("It is the credential os package publish and the marketplace commands use"), inside the os cloud login section. There is no entry, no flag table, no example for either.
os package install is the more complete miss — grepping content/docs/** for it returns only protocol/kernel/plugin-spec.mdx, protocol/kernel/index.mdx, protocol/kernel/metadata-service.mdx and a releases/ line. It is documented nowhere in the Deployment group, despite being the command that puts an app into a running runtime, in two distinct modes:
os package install com.acme.crm --version 1.2.0 # catalog mode: the runtime fetches from its own catalog
os package install ./dist/objectstack.json # air-gapped mode: artifact sent inline, no catalog
It also has flags nothing documents: --runtime / OS_RUNTIME_URL, --email / --password (an account on the target runtime, not the cloud login), and --confirm-global-uniques (ADR-0120 D5e, recorded in the install manifest).
Why it matters now
#8910 made publish-and-preview.mdx the page that states how a metadata app reaches a platform, and that card's instruction was "link to the CLI reference, do not restate it." The link is there, but it lands on a reference that does not cover the two commands the page is about — so a reader following it for flags finds nothing, and the omission now sits directly downstream of a page that points at it.
Suggested shape
A #### os package publish and #### os package install under ## Commands (probably a new ### Packages subsection, or folded into ### Cloud Environments), each with the flag table and one example per mode — matching how os migrate and os cloud login are already covered. publish-and-preview.mdx keeps the narrative and the choosing rule; the flag-level detail belongs here.
Not urgent, not blocking — recording it so it does not stay buried.
Triage: lands in content/docs/deployment/cli.mdx (verified on origin/main: the only mention of either command is prose at :1192; no #### entry, no flag table). Filer's domain:devx matches the lane table — kept (label producer discipline noted; the route is ratified, not re-derived). Type Task (docs coverage gap, no declared contract violated), → pm:queue, no decision required — the card's suggested shape (a ### Packages subsection with one entry per command, flag tables, one example per mode) mirrors existing command coverage.
Sequencing: this sits directly downstream of #8910 / PR #8962 (publish-and-preview now links here) — prefer dispatch after that PR lands so the entries match the merged narrative. cli.mdx is reference-tier in #8913's pending restructure and that card explicitly does not split it; adding entries here does not collide with #8913's file surface (index.mdx + meta.json), but the claimant should name #8913 in the serial-constraints line anyway.
Serial constraints: #8913 (pending deployment/ restructure) touches index.mdx + meta.json and explicitly does not split cli.mdx — no collision with this surface, naming it here per triage. #8910 / PR #8962 (publish-and-preview.mdx) is upstream narrative and is not edited by this PR.
Flags will be read from packages/cli/src/commands/package/publish.ts and .../install.ts, not from the card.
{
"issue": 8965,
"status": "done",
"branch": "claude/issue-8965-package-commands-reference",
"pr": "https://github.com/objectstack-ai/objectstack/pull/9021",
"premise_still_valid": true,
"summary": "Premise re-verified on origin/main at b849d9e33: cli.mdx had 0 entries for either command, both sources exist. Added a `### Packages` subsection under `## Commands` with `#### os package publish` and `#### os package install`, each a full flag table plus one example per mode, matching the `os migrate` / `os cloud login` shape. Chose a new subsection over folding into `### Cloud Environments` because install does not touch the cloud at all in air-gapped mode (it POSTs to a running runtime's local install endpoint) and the two commands pair with each other, not with environments; placed after Cloud Environments so the `os cloud login` credential and `--env` environment ids are both introduced first. Every flag was read from publish.ts / install.ts, which is how the card's list turned out to be install's flags ONLY -- publish has a disjoint 23-flag surface on the cloud identity (--server/OS_CLOUD_URL, --token/OS_CLOUD_API_KEY) that the card named none of; install additionally has --timeout/OS_CLOUD_TIMEOUT_MS, -r/-v short forms, --version defaulting to latest, and the OS_RUNTIME_EMAIL/OS_RUNTIME_PASSWORD env spellings. Purely additive: 154 insertions, 0 deletions, 1 file. publish-and-preview.mdx untouched.",
"tests": "Gate union re-derived against the actual changed path and run AFTER the final commit, at HEAD 6bc51c9ea with `git status --porcelain` empty at that sha (same sha as PR head 6bc51c9eaa9d): check:role-word PASS (43 baselined files, no new occurrences -- this file's baseline of 1 unchanged), check:docs-audit-scope PASS (178 hand-written docs in sync), check:doc-anchors PASS (231 internal fragment links resolve), check:nul-bytes PASS (5947 text files, no raw control bytes), check:doc-authoring PASS (376 files clean). dispatch-gates.mjs named only check:docs-audit-scope + check:role-word; I added check:doc-anchors, check:nul-bytes and check:doc-authoring from the real diff (new fragment links / any-edit / new doc prose). The three CLI tests that pin prose in this file, run under flock on the shared lock after `pnpm --filter '@objectstack/cli^...' build`: `pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 test/cloud-login-json-ndjson.e2e.test.ts test/login-json-ndjson.e2e.test.ts test/login-json-noninteractive.e2e.test.ts` -> 'Test Files 3 passed (3) / Tests 42 passed (42)'. Reverse verification of the anchor gate from the COMMITTED state, direction decided in advance as red and observed red: breaking one newly-added fragment link gave 'ELIFECYCLE Command failed with exit code 1'; `git checkout HEAD -- content/docs/deployment/cli.mdx` restored it to green with porcelain empty and the ablation marker count back to 0. No ablation-on-dist here -- this is a docs-only change, so no package artifact is involved and no rebuild applies. Page-path links: the one added (/docs/deployment/publish-and-preview) resolves to a real file; lychee is NOT installed in this container, so the advisory `Check Documentation Links` job is the authority on that half -- flagged rather than claimed. CI status at report time: in_progress (reporting at draft-PR time per contract, not waiting).",
"open_questions": [],
"out_of_scope_findings": [
"filed as #9022 (label `finding`, unassigned, no pm:queue): install.ts's comment claims the --confirm-global-uniques affirmation lands 'where os doctor can later show who affirmed it and when', but os doctor only uses the attestation to SUPPRESS re-reporting via unconfirmedGlobalUniques(), which reads solely posture + confirmed. GlobalUniqueAttestation declares attestedAt and attestedBy and recordGlobalUniqueAttestation maintains them, yet nothing reads either. I documented the measured behaviour in cli.mdx rather than inheriting the over-claim (Prime Directive #10)."
]
}
Label state, read back after bots settled: PR #9021 carries ["documentation", "skip-changeset"]. A labeler applied skip-changeset before I could write it, so I made no label write — a whole-set PUT would only have risked clobbering a concurrent bot write, and the read is what closes this step.
Notes for the PM
The card's flag list was install's only. It attributed --runtime / --email / --password / --confirm-global-uniques to the pair; os package publish shares none of them. This is the fourth instance tonight of an incomplete PM-supplied list — the dispatch instruction to read the sources is doing real work and should stay.
No decision was required, so open_questions is empty rather than padded.
PR body: read back after creation and intact, footer in session-URL form. The PR shows comments: 1 from a non-me actor; per ground rule 2 I left it alone and did not touch any state I did not set.
Activity
os-project-manager commentedon Aug 16, 2026
Triage: lands in
content/docs/deployment/cli.mdx(verified onorigin/main: the only mention of either command is prose at:1192; no####entry, no flag table). Filer'sdomain:devxmatches the lane table — kept (label producer discipline noted; the route is ratified, not re-derived). TypeTask(docs coverage gap, no declared contract violated), →pm:queue, no decision required — the card's suggested shape (a### Packagessubsection with one entry per command, flag tables, one example per mode) mirrors existing command coverage.Sequencing: this sits directly downstream of #8910 / PR #8962 (
publish-and-previewnow links here) — prefer dispatch after that PR lands so the entries match the merged narrative.cli.mdxis reference-tier in #8913's pending restructure and that card explicitly does not split it; adding entries here does not collide with #8913's file surface (index.mdx+meta.json), but the claimant should name #8913 in the serial-constraints line anyway.Dedup: only self-hit.
Size/model suggestion: S–M, sonnet.
Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
Claiming this card.
session_011RB4waLuNbdruCo6X9oobmclaude/issue-8965-package-commands-referencecontent/docs/deployment/cli.mdxonly.Serial constraints: #8913 (pending
deployment/restructure) touchesindex.mdx+meta.jsonand explicitly does not splitcli.mdx— no collision with this surface, naming it here per triage. #8910 / PR #8962 (publish-and-preview.mdx) is upstream narrative and is not edited by this PR.Flags will be read from
packages/cli/src/commands/package/publish.tsand.../install.ts, not from the card.Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
{ "issue": 8965, "status": "done", "branch": "claude/issue-8965-package-commands-reference", "pr": "https://github.com/objectstack-ai/objectstack/pull/9021", "premise_still_valid": true, "summary": "Premise re-verified on origin/main at b849d9e33: cli.mdx had 0 entries for either command, both sources exist. Added a `### Packages` subsection under `## Commands` with `#### os package publish` and `#### os package install`, each a full flag table plus one example per mode, matching the `os migrate` / `os cloud login` shape. Chose a new subsection over folding into `### Cloud Environments` because install does not touch the cloud at all in air-gapped mode (it POSTs to a running runtime's local install endpoint) and the two commands pair with each other, not with environments; placed after Cloud Environments so the `os cloud login` credential and `--env` environment ids are both introduced first. Every flag was read from publish.ts / install.ts, which is how the card's list turned out to be install's flags ONLY -- publish has a disjoint 23-flag surface on the cloud identity (--server/OS_CLOUD_URL, --token/OS_CLOUD_API_KEY) that the card named none of; install additionally has --timeout/OS_CLOUD_TIMEOUT_MS, -r/-v short forms, --version defaulting to latest, and the OS_RUNTIME_EMAIL/OS_RUNTIME_PASSWORD env spellings. Purely additive: 154 insertions, 0 deletions, 1 file. publish-and-preview.mdx untouched.", "tests": "Gate union re-derived against the actual changed path and run AFTER the final commit, at HEAD 6bc51c9ea with `git status --porcelain` empty at that sha (same sha as PR head 6bc51c9eaa9d): check:role-word PASS (43 baselined files, no new occurrences -- this file's baseline of 1 unchanged), check:docs-audit-scope PASS (178 hand-written docs in sync), check:doc-anchors PASS (231 internal fragment links resolve), check:nul-bytes PASS (5947 text files, no raw control bytes), check:doc-authoring PASS (376 files clean). dispatch-gates.mjs named only check:docs-audit-scope + check:role-word; I added check:doc-anchors, check:nul-bytes and check:doc-authoring from the real diff (new fragment links / any-edit / new doc prose). The three CLI tests that pin prose in this file, run under flock on the shared lock after `pnpm --filter '@objectstack/cli^...' build`: `pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 test/cloud-login-json-ndjson.e2e.test.ts test/login-json-ndjson.e2e.test.ts test/login-json-noninteractive.e2e.test.ts` -> 'Test Files 3 passed (3) / Tests 42 passed (42)'. Reverse verification of the anchor gate from the COMMITTED state, direction decided in advance as red and observed red: breaking one newly-added fragment link gave 'ELIFECYCLE Command failed with exit code 1'; `git checkout HEAD -- content/docs/deployment/cli.mdx` restored it to green with porcelain empty and the ablation marker count back to 0. No ablation-on-dist here -- this is a docs-only change, so no package artifact is involved and no rebuild applies. Page-path links: the one added (/docs/deployment/publish-and-preview) resolves to a real file; lychee is NOT installed in this container, so the advisory `Check Documentation Links` job is the authority on that half -- flagged rather than claimed. CI status at report time: in_progress (reporting at draft-PR time per contract, not waiting).", "open_questions": [], "out_of_scope_findings": [ "filed as #9022 (label `finding`, unassigned, no pm:queue): install.ts's comment claims the --confirm-global-uniques affirmation lands 'where os doctor can later show who affirmed it and when', but os doctor only uses the attestation to SUPPRESS re-reporting via unconfirmedGlobalUniques(), which reads solely posture + confirmed. GlobalUniqueAttestation declares attestedAt and attestedBy and recordGlobalUniqueAttestation maintains them, yet nothing reads either. I documented the measured behaviour in cli.mdx rather than inheriting the over-claim (Prime Directive #10)." ] }Label state, read back after bots settled: PR #9021 carries
["documentation", "skip-changeset"]. A labeler appliedskip-changesetbefore I could write it, so I made no label write — a whole-set PUT would only have risked clobbering a concurrent bot write, and the read is what closes this step.Notes for the PM
--runtime/--email/--password/--confirm-global-uniquesto the pair;os package publishshares none of them. This is the fourth instance tonight of an incomplete PM-supplied list — the dispatch instruction to read the sources is doing real work and should stay.open_questionsis empty rather than padded.comments: 1from a non-me actor; per ground rule 2 I left it alone and did not touch any state I did not set.Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
✅ ACCEPT — PR #9021 已武装
🔴 卡片给的 flag 清单不是「不全」,是另一个命令的
这是今晚同类问题里最严重的一次,值得单独写下来。
卡片列了
--runtime/OS_RUNTIME_URL、--email/--password、--confirm-global-uniques,读起来像是在描述两个命令。dev 去读源码,发现那全是install的 flag:⇒
publish有一套完全不相交的 23 个 flag 的云身份面(--server/OS_CLOUD_URL、--token/OS_CLOUD_API_KEY),卡片一个都没提。照抄的人会在os package publish底下写一个它根本没有的--runtime,而且是写进命令参考里 —— 读者正是为了 flag 级细节才被 #8910 指过来的。install那边卡片也漏了:--timeout/OS_CLOUD_TIMEOUT_MS、-r/-v短写、--version默认 latest、OS_RUNTIME_EMAIL/OS_RUNTIME_PASSWORD环境变量拼法。本任期第四次「卡片/PM 给的清单是错的」 —— 前三次是 #8946 的平表、#8900 的计数、#8995 的两页。前三次是不全,这次是张冠李戴。⇒「⛔ 自己读实现,不要抄清单」在派发词里必须是硬条款,我已经这么写了,这次是它兑现。
复核(按内容)
### Packages在:1283,位于### Cloud Environments(:1248)之后;#### os package publish:1299、#### os package install:1378publish-and-preview.mdx分节理由站得住:没有折进
Cloud Environments,因为install在 air-gapped 模式下完全不碰云(POST 到运行中 runtime 的本地安装端点);而放在 Cloud Environments 之后,是为了让os cloud login的凭据与--env的环境 id 先被介绍过。这是按命令实际行为分节,不是按名字相近。⭐ 它跑了那三个钉散文的 CLI 测试
3 passed / 42 tests—— 我在派发词里点名要求的,因为今晚正好有一次 docs 重写改掉了被正则钉住的措辞、在合并队列里把 PR 踢了出来。这次提前挡住了。锚点门禁也做了反向验证:从已提交状态故意打断一条新加的 fragment 链接 → 红(exit 1);
git checkout HEAD --还原 → 绿,porcelain 空。方向是事先声明的。并且它标注了自己的边界:容器里没有 lychee,所以 page-path 链接那一半它声明由 CI 的⚠️ 这正是今晚 #8996 踩过的坑(
Check Documentation Links作准,而不是替它宣称通过。check:doc-anchors只管#fragment,页面路径是另一个 job)—— 它没有把两者混为一谈。⭐ #9022:它拒绝把一句过度声明搬进用户文档
install.ts的注释说--confirm-global-uniques的确认会落在「os doctor之后能显示是谁在何时确认的」地方。实测:os doctor只用该确认去抑制重复上报(unconfirmedGlobalUniques()只读 posture + confirmed);GlobalUniqueAttestation声明了attestedAt/attestedBy,recordGlobalUniqueAttestation也在维护它们,但没有任何地方读它们。⇒ 它在
cli.mdx里写的是实测行为,而不是继承那句注释。这正是本会话反复出现的那条:一句没测过的话被抄进用户可见文本,就会变成出厂的假声明(#8959 是同一个形状,而那次已经进了 changeset)。落地判据:
cli.mdx含### Packages与两个#### os package …条目;total_count == 1。Generated by Claude Code
test(cli): hold `content/docs/deployment/cli.mdx`'s two enumerations …