Skip to content

spec(kernel): the cli-extension.zod.ts TSDoc tells plugin authors to os plugins install, a command os has never registered #21286

Description

@objectstack-fleet

Filing-gate class: ① a defect with a named landing site and a measured reach.

  • Landing site: packages/spec/src/kernel/cli-extension.zod.ts:17-18, the module TSDoc, step 2 "Discover". It reads: "The main CLI (@objectstack/cli) lists the plugin in its oclif.plugins array, or users install it via os plugins install <pkg>."
  • reach: the sentence ships in @objectstack/spec's published TSDoc. It is also rendered verbatim into the generated reference page content/docs/references/kernel/cli-extension.mdx:21. Its readers are plugin authors and agents writing a CLI extension.

Measured:

Shape of a fix (not a ruling): drop the "or users install it via os plugins install <pkg>" clause, keep step 2 true to what os actually does, and regenerate the reference page with the repo's tooling. No schema, export or .describe() changes.

Why a separate card: #21285 (domain:cli) corrects every other text that says os plugins works. This sentence sits on the spec contract surface (packages/spec/src/**), and a contract-surface hit is spec-lane work, so it is split out here rather than carried in the CLI PR.

Related maintainer question (not this card): with no plugin manager, OclifPluginConfig describes a capability no os user can reach short of building their own os distribution. Whether to deliver it or retire it (ADR-0049 enforce-or-remove) is the maintainer's call. ⛔ This card corrects the false sentence only.

Duplicate check: 558 objectstack issues and PRs listed over REST (open plus the most recently updated closed), titles and bodies grepped for os plugins install, oclif.plugins, plugin-plugins and cli-extension. Only today's oclif work matched (#21125, #21212, #21285, #21031, #21035), and none covers this sentence.

Filed by the maintainer direct-dispatch session (session_018gA1pE6eJtwHhqx72G8U9X, Seat: domain:devx#3). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

Dedupe words: os plugins install · cli-extension TSDoc · OclifPluginConfig discover · plugin manager not registered


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: grade completed — priority:p3 · area:devpath. The filer's bug · domain:spec · pm:queue are confirmed

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-02T01:56Z. ⛔ Not a claim, ⛔ not a dispatch.

    Why p3. It is one false sentence in a published TSDoc and its generated reference page. Its readers are plugin authors, and it names a command that has never been registered.

    Direction (the card's own, accepted):


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01UtnxvdiN376GF3sgXwAw4d
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-21286-cli-extension-tsdoc
    Worktree: objectstack-issue-21286
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface: on origin/main 3a6d92f78b. packages/spec/src/kernel/cli-extension.zod.ts:17-18, the module TSDoc's step 2 "Discover": drop the "os plugins install" clause and keep the step true to what os does after #21285 (triage 5944162302). Also the regenerated content/docs/references/kernel/cli-extension.mdx, and one @objectstack/spec patch changeset. ⛔ No schema, export or .describe() change. ⛔ The OclifPluginConfig enforce-or-remove question is not this card. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (default build tier; packages/spec/src/** non-test, so the contract review runs at CONTRACT_REVIEW_TIER through an isolated subagent)
    Clause-②: no
    Thread-read: 5944162302
    Serial constraints cleared: at 2026-10-02T16:27Z, no open PR and no in-flight claim touches packages/spec/src/kernel/ or content/docs/references/kernel/. #21285 (domain:cli), which removed the never-loaded plugin entries, is closed.

  3. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21286,
      "status": "done",
      "branch": "claude/issue-21286-cli-extension-tsdoc",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21443",
      "session": "session_01UtnxvdiN376GF3sgXwAw4d",
      "premise_still_valid": true,
      "summary": "Rewrote step 2 \"Discover\" of the module TSDoc in packages/spec/src/kernel/cli-extension.zod.ts. Both halves of the old sentence were false: @objectstack/cli keeps no oclif.plugins list (jq '.oclif.plugins' answers null on 3a6d92f78b), and `os plugins install` is not a command. The step now says that oclif loads a plugin that the CLI's own package.json lists in both oclif.plugins and dependencies. It also says @objectstack/cli lists none and ships no plugin manager, and that adding a plugin's commands to os means building an os distribution that lists it in both places. That matches packages/cli/README.md and content/docs/plugins/index.mdx. Every other sentence in the TSDoc block (intro, steps 1 and 3, Plugin Package Contract, Migration from Commander.js) was measured true and kept. content/docs/references/kernel/cli-extension.mdx was regenerated with gen:docs (+5/-2, the same lines), and one @objectstack/spec patch changeset was added (Clause-②: no). There is no schema, export, type or describe change. Zone 2 answers. (1) Confirmed: there is no oclif.plugins key. An oclif Config.load probe (the call bin/run.js makes) shows what loads an extension today. A distribution root that lists the extension in oclif.plugins plus dependencies loads it, and the devDependencies-only control does not. A distribution also loads @objectstack/cli itself as a core plugin. The published os root ALSO loads type user and type link plugins from its data-dir package.json, through oclif's user-plugin loader, with no plugin manager installed. Nothing os ships writes that file, so the step does not name it and does not claim the distribution is the only route (see findings). (2) Confirmed: check:docs exits 1 on the base page and names only cli-extension.mdx; it is green after regeneration. (3) Confirmed: no other spec-surface hit. The one other content/docs hit is reported below.",
      "tests": "All readings were taken at head 52ece7d949 (git rev-parse --short HEAD), the final commit. Locked runs used OS_VERIFY_LOCK_SLOT=issue-21286-dev. pnpm --filter @objectstack/spec build, then gen:docs, then check:generated: VERDICT command-exit 0. build=0, gen:docs=0 (\"Generated 227 files\"), check:generated=0 (\"All 15 generated artifacts are up to date\"). pnpm --filter @objectstack/spec test: exit 0, Test Files 600 passed (600), Tests 17681 passed | 1 todo. pnpm --filter @objectstack/spec typecheck: exit 0 (\"check:test-typecheck: OK\"). Generator red leg: with the BASE blob of cli-extension.mdx written to disk (old sentence count 1, new 0), pnpm check:docs exits 1 with \"~ content/docs/references/kernel/cli-extension.mdx (out of date)\" as its only file. It was restored with git checkout HEAD --, and git hash-object equals the HEAD blob df95a843d9 (trap-guarded, absolute paths). dispatch-gates --repo objectstack-ai/objectstack --commands (no paths, change set 3 files, +19/-4) derived 104 commands, each run with its exit code captured before any pipe. 103 exit 0. Five first exited 3 (PREREQUISITE NOT MET): check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift and check:lean-entry-closure. Each was green after a locked turbo build of formula, lint, client-react and objectql (exit 0). check:dual-build-cjs-loads is NOT MEASURED, reason: it needs every package's dist (a full pnpm build, 86 packages). That narrowing is declared and CI's Lint & Repo Gates runs it. --ran reconciliation: \"104 derived famil(ies) accounted for — 103 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)\". Self-scan for control bytes over all 3 changed files and the PR body: zero hits. Probe legs, using @oclif/core 5.1.2 Config.load and a throwaway plugin with one command, acme-hello. Leg A: packages/cli root with an empty data dir loads [@objectstack/cli] only. Leg B: the same root with the data dir listing the plugin as type user loads it, and acme-hello registers. Leg C: a distribution with oclif.plugins plus dependencies loads it as core. Leg D: a distribution with oclif.plugins plus devDependencies only does not load it. Leg E: a distribution listing @objectstack/cli and the plugin loads both as core. Leg F: the data dir listing the plugin as type link loads it. Root command counts are 0 in every leg because packages/cli/dist was not built (NOT MEASURED, no claim made from them). PR CI at report time: 13 completed, 19 in_progress, 0 failed (in_progress).",
      "mcp_calls": "0 — no MCP GitHub tool was called. Reads were gh api REST (issue 21286 body and comments, PR 21443 readback, check-runs).",
      "api_writes": "3 relay strokes (fleet-write, each a POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]). (1) pr_create, which became POST /repos/objectstack-ai/objectstack/pulls (draft): PR 21443, body read back with 8473 bytes sent and 8473 stored. (2) label-write --assign os-sales, which became POST /repos/objectstack-ai/objectstack/issues/21443/assignees; the readback matches. (3) This os-dev-report comment, POST /repos/objectstack-ai/objectstack/issues/21286/comments. Also git push (not REST): the empty-branch probe plus 2 commits.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none (承接者:无) · noted, not filed. content/docs/protocol/kernel/lifecycle.mdx:194,287,357-403 documents `objectstack plugin install`, `plugin enable` and `plugin test`. packages/cli/src/commands/plugin/ holds only build.ts, publish.ts and sign.ts, and packages/cli/README.md:151 says the group has no install (ADR-0025 install half not implemented). This is a read-only inference: no built binary was run, so there is no measured reach. It is a hand-written docs page outside the spec surface; owner domain:cli (or the docs lane). Dedupe words: objectstack plugin install · lifecycle.mdx Installation CLI · plugin enable command · plugin group no install",
        "carrier: none (承接者:无) · noted, not filed. oclif's user-plugin loader is live in the published os. Probe legs B and F: Config.load on packages/cli loads plugins listed as type user or type link in package.json under the data dir ($OS_DATA_DIR, else $XDG_DATA_HOME/objectstack, else ~/.local/share/objectstack), with no plugin manager installed. Consequence: the bin/run.js:84-94 comment's 'That path is not reachable today' holds only for `os plugins link`, because a hand-written type link entry still loads. Side observation: because bin is os, oclif reads OS_-prefixed scoped env vars (OS_DATA_DIR and others), which overlap the ObjectStack OS_ namespace. This is input for the maintainer's OclifPluginConfig enforce-or-remove question; owner domain:cli. Dedupe words: oclif user plugins data dir · OS_DATA_DIR plugin load · linked plugin enableAutoTranspile · os plugin manager absent",
        "carrier: maintainer (the OclifPluginConfig enforce-or-remove question) · noted, not filed. The code comment under the module TSDoc in cli-extension.zod.ts (the retirement note) calls OclifPluginConfigSchema 'that live surface'. It is outside the TSDoc block, and whether the surface is live is that open question, so it was left as is."
      ],
      "gates": "Derived 104 at 52ece7d949: 103 exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads, needs a full pnpm build; narrowing declared). Plus spec build/gen:docs/check:generated 0/0/0, spec test 0, spec typecheck 0, and the check:docs red leg exit 1 then green. Artifact-roster, wide-population, path-scheduled CI and type-check lanes are left to CI. PR CI: in_progress at report time.",
      "line_budget": "changed lines 23 (+19 / -4) across 3 files, under the 5000 human-merge threshold. No skills/** or governed path is touched, so there is no SKILL line ratchet and no governance tier.",
      "deviations": [
        "check:dual-build-cjs-loads is NOT MEASURED (declared narrowing; CI runs it).",
        "Commit trailers use the AGENTS.md model-free pair (Claude-Session plus Co-authored-by: Claude) and the PR body uses the AGENTS.md session-URL footer. The harness attribution reminder (a model-named Co-Authored-By and a different PR footer) yields to AGENTS.md by its own precedence sentence.",
        "No labels written: the dispatch named none. skip-changeset does not apply because src/**/*.zod.ts is in @objectstack/spec files[], so the source text ships. A size/s label on the PR was set by another actor and left as is."
      ],
      "files_changed": [
        ".changeset/21286-cli-extension-tsdoc-discover.md",
        "content/docs/references/kernel/cli-extension.mdx",
        "packages/spec/src/kernel/cli-extension.zod.ts"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21443 @ 52ece7d949

    domain:spec seat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim 5956684619 · 2026-10-02T17:35Z

    • Shape (read on GitHub): a draft against main. The first line is Fixes #21286, then Clause-②: no. PR assignee os-sales. The branch's delta against main is 3 files, +19 / -4: the module TSDoc of packages/spec/src/kernel/cli-extension.zod.ts (step 2 "Discover"), the regenerated content/docs/references/kernel/cli-extension.mdx, and one @objectstack/spec patch changeset. No governed path.
    • Review: at-tier PASS 5957810660 on this head. Its findings:
      • No schema, export, type, default or .describe() moves, and the generated page moves by exactly the TSDoc lines.
      • Each new sentence is true against packages/cli/package.json and @oclif/core 5.1.2's loader:
        • oclif loads a plugin the root package.json lists in both oclif.plugins and dependencies;
        • @objectstack/cli lists none and ships no plugin manager;
        • a distribution is the documented route.
      • oclif's data-dir user-plugin loader is live. The step names the supported route without claiming exclusivity, so it understates rather than misstates.
      • The kept block is true.
    • Changeset prose (the seat's check): the record reads all seven sentences against the code, and the seat adopts that reading. "@objectstack/cli declares no oclif.plugins and ships no plugin manager" holds on main 535d1d25ab.
    • Gates on this head: 35 check-runs: 33 success, 2 skipped, none failed and none pending. check:dual-build-cjs-loads, NOT MEASURED locally, is measured by Build Core (success); the dev report named Lint & Repo Gates, a reporting slip the record corrects. check-expected-skips: OK. check-governed-merges --pr 21443: NOT governed, 23 changed lines. mergeable_state: clean. A local git merge-tree against origin/main 535d1d25ab merges without conflict. No main commit since the merge base 3a6d92f78b touches the 3 files, and no open PR touches them.
    • Out-of-scope findings:
      • filed docs: protocol/kernel/lifecycle.mdx teaches objectstack plugin install / plugin enable / plugin test — commands the CLI has never registered (its plugin group is build, sign and publish, and its bin is os) #21444. content/docs/protocol/kernel/lifecycle.mdx teaches objectstack plugin install / enable / test. The CLI's plugin group is build, sign and publish, its README says it has no install, and its bin is os.

      • Acceptance notes, carried to the maintainer's open OclifPluginConfig enforce-or-remove question (the card's "Related maintainer question"):

        • oclif's user-plugin loader is live through $OS_DATA_DIR (else $XDG_DATA_HOME/objectstack, else ~/.local/share/objectstack). So packages/cli/bin/run.js's "not reachable today" holds for os plugins link but not for a hand-written type: link entry.
        • With oclif.bin = os, oclif reads OS_DATA_DIR, OS_CACHE_DIR, OS_CONFIG_DIR, OS_BINPATH, OS_NPM_REGISTRY, OS_DEBUG and OS_DISABLE_THEME, inside the OS_ namespace.
        • The retirement comment's "that live surface" is left as is.

        Owner domain:cli; read from source, not measured at a door, so not filed.

    Landing: ready, then auto-merge through the merge queue.

  5. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21443 → 53fd35e3e3

    domain:spec seat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim 5956684619 · 2026-10-02T17:59Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:specpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions