Skip to content

Commit 468e0c1

Browse files
feat(spec)!: one marketplace taxonomy — business functions, industries, a solution type and maturity replace the single category (#30980)
Fixes #30904 Clause-②: yes (narrowing) — new facet keys and `maturity` widen; `category` retired and refused by name narrows; a contract review runs before the queue Metadata-protocol: narrowed > The claim (card comment 6683208761) and the dispatch declared `Clause-②: yes (widening)` / `Metadata-protocol: none`. `Check Changeset` refuses that pair on this diff, measured locally: `metadata-protocol declares none while an authorable-surface or authorable-defaults baseline moved` (`packages/spec/authorable-surface/marketplace.json`). AGENTS.md defines a tombstoned key as `narrowed`, and `narrowed` needs the `(narrowing)` arm and a `minor`, so the two lines above and the changeset carry that pair. The seat can still rule otherwise; see Acceptance notes. ## 维护者速读 - **改了什么:** 市场分类在 spec 里只定义一处:职能 `businessFunctions`(1–3 个,第一个是主职能)、行业 `industries`(0–3 个,可选)、类型 `solutionType`(app / template / connector),另加独立的 `maturity`(beta / stable)。两份旧的 `category` 按 ADR-0087 退役,带 `category` 的发布被点名拒绝并给出改法。 - **为什么改:** 一个 `category` 同时表示“给谁用”和“是什么”,平台和 cloud 各有一套取值且互相对不上;按维护者裁决 D1–D3 合并为一套。空白模板的 `"starter"` 会让每个新项目第一次发布被 cloud 拒绝,这里一并删掉。 - **风险与回滚:** 破坏性:还写着 `category` 的清单在发布时被拒(附映射)。运行时启动不读这些 schema,不受影响。cloud 在 cloud#3661 落地前会忽略新字段,且其提交审核仍要求 `category`,需要先落 cloud 再发 CLI(见 Acceptance notes)。回滚即 revert 本 PR。 - **先看:** `packages/spec/src/marketplace/taxonomy.zod.ts`(取值、上限、交叉校验、旧值映射);`packages/cli/src/commands/package/publish.ts` 的 `retiredCategoryRefusal` / `readPublishTaxonomy`;`packages/spec/liveness/template_manifest.json`(新纳入的台账与消费方)。 - **两分钟验证:** `pnpm --filter @objectstack/spec exec vitest run src/marketplace/taxonomy.test.ts`,预期 39 个测试全部通过;在任一 `objectstack.manifest.json` 里加 `"category": "finance"` 后跑 `os package publish`,预期在联网前被拒,提示 `"businessFunctions": ["finance"], "solutionType": "app"`。 - **需要你做的:** 无,席位落地(契约复核后由席位决定声明行与发布顺序)。 ## What changes <details><summary>spec — the taxonomy, defined once</summary> - New `packages/spec/src/marketplace/taxonomy.zod.ts`, exported from `@objectstack/spec/marketplace`: - `MarketplaceBusinessFunctionSchema` (11 values, ruling §2 F1) and `MarketplaceBusinessFunctionsSchema` (1–3 distinct, ordered, the first is primary). - `MarketplaceIndustrySchema` (10 values, §2 F2 / D1) and `MarketplaceIndustriesSchema` (0–3 distinct; no catch-all value — absence means cross-industry). - `MarketplaceSolutionTypeSchema` (`app` | `template` | `connector`; no `theme`, ADR-0019) and `PackageMaturitySchema` (`beta` | `stable`, D3 — a flag, not a facet). - `explainSolutionTypeContradiction(solutionType, { installModes, connectorCount })` — the publish cross-check: `template` needs `unmanaged` among the install modes (ADR-0131 D6), `connector` needs a declared connector. One rule and one sentence for the CLI and, through cloud#3661, the cloud publish gate. - `LEGACY_CATEGORY_MAPPING` — ruling §3.1 + §3.2: every value of the retired spec enum, the cloud list and its folded aliases → `mapped` / `manual` (author chooses the functions; never a catch-all) / `unlistable` (ADR-0019). `operations` is mapped and flagged `review`. - `PackageSchema` / `CreatePackageRequestSchema` / `UpdatePackageRequestSchema` / `TemplateManifestSchema` / `MarketplaceListingSchema` carry the four keys. Row shapes default `solutionType: 'app'` and `maturity: 'stable'`; requests and the manifest carry no default (absent stays absent, so a re-publish never rewrites a stored value). `businessFunctions` is required on the listing. - `MarketplaceSearchRequestSchema` filters by `businessFunctions` / `industries` / `solutionTypes` (OR inside a facet, AND across) and `maturity`; `MarketplaceSearchResponseSchema.facets` has one count list per facet. </details> <details><summary>spec — the ADR-0087 retirement of both category schemas</summary> - `category` is a `retiredKey()` tombstone on all six schemas (and `facets.categories` on the search response). The schemas are not strict, so a bare deletion would strip silently; the tombstone refuses with the prescription in both channels (`tsc`, parse). `TemplateManifestSchema` re-declares its own so the refusal names the file an author writes. - `MarketplaceCategorySchema` / `MarketplaceCategory` and `PackageCategorySchema` / `PackageCategory` are deleted: `RETIRED_DEFS_BY_MAJOR[18]` (two entries), the deliberate `json-schema.manifest/marketplace.json` deletion, and the two `scripts/lib/renamed-defs.ts` rows retired with a note. - Registration: six `RETIRED_KEYS_BY_MAJOR[18]` entries, one D3 semantic entry `marketplace-category-retired`, one `STEP18_RATIONALE` fragment. **No D2 conversion**: none of these shapes is a stack collection member (the `marketplace/PackageDependency:optional` precedent), so a conversion would be a transform no seam runs. - **Publish-time and boot-time consequence** for a manifest that still carries `category`: publish refuses it (the CLI before any network call; a parse of any of the schemas, with the prescription). Boot: nothing — no runtime boot reads `objectstack.manifest.json`, a package row or a listing (measured: the only readers of the file are `os package publish`, create-objectstack and `check:template-manifests`). So there is nothing for the boot to tolerate or refuse; ADR-0087's load-path conversion has no seam here, and the decision recorded in the D3 entry is refuse-at-publish, migrate-stored-rows-once (cloud#3661, reading `LEGACY_CATEGORY_MAPPING`). - Generated: `authorable-surface`, `authorable-defaults`, `json-schema.manifest`, `api-surface`, `export-origins`, `declaration-map`, `content/docs/references/marketplace/**`, the strictness-ledger counts; `dropped-refinements.baseline.json` declares the uniqueness refinement on the two facet lists (no projectable arm for "distinct items" exists); six ADR-0122 isomorphic pins (837 → 841). </details> <details><summary>CLI, first-party manifests, scenario library, docs</summary> - `os package publish` (`packages/cli/src/commands/package/publish.ts`): - refuses `category` in `objectstack.manifest.json` and the now-hidden `--category` flag before any network call, naming the facets for the value it held (from `LEGACY_CATEGORY_MAPPING`); a `starter` copied from the blank template is told it never classified the package; - judges each facet with the spec's own schema, cross-checks a declared `solutionType` against the built artifact (`resolveInstallModes` + the artifact's `connectors`), and sends them as `business_functions` / `industries` / `solution_type` / `maturity`; an absent facet is not sent. - Manifests: connector-stripe `[finance]`, connector-github `[it]`, connector-docusign `[collaboration, legal]`, each `solutionType: connector` (their listing tests now assert the stack declares the connector that makes them one). The create-objectstack blank template drops `category: "starter"` and declares **no** facet: create-objectstack copies this file into every scaffolded project, so a facet here would be inherited by projects it does not describe, and a `template` there would be refused by the new cross-check on the first publish (the blank config permits only `managed`). - `packages/qa/scenarios`: the hand copy `SCENARIO_CATEGORIES` is gone; a card's key is `businessFunctions`, typed by the spec schema. The nine cards are re-tagged per ruling §3.3. - Docs: `content/docs/deployment/marketplace-handbook.mdx`, `content/docs/deployment/cli.mdx`, `content/docs/protocol/kernel/plugin-spec.mdx`, `docs/qa/scenarios/README.md` — no hand copy of the value lists (the handbook links the generated taxonomy reference). - Liveness: `objectstack.manifest.json` (`TemplateManifestSchema`) enters the ledger as `template_manifest` via `SPEC_ONLY_SCHEMAS`. `businessFunctions` / `industries` / `maturity` are `planned`, naming their consumers — the cloud catalog (objectstack-ai/cloud#3661) and the console marketplace card the seat files; `solutionType` is `live` through the publish cross-check; `category` is the tombstone row. The platform checklist carries a measured waiver for it (no checklist item can drive a hosted publish). </details> ## Tests Measured on head `7cd7fe941c` (the commits after it are the changeset declaration and nothing a test reads). <details><summary>Suites</summary> - `pnpm --filter @objectstack/spec test` — exit 0 (818 + 1 files; the one earlier red, the dropped-refinements header totals, fixed and re-run green: 27/27). - `pnpm --filter @objectstack/spec typecheck` — exit 0. - `pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2` — exit 0, `Test Files 390 passed (390)`, `Tests 5496 passed (5496)`. Integration tier declared to CI (no spawn entry or driver path touched). - `pnpm --filter @objectstack/cli typecheck` — exit 0. - `pnpm --filter create-objectstack test` / `typecheck` — exit 0 / 0. - `pnpm --filter @objectstack/scenarios test` / `typecheck` — exit 0 / 0. - connector-stripe / connector-github / connector-docusign `test` — exit 0 each. - New: `packages/spec/src/marketplace/taxonomy.test.ts` (39 cases: one block per rule — F1, F2, F3, D3, the cross-check, the refusal on every schema, the registration, the mapping) and `packages/cli/test/package-publish-taxonomy.test.ts` (14 cases). </details> <details><summary>Ablations — one per rule, each through scripts/ablation-replace.mjs (mutation proven on disk, restore proven against HEAD)</summary> | Rule | Mutation | Result | |:--|:--|:--| | F1 at most 3 | `.max(MAX_BUSINESS_FUNCTIONS,` → `.max(99,` | 1 failed / 39 — "refuses a fourth value" | | F1 at least 1 | `.min(1,` → `.min(0,` | 1 failed / 39 | | F1/F2 distinct | the refine predicate → always true | 2 failed / 39 | | F2 at most 3 | `.max(MAX_INDUSTRIES,` → `.max(99,` | 1 failed / 39 | | template needs unmanaged | the template branch → `if (false)` | 1 failed / 39 | | connector needs a connector | the connector branch → `if (false)` | 1 failed / 39 | | category tombstone | delete `CreatePackageRequest.category` | 2 failed / 39 (the refusal and the tsc pin) | | CLI refuses manifest `category` | the guard → `if (false)` | 2 failed / 14 | | CLI refuses `--category` | the guard → `if (false)` | 1 failed / 14 | | CLI wires the cross-check | delete the refusal return | 3 failed / 14 | Every leg ends `git diff HEAD` empty for its file; the final tree carried 0 modified source paths. </details> ## Acceptance notes <details><summary>Every caller class that newly sees a refusal</summary> 1. A TypeScript author writing `category` on `Package` / `CreatePackageRequest` / `UpdatePackageRequest` / `TemplateManifest` / `MarketplaceListing` / `MarketplaceSearchRequest` — `tsc` error (the retired mark). 2. Any code parsing those schemas with `category` present — parse refusal with the prescription. Measured at cloud `8f574b9`: cloud reads only `PackageSchema.shape.manifestId` and `CreatePackageRequestSchema.shape.tags`, so its pin bump is not refused by this. 3. A TypeScript importer of `MarketplaceCategorySchema` / `PackageCategorySchema` / their types — compile error (zero importers here and in cloud at `8f574b9`). 4. `os package publish` with `category` in `objectstack.manifest.json` — refused before any network call. This includes every project already scaffolded from the blank template (`"starter"`). 5. `os package publish --category …` — refused. 6. A manifest declaring `solutionType: template` without the `unmanaged` install mode, or `connector` with no connector, or a malformed facet — refused (new keys, no existing caller). 7. A producer of `MarketplaceListingSchema` without `businessFunctions` — refused (new requirement; no producer in this repo). 8. A scenario card with `category`, or a business function outside the facet — loader refusal. 9. `check:template-manifests` — any shipped manifest with `category` reds. </details> <details><summary>Sequencing, declarations and what this PR deliberately does not do</summary> - **Cloud sequencing (needs the seat's call):** at cloud `8f574b9` the publish route picks named body keys, so the four facets are dropped until objectstack-ai/cloud#3661 lands, and `marketplace-policy.ts` still requires `category` at marketplace submission. A CLI released from this PR before cloud#3661 deploys can no longer satisfy that submission rule for a package that has no stored category. Order: cloud#3661 (accept the facets, require a business function instead of `category`) before the next CLI release reaches authors. - **Declarations:** see the quote under the declaration lines. The pair here is what `Check Changeset` accepts and what AGENTS.md defines; if the seat keeps `none`, the changeset must go back to `patch` and the level gate stays red on the moved authorable-surface shard. - **Blank template reproduction:** reproduced in two halves, not end to end. Cloud half executed: cloud `8f574b9`'s `isValidPackageCategory("starter")` returns `false` (the route answers 400 on it at `package-publish.ts:896`). CLI half read: at the base, publish sent `m.category` verbatim and create-objectstack copied the template's `category` into every project. - **Kebab-case values** (`customer-service`, `trade-distribution`, …) are the ruling's verbatim values and match the marketplace enums' existing spelling (`usage-based`, `in-review`); Prime Directive #3's snake_case is the general rule for machine names. - **`explainSolutionTypeContradiction` lives in the spec** as a pure function beside `resolveInstallModes`, so the CLI and the cloud gate share one rule and one sentence instead of two copies. - **Liveness enrolment found more than the taxonomy:** `name`, `specVersion`, `skills`, `scaffold`, and the warned-and-unsent `visibility` / `publisher` / `isStarter` have no reader of the file's value. Recorded `dead` in the new ledger, not retired here. - Not touched: HotCRM's manifest (hotcrm lane); cloud (cloud#3661); the console `ui/` (the seat files that card); `docs/design/marketplace-publishing.md` (a design record whose `--category` search example describes a command this repo does not ship). </details> ## Verification <details><summary>Gates — dispatch-gates.mjs derivation, reconciled</summary> - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran …` → `✓ 119 derived famil(ies) accounted for — 115 run, 4 NOT-MEASURED (4 DERIVED from a recorded exit 3).` - NOT MEASURED (exit 3, the gate's own prerequisite verdict — each needs a whole-workspace build outside this diff's closure; CI runs them): `check:skill-examples` (client-react has no `.d.ts`), `check:i18n-coverage` (`@objectstack/connector-slack` unbuilt), `check:dual-build-cjs-loads` (packages outside the closure unbuilt), `check:type-check-debt` (its own locked closure build never got the shared lock). - Fixed on the way: `check:llms-txt` (the marketplace row and the inventory total), `check:platform-checklist` (the `template_manifest` waiver), `check:test-source-alias` (the connector configs alias `@objectstack/spec/kernel` to source). - `pnpm --filter @objectstack/spec check:generated` — all artifacts current after `--fix`; `check:liveness`, `check:spec-parsed-alias`, `check-adr-0087-registration`, `check-changeset-no-major` (level axis, against this body) — exit 0. - `node scripts/check-platform-checklist.mjs --changed-from origin/main` — exit 0 (no anchored file in the change set). </details> <details><summary>Dogfood battery</summary> Owed on the final head (title `!`, `(narrowing)` arm). Its reading is in the report comment on the card. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01Q4EjjRhUZjdy8VXs6Kkur2)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 41dc302 commit 468e0c1

76 files changed

Lines changed: 2081 additions & 227 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/cli': minor
4+
'create-objectstack': patch
5+
---
6+
7+
feat(spec)!: one marketplace taxonomy — business functions, industries, a solution type and a maturity flag replace the single `category` (#30904)
8+
9+
Clause-②: yes (narrowing) — new facet keys and `maturity` widen; `category` retired and refused by name narrows; a contract review runs before the queue
10+
Metadata-protocol: narrowed
11+
12+
<!-- adr-0087: registered marketplace-category-retired -->
13+
14+
**BREAKING** for a package source, publish request or listing that still writes `category`.
15+
16+
- **`@objectstack/spec`.** The marketplace taxonomy is defined once, in `@objectstack/spec/marketplace` (`taxonomy.zod.ts`): `businessFunctions` (1-3 distinct values, the primary one first: `sales`, `marketing`, `customer-service`, `finance`, `hr`, `supply-chain`, `administration`, `project`, `legal`, `it`, `collaboration`), `industries` (up to 3, optional; absent means cross-industry), `solutionType` (`app` | `template` | `connector`; absent means `app`) and `maturity` (`beta` | `stable`; absent means `stable`), on `PackageSchema`, `CreatePackageRequestSchema`, `UpdatePackageRequestSchema`, `TemplateManifestSchema` (`objectstack.manifest.json`) and `MarketplaceListingSchema`, where `businessFunctions` is required. A search filters by `businessFunctions` / `industries` / `solutionTypes` / `maturity` and reads one facet count list per facet. `explainSolutionTypeContradiction` is the publish cross-check (a `template` needs the `unmanaged` install mode, a `connector` a declared connector) and `LEGACY_CATEGORY_MAPPING` says what every old category value becomes.
17+
- **Retired.** `category` on all six schemas, and `MarketplaceSearchResponse.facets.categories`, are `retiredKey()` tombstones: `tsc` refuses them and a parse refuses them with the prescription. `MarketplaceCategorySchema` / `MarketplaceCategory` and `PackageCategorySchema` / `PackageCategory` are removed. `RETIRED_KEYS_BY_MAJOR[18]` lists the six keys, `RETIRED_DEFS_BY_MAJOR[18]` both defs, and the upgrade guide carries the semantic entry `marketplace-category-retired`. No ADR-0087 conversion: none of these shapes is a stack collection member, so `os migrate meta` has nothing to rewrite; a runtime boot never reads them.
18+
- **`@objectstack/cli`.** `os package publish` refuses a `category` in `objectstack.manifest.json`, or the now-hidden `--category` flag, before any network call, naming the facets for the value it held. It judges each facet with the spec's schema, checks a declared `solutionType` against the built artifact, and sends the facets as `business_functions`, `industries`, `solution_type` and `maturity`; an absent facet is not sent.
19+
- **`create-objectstack`.** The blank template no longer ships `category: "starter"`, which every project scaffolded from it inherited and which the hosted publish route refused.
20+
21+
**The remedy.** FROM `"category": "<value>"` TO the facets: delete `category` and declare `businessFunctions` (and, where they apply, `industries` and `solutionType`) in `objectstack.manifest.json`. `os package publish` prints the mapping for the value you had — for example `"finance"` → `"businessFunctions": ["finance"], "solutionType": "app"` — and `LEGACY_CATEGORY_MAPPING` lists them all. A `"starter"` copied from the blank template is simply deleted. A TypeScript caller that imported `MarketplaceCategorySchema` or `PackageCategorySchema` uses `MarketplaceBusinessFunctionSchema` and `MarketplaceSolutionTypeSchema` instead.

‎content/docs/deployment/cli.mdx‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3264,7 +3264,6 @@ candidates with how to pass `--env`.
32643264
| `-v, --version <semver>` | — | Version to publish. Default: `artifact.manifest.version`, else `0.0.0-dev.` + a timestamp |
32653265
| `--display-name <name>` | — | Name shown in the Marketplace (default `artifact.manifest.name`) |
32663266
| `--description <text>` | — | Short package description |
3267-
| `--category <slug>` | — | Marketplace category slug (`crm`, `hr`, `devtools`, …) |
32683267
| `--visibility <level>` | — | `org` (installable across your organization) · `private` (explicit grants only) · `marketplace` (public after review). Omitted: not sent, so the control plane decides — an existing package keeps its visibility, a new one gets the control plane's default (`org` on ObjectOS Cloud) |
32693268
| `--org <id>` | `OS_ORG_ID` | `owner_org_id`. Required with a bearer key in service mode; ignored in user mode |
32703269
| `--env <id>` | `OS_ENVIRONMENT_ID` | Environment to install the new version into. Defaults to the environment [`os environments switch`](#cloud-environments) — or `os environments create --activate` — recorded **for this control plane** in `~/.objectstack/cloud.json`, then to your organization's only environment |
@@ -3300,9 +3299,15 @@ and rebuild.
33003299

33013300
**`objectstack.manifest.json` supplies the listing fields.** When that file is
33023301
present in the working directory, publish reads `manifestId`, `displayName`,
3303-
`description`, `category`, `tags`, `iconUrl`, `homepageUrl`, `license`,
3304-
`readmePath` and a `translations` map from it, so a listing need not be retyped
3305-
as flags on every publish. **CLI flags always win.** `tags` has no flag and is
3302+
`description`, `tags`, `iconUrl`, `homepageUrl`, `license`, `readmePath`, a
3303+
`translations` map and the marketplace facets — `businessFunctions`,
3304+
`industries`, `solutionType` and `maturity` — from it, so a listing need not be
3305+
retyped as flags on every publish. **CLI flags always win.** Each facet is
3306+
checked against the spec's schema before anything is sent, and a declared
3307+
`solutionType` against the built artifact: a `template` needs the `unmanaged`
3308+
install mode, a `connector` a declared connector. The retired `category` — in
3309+
the file, or as `--category` — is refused before any network call, with the
3310+
facets that replace the value it held. `tags` has no flag and is
33063311
sent as written: the control plane judges the list, and a refusal is its 400,
33073312
printed as it is. A top-level `tagline` is used only as the description, when
33083313
neither `--description` nor the file's `description` gives one; otherwise it is

‎content/docs/deployment/marketplace-handbook.mdx‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ D1/D2). Modules, plugins and other contributions ship **inside** that App — se
1818
[Extras](#extras-dependencies-and-modules) below.
1919

2020
The listing is a package row in the catalog plus its versions: the row carries
21-
the name, description, category, icon, README and translations, and each
21+
the name, description, business functions and other taxonomy facets, icon, README and translations, and each
2222
version is a snapshot of your compiled artifact.
2323

2424
## The listing file: `objectstack.manifest.json`
@@ -34,24 +34,30 @@ the declared keys below are the ones publish actually sends.
3434
| `manifestId` | The package id (reverse-domain, immutable once published) | `--manifest-id` |
3535
| `displayName` | The name on the card | `--display-name` |
3636
| `description` | The short description | `--description` |
37-
| `category` | The catalog category slug (`crm`, `hr`, `finance`, …) | `--category` |
37+
| `businessFunctions` | The business functions the app serves: 1-3 values, the primary one first (the values: [Marketplace Taxonomy reference](/docs/references/marketplace/taxonomy)) | — |
38+
| `industries` | Up to 3 industries the app is built for; leave it out for a cross-industry app | — |
39+
| `solutionType` | `app` (you keep upgrading it), `template` (the customer's to change — needs the `unmanaged` install mode) or `connector` (needs a declared connector); publish checks it against your built package. Left out: `app` | — |
40+
| `maturity` | `beta` or `stable`; left out: `stable` | — |
3841
| `tags` | The listing tags, sent as written. The catalog validates and stores them and refuses a bad list with a 400, which publish prints as it is; `[]` clears the stored tags, and leaving the key out keeps them | — |
3942
| `iconUrl` | A public http(s) icon URL | `--icon-url`, or `--icon-file` to upload one |
4043
| `homepageUrl` | Your project or docs URL | `--homepage-url` |
4144
| `license` | An SPDX identifier | `--license` |
4245
| `readmePath` | A markdown file, relative to the manifest, read at publish time | `--readme-file`, `--readme` |
4346
| `translations` | Per-locale `displayName`, `description`, `tagline`, `readme` and `screenshotCaptions` | — |
4447

48+
The four taxonomy keys are defined once, in `@objectstack/spec/marketplace`. Publish validates them and sends them; the hosted catalog's facet filters, its submission rule (at least one business function) and the console's facet chips and Beta badge arrive as each side adopts the taxonomy, so until then a value you declare is accepted and not yet shown.
49+
4550
An official ObjectStack listing's `manifestId` is `app.objectstack.<app>` (`app.objectstack.hotcrm`, `app.objectstack.connector-github`); a partner listing uses its own reverse domain, `app.<partner>.<app>`.
4651

4752
[HotCRM](https://github.com/objectstack-ai/hotcrm/blob/main/objectstack.manifest.json)
48-
is a worked example for the keys it carries:
53+
is a worked example for the keys it carries (shown with the business functions
54+
that replace its retired `category`):
4955

5056
```json
5157
{
5258
"manifestId": "app.objectstack.hotcrm",
5359
"displayName": "HotCRM",
54-
"category": "crm",
60+
"businessFunctions": ["sales", "customer-service", "marketing"],
5561
"license": "Apache-2.0",
5662
"iconUrl": "https://raw.githubusercontent.com/objectstack-ai/hotcrm/main/assets/icon.svg",
5763
"homepageUrl": "https://github.com/objectstack-ai/hotcrm",
@@ -189,7 +195,7 @@ the detail.
189195

190196
1. **Finding the app.** In the Console, **Setup → Browse Marketplace** opens the
191197
**App Marketplace** page, which lists the approved apps; clicking one opens
192-
its page with the README, version, category and license. A runtime started
198+
its page with the README, version, business functions and license. A runtime started
193199
with `OS_CLOUD_URL=off` shows **App Marketplace is turned off** instead —
194200
[Cloud connection](/docs/deployment/cloud-connection) covers connecting one.
195201
2. **Installing.** Into a cloud environment, **Install to cloud…** opens a

‎content/docs/protocol/kernel/plugin-spec.mdx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ export default definePlugin({
136136

137137
// MARKETPLACE METADATA
138138
marketplace: {
139-
// Category for marketplace listing
140-
category: 'crm',
139+
// Business functions for the marketplace listing (the taxonomy in
140+
// @objectstack/spec/marketplace; the first is primary)
141+
businessFunctions: ['sales'],
141142

142143
// Screenshots
143144
screenshots: [

‎content/docs/references/index.mdx‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Protocol reference — every schema by module
33
navTitle: Protocol Reference
4-
description: Every schema published by @objectstack/spec — 1631 schemas across 14 protocol modules
4+
description: Every schema published by @objectstack/spec — 1635 schemas across 14 protocol modules
55
---
66

77
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -27,14 +27,14 @@ counts are sums of the rows they head. Regenerate with
2727
| [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. |
2828
| [Integration Protocol](/docs/references/integration) | 1 | 23 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. |
2929
| [Kernel Protocol](/docs/references/kernel) | 30 | 152 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. |
30-
| [Marketplace Protocol](/docs/references/marketplace) | 4 | 30 | The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests. |
30+
| [Marketplace Protocol](/docs/references/marketplace) | 5 | 34 | The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests. |
3131
| [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. |
3232
| [Security Protocol](/docs/references/security) | 6 | 37 | Permission sets, row-level security, sharing rules, tenancy posture. |
3333
| [Shared Protocol](/docs/references/shared) | 10 | 31 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. |
3434
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
3535
| [System Protocol](/docs/references/system) | 39 | 295 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
3636
| [UI Protocol](/docs/references/ui) | 16 | 175 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
37-
| **Total** | **211** | **1631** | 14 protocol modules |
37+
| **Total** | **212** | **1635** | 14 protocol modules |
3838

3939
---
4040

@@ -249,15 +249,16 @@ Plugin lifecycle and manifests, capabilities and security, metadata loading, ser
249249

250250
## Marketplace Protocol
251251

252-
**Source:** `packages/spec/src/marketplace/` · **Import:** `@objectstack/spec/marketplace` · **4 pages, 30 schemas**
252+
**Source:** `packages/spec/src/marketplace/` · **Import:** `@objectstack/spec/marketplace` · **5 pages, 34 schemas**
253253

254254
The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests.
255255

256256
| File | Schemas |
257257
| :--- | :--- |
258-
| [`marketplace.zod.ts`](/docs/references/marketplace/marketplace) | `ArtifactDownloadResponse`, `ArtifactReference`, `ListingStatus`, `MarketplaceCategory`, `MarketplaceInstallRequest`, `MarketplaceInstallResponse`, `MarketplaceListing`, `MarketplaceSearchRequest`, `MarketplaceSearchResponse`, `PackageSubmission`, `PricingModel`, `Publisher`, `PublisherVerification` |
259-
| [`package.zod.ts`](/docs/references/marketplace/package) | `CreatePackageRequest`, `Package`, `PackageCategory`, `PackageLocale`, `PackagePublisher`, `PackageTranslation`, `PackageTranslations`, `PackageVisibility`, `UpdatePackageRequest` |
258+
| [`marketplace.zod.ts`](/docs/references/marketplace/marketplace) | `ArtifactDownloadResponse`, `ArtifactReference`, `ListingStatus`, `MarketplaceInstallRequest`, `MarketplaceInstallResponse`, `MarketplaceListing`, `MarketplaceSearchRequest`, `MarketplaceSearchResponse`, `PackageSubmission`, `PricingModel`, `Publisher`, `PublisherVerification` |
259+
| [`package.zod.ts`](/docs/references/marketplace/package) | `CreatePackageRequest`, `Package`, `PackageLocale`, `PackagePublisher`, `PackageTranslation`, `PackageTranslations`, `PackageVisibility`, `UpdatePackageRequest` |
260260
| [`package-version.zod.ts`](/docs/references/marketplace/package-version) | `CreatePackageVersionRequest`, `PackageDependency`, `PackageManifest`, `PackageVersion`, `PackageVersionStatus`, `PublishPackageVersionRequest`, `UpdatePackageVersionRequest` |
261+
| [`taxonomy.zod.ts`](/docs/references/marketplace/taxonomy) | `MarketplaceBusinessFunction`, `MarketplaceBusinessFunctions`, `MarketplaceIndustries`, `MarketplaceIndustry`, `MarketplaceSolutionType`, `PackageMaturity` |
261262
| [`template-manifest.zod.ts`](/docs/references/marketplace/template-manifest) | `TemplateManifest` |
262263

263264
---

‎content/docs/references/marketplace/index.mdx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Marketplace Protocol — schema reference
33
navTitle: Marketplace Protocol
4-
description: "The ObjectStack Marketplace Protocol in 4 reference pages: every schema in @objectstack/spec with its properties, types, defaults and a TypeScript example."
4+
description: "The ObjectStack Marketplace Protocol in 5 reference pages: every schema in @objectstack/spec with its properties, types, defaults and a TypeScript example."
55
---
66

77
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -12,5 +12,6 @@ This section contains all protocol schemas for the marketplace layer of ObjectSt
1212
<Card href="/docs/references/marketplace/marketplace" title="Marketplace" description="Source: packages/spec/src/marketplace/marketplace.zod.ts" />
1313
<Card href="/docs/references/marketplace/package" title="Package" description="Source: packages/spec/src/marketplace/package.zod.ts" />
1414
<Card href="/docs/references/marketplace/package-version" title="Package Version" description="Source: packages/spec/src/marketplace/package-version.zod.ts" />
15+
<Card href="/docs/references/marketplace/taxonomy" title="Taxonomy" description="Source: packages/spec/src/marketplace/taxonomy.zod.ts" />
1516
<Card href="/docs/references/marketplace/template-manifest" title="Template Manifest" description="Source: packages/spec/src/marketplace/template-manifest.zod.ts" />
1617
</Cards>

0 commit comments

Comments
 (0)