Skip to content

feat(skills): publish the skills catalog as @objectstack/skills in the fixed group - #22691

Merged
os-zhuang merged 7 commits into
mainfrom
claude/issue-22658-skills-package
Oct 11, 2026
Merged

os-zhuang merged 7 commits into
mainfrom
claude/issue-22658-skills-package

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #22658
Clause-②: no

Ruling A on #22649 (record 6096124407, maintainer 「22649 同意 A」): the published skills catalog ships as a versioned package in the changeset fixed group. This is PR 1 of the two the card allows — the package. PR 2 (claude/issue-22658-compat-line-derived, Tier H) derives the frontmatter lines; the cli and devx halves (#22659, #22668) remain open and consume what this PR publishes.

What this adds

  • packages/skills/ — a new publishable package @objectstack/skills (version 17.7.0, the fixed group's; publishConfig.access: public; files: dist, README.md, CHANGELOG.md; exports names only ./package.json, the @objectstack/console shape for a package with no JS entry). No second copy of a skill is committed and nothing is symlinked: dist/ is gitignored and produced by the build.
  • packages/skills/scripts/sync-catalog.mjs — the build: wipe dist/, copy the repository root's skills/** into dist/skills/**, read the copy back and refuse to finish unless the two trees are equal file for file and byte for byte; --check runs that same comparison and is the package's prepack, so pnpm pack / pnpm publish refuse a stale or absent tree; --self-test (nine batteries over temp fixtures: byte equality, idempotence, a deleted source file not surviving a rebuild, byte change / extra file / missing file / absent tree each red, an empty catalog refused, a symlink refused rather than followed) runs as the first leg of the package's build, the --self-test && run idiom every check:* alias uses, so it is never dormant and needs no new gate.
  • .changeset/config.json — @objectstack/skills joins the fixed group (70 members); .changeset/22658-skills-package.md — minor for the new package, plus a patch line for @objectstack/spec because packages/spec/llms.txt (a published file) counts the scoped packages and check:llms-txt moved it 68 → 69.
  • pnpm-lock.yaml — the new importer (packages/skills: {}), as pnpm install writes it; pnpm-workspace.yaml is untouched (packages/* already covers it).

Why dist/skills/, measured

skills@1.7.2's experimental_sync discovers a dependency's skills at exactly two places, read from its discoverPackageSkills: PKG/skills/NAME/SKILL.md and PKG/dist/skills/NAME/SKILL.md. Of the two, dist/ is the one this repository already treats as a build output everywhere: canonical in files for check:published-files (no EXTRA_ENTRIES row), gitignored repo-wide, turbo's default outputs, and skipped by the directory walk of check:published-readme-exports / check:published-readme-links — a copy at PKG/skills/ would have put all 53 catalog markdown files into those two gates' published-markdown population whenever a build had run, so their verdict would have depended on local build state. The sibling cards wrote node_modules/@objectstack/skills/skills/* before this measurement; the path they consume is node_modules/@objectstack/skills/dist/skills/NAME/.

Tarball and consumer measurement (the card's Done-when)

pnpm pack from packages/skills on the built tree: prepack ran --check (65 files byte-identical), tarball objectstack-skills-17.7.0.tgz, 68 entries — 65 under package/dist/skills/ (10 SKILL.md, 21 references, 18 rules, 15 evals, the catalog README) plus package.json, README.md, LICENSE. Installed in a throwaway project outside the repository (npm install --save-dev FILE.tgz), then npx -y skills@latest experimental_sync --yes --agent claude-code:

  • Found 10 skills in node_modules, each listed as NAME from @objectstack/skills;
  • wrote .agents/skills/NAME as a symlink to ../../node_modules/@objectstack/skills/dist/skills/NAME and .claude/skills/NAME as a symlink to ../../.agents/skills/NAME; 64 files reachable through .claude/skills (65 minus the catalog README, which is not a skill); diff -r of .agents/skills/objectstack-data against the package copy: identical;
  • skills-lock.json records each skill with source: @objectstack/skills, sourceType: node_modules, skillPath: dist/skills/NAME/SKILL.md, version: 17.7.0.

So the sync fits the layout; --copy copies instead of linking. The cli card can use the sync as is.

Every gate that must learn a no-JS package, through its declared path

  • check:type-check-coverage — an EXEMPT ledger row beside @objectstack/console (no TypeScript sources, no tsconfig).
  • check:dts-closure, check:dual-build-cjs-loads, check:sourcemap-no-sources-content, check:lean-entry-closure — nothing declared: the populations are derived (a built package whose manifest declares no declaration path owes none; no require entry, no .map, no lean entry). Measured on the fully built tree: check-dts-closure: 1 built package(s) declare no declaration entry point and owe none on the package alone, and all four green over the 73-task build.
  • check:published-files — dist + README + CHANGELOG are canonical; exports present (70 publishable packages, census floor 50).
  • check-published-list-mirrors does not fit (it mirrors a constant into AGENTS.md), so byte equality is proven by the copy step's self-test, as the card allows.
  • turbo.json — @objectstack/skills#build declares $TURBO_ROOT$/skills/** as an input (otherwise an edit under skills/** is a cache hit replaying a stale copy, remote cache included). Probe on this tree: one byte appended to skills/objectstack-data/SKILL.md → cache miss, executing aca937c23b400d14; restored to HEAD (blob equal, git diff HEAD empty) → cache hit, replaying logs 47fea834c3a0ce5a.
  • .github/workflows/ci.yml — the core: filter gains skills/**, because check-ci-filter-parity requires every $TURBO_ROOT$ build input to be covered there (OK: all 21 build input(s) … covered by core). Its self-test pins the live crosspkg rollback count over the LIVE table on purpose; with core now covering the skills root the rollback uncovers 19 instead of 22, and the pin moved with the tree (the two by-name assertions now assert coverage through core), recorded in its comment.
  • check:lockstep-package-count --fix — the three prose restatements of the group's size (two in content/docs/protocol/backward-compatibility.mdx, one in scripts/publish-smoke-pack.mjs's header) 69 → 70; check:llms-txt — packages/spec/llms.txt 68 → 69 (the gate's own remedy: the number and the prose).

pnpm changeset status: @objectstack/skills is listed among the 70 fixed-group packages to be bumped, at the group's pending level (major, from the v18 stock already on main).

Gates run (exit codes captured before any pipe)

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the changed set and reconciled with --ran: 140 derived, 140 run, 0 UNRUN. All exit 0 except two prerequisite refusals (exit 3, NOT MEASURED, neither reads this diff's surface): check-plugin-teardown-shape --self-test (needs an unshallow clone) and, before the build, check:docs-transcript-drift (needs @objectstack/lint built — green after the build). Highlights: check:published-files, check:type-check-coverage, check:type-check-debt, check:ci-filter-parity (+ self-test, 131 assertions), check:changeset-fixed (70 public packages in sync), check:lockstep-package-count, check:llms-txt, check:published-readme-links (102 published markdown files), check:published-readme-exports, check:dts-closure, check:dual-build-cjs-loads, check:sourcemap-no-sources-content, check:lean-entry-closure, check:skill-compatibility, check:skill-identifier-liveness, check:doc-authoring, check:nul-bytes, check:pm-governed-prose, check:merge-driver, the three changeset gates against origin/main, spec check:docs / check:skill-examples (262 prose examples type-check), check:pm-dispatch-gates (fast tier: 1825 cases pass; 6 slow sections deferred to CI). Full workspace build under the verify lock: 73 tasks successful, VERDICT command-exit 0, held 350s.

Lint, narrowed and measured at 3372d78b1: eslint over the four JavaScript files this PR touches (packages/skills/scripts/sync-catalog.mjs, scripts/check-ci-filter-parity.mjs, scripts/check-type-check-coverage.mjs, scripts/publish-smoke-pack.mjs) — --format json: 4 files, 0 errors, 0 warnings. Population: eslint.config.mjs judges .; invariance: the config enables no type-aware linting (its own note: no parserOptions.project, no typed rules), so this diff cannot move the verdict of any untouched file; the repo-wide run is CI's.

Acceptance notes

维护者速读(草稿)

  • 改了什么:新增发布包 @objectstack/skills,构建时把仓库根目录的 skills/** 原样复制进 dist/skills/,进 changeset fixed 组,版本号恒等于 @objectstack/spec。skills/** 本身不动、不搬、不做符号链接。
  • 为什么改:今天装 17.7.0 的项目从仓库 main 取技能,拿到的是在教 v18 写法的文本;发成包以后,装哪个版本就拿哪个版本的技能(已用打包 + npx skills experimental_sync 实测:10 个技能全部从 node_modules 装入)。
  • 风险与代价(含回滚):多一个发布包;fixed 组从 69 变 70,三处文案计数与 llms.txt 的计数随之改动。回滚 = 从 fixed 组移除并删掉目录,其余文件不受影响。
  • 席位意见:(留空)
  • 你要做的:这张 PR 不是受管面,走队列即可;你要批的是第二张(十个 SKILL.md 的两行派生)。

Generated by Claude Code

…e fixed group

The repository's skills/** ships as a versioned package: a new publishable
package whose build copies the catalog into dist/skills/** byte for byte
(scripts/sync-catalog.mjs, self-tested, --check at prepack) and whose files
lists only that tree. The package joins the changeset fixed group, so its
version is always the version of the @objectstack/* packages it teaches.

Declared paths for the no-JS shape: the type-check coverage EXEMPT ledger, a
turbo build override declaring $TURBO_ROOT$/skills/** as the build's input,
the ci.yml core filter carrying that input (check-ci-filter-parity), and the
parity self-test's live-tree pin moved with it. check-lockstep-package-count
--fix moved the three prose restatements of the group's size to 70.

Claude-Session: https://claude.ai/code/session_01RdnZdPZH9ByduzPRWuH9tN
Co-authored-by: Claude <noreply@anthropic.com>
…/skills in scope

check:llms-txt reconciles the package-ecosystem heading against the real
non-private @objectstack/* workspace; the new package moves it 68 -> 69.
The changeset carries the patch line for the published file.

Claude-Session: https://claude.ai/code/session_01RdnZdPZH9ByduzPRWuH9tN
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tooling labels Oct 10, 2026
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 4 changed file(s) yielded no anchor (packages/skills/.gitignore, packages/skills/README.md, packages/skills/package.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 2 changed package(s)).

What this run could not see
  • 4 changed file(s) yielded no anchor (packages/skills/.gitignore, packages/skills/README.md, packages/skills/package.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 996aa86e0a2f21423b321250085479427a36758b → packageMentionDocs.

…ADME's unlanded claim

pnpm pack --json prints its lifecycle banner on stdout ahead of the JSON, and
scripts/publish-smoke-pack.mjs parses that stdout, so a prepack on any
publishable package reds both smokes at their pack step (reproduced:
`pnpm pack --json returned non-JSON for @objectstack/skills`). The check
moves to prepublishOnly, the @objectstack/console shape: pnpm publish still
refuses a stale or absent tree; pnpm pack runs no lifecycle script.

The README no longer says the scaffolder and the docs read the catalog from
this package: neither has landed, and a published README states only what
the platform does.

Claude-Session: https://claude.ai/code/session_01RdnZdPZH9ByduzPRWuH9tN
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants