Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs-site/scripts/generate-docs-data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,14 @@ Generated from

**Always required:** ${requiredList.map((f) => `\`${f}\``).join(", ")}. ${conditional}

:::note
In a dev tree this file is \`plugin.json\` at the plugin root. In a *published
catalog bundle* it rides at \`appos/runtime/plugin.json\` (the zip root holds the
catalog \`manifest.json\` instead) and the desktop installer copies it back to
the bundle root at install time — see
[Catalog bundle layout](/manifest/#catalog-bundle-layout).
:::

## Fields

${renderSchemaObject(manifestSchema, requiredList, 2, "")}
Expand Down
6 changes: 5 additions & 1 deletion docs-site/src/content/docs/getting-started/first-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ npx esbuild src/main.ts --bundle --format=iife --target=es2020 --outfile=dist/ma
`npx` runs the esbuild binary you installed as a devDependency during
[installation](/getting-started/installation/) — no global install needed.

Validate your manifest against the schema shipped in this repo:
Validate your runtime `plugin.json` against the schema shipped in this repo
(runtime schema only — the catalog `manifest.json` of a published bundle is
validated server-side at submit time):

```bash
node scripts/validate-schema.mjs path/to/plugin.json
Expand All @@ -110,3 +112,5 @@ node scripts/validate-schema.mjs path/to/plugin.json
- [API namespaces](/reference/namespaces/) — the full `context.*` surface
- [Manifest & permissions](/manifest/) — every manifest field and scope
- [Extension points](/extension-points/) — contributing to core plugins via `extensions[]`
- [Catalog bundle layout](/manifest/#catalog-bundle-layout) — how a published
catalog bundle's zip layout differs from this dev layout
72 changes: 68 additions & 4 deletions docs-site/src/content/docs/manifest/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ sidebar:
order: 1
---

Every AppOS plugin ships a `plugin.json` manifest at its root. The manifest
declares the plugin's identity, when it activates, which permissions it needs,
and any system or plugin dependencies.
Every AppOS plugin keeps its `plugin.json` manifest at the plugin root — in
the dev tree and in the installed plugin directory alike. The one exception is
a catalog-published zip, which nests the runtime manifest at
`appos/runtime/plugin.json` until the installer copies it to the root at
install time — see [Catalog bundle layout](#catalog-bundle-layout) below. The
manifest declares the plugin's identity, when it activates, which permissions
it needs, and any system or plugin dependencies.

The manifest is validated against the JSON Schema at
[`schemas/plugin-v1.json`](https://github.com/appos/plugin-sdk/blob/main/schemas/plugin-v1.json).
Expand Down Expand Up @@ -42,10 +46,70 @@ Add a `$schema` reference for editor autocomplete:
- **[Extension points](/extension-points/)** — the `extensions[]` array for
contributing to core-plugin extension points.

## Catalog bundle layout

A dev tree keeps `plugin.json` at the plugin root — that is what local and
sideload installs load. Bundles published to the AppOS catalog use **AppOS
Catalog Bundle Layout v1**, which carries TWO manifests because the catalog's
submit validation and the desktop installer read different schemas:
Comment thread
acebytes marked this conversation as resolved.

- `manifest.json` at the **zip root** — the catalog `manifest-v1` document
(`schema`, `slug`, `kind`, `version`, `title`, `license`, `capabilities`,
`permissions`, `compatibility`, `entry`; unknown keys rejected). Validated at
publish time.
Comment thread
acebytes marked this conversation as resolved.
- `appos/runtime/plugin.json` — the AppOS runtime manifest (the schema
documented on these pages). Read by the desktop app at install time.

```text
space-appos-myplugin-1.0.0.zip
├── manifest.json # catalog manifest-v1
├── appos/
│ └── runtime/
│ └── plugin.json # AppOS runtime manifest (this schema)
├── dist/
│ └── main.js # runtime payload at the zip root
└── webview/ assets/ README.md LICENSE ...
```

Rules:

- **Installer resolution is root-first.** A root `plugin.json` always wins;
otherwise the desktop installer consults the single well-known fallback
`appos/runtime/plugin.json` and copies it to the bundle root at install time
("normalize-at-install"); neither present fails the install with
`manifestMissing`. There is no globbing — the fallback is one constant path.
- **Verification precedes manifest resolution.** SHA-256 (both install paths)
and, on the catalog install path, the publisher-verified gate plus Ed25519
signature verification all run before extraction — the hash and signature
checks cover the exact zip bytes, so no manifest is read until verification
passes.
- **Exactly one catalog-manifest candidate.** Nothing named `plugin.json` or
`manifest.json` may exist at the zip root or one level deep except the single
catalog manifest — the submit scan rejects zero candidates (`no_manifest`)
and more than one (`ambiguous_bundle_root`). Depth 2 keeps the runtime
manifest invisible to that scan.
- **Runtime-manifest paths are relative to the ZIP ROOT**, not to
`appos/runtime/` — e.g. `"entrypoint": "dist/main.js"`.
- A dev-layout bundle (root `plugin.json`, no `manifest.json`) installs locally
but is NOT publishable to the catalog: its root `plugin.json` would be
selected as the catalog-manifest candidate and fail `manifest-v1` validation
(`manifest_invalid`).

## Validation

This repo ships a validator you can run locally against any manifest:
This repo ships a validator for the **runtime `plugin.json` manifest only** —
it checks against `schemas/plugin-v1.json`, the schema documented on these
pages:

```bash
node scripts/validate-schema.mjs path/to/plugin.json
```

The catalog `manifest.json` at the zip root uses a different schema — catalog
`manifest-v1` — and has **no local validator in this repo**, so don't point
`validate-schema.mjs` at it: you'd get irrelevant runtime-schema errors.
Catalog manifests are validated server-side at publish time — the submit step
re-extracts `manifest.json` from your uploaded zip and validates it strictly
(unknown keys rejected; `schema`, `slug`, `title`, and `entry` required).
Failures surface as `manifest_invalid` errors in the publish API's
`prepare → submit` response.
8 changes: 8 additions & 0 deletions docs-site/src/content/docs/manifest/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ Generated from

**Always required:** `id`, `name`, `version`, `runtime`. Plugins with `"runtime": "javascript"` must also declare `entrypoint`.

:::note
In a dev tree this file is `plugin.json` at the plugin root. In a *published
catalog bundle* it rides at `appos/runtime/plugin.json` (the zip root holds the
catalog `manifest.json` instead) and the desktop installer copies it back to
the bundle root at install time — see
[Catalog bundle layout](/manifest/#catalog-bundle-layout).
:::

## Fields

| Field | Type | Required | Description |
Expand Down
Loading