Manifest (PluginManifest)
The full set of required and optional fields of PluginManifest, declared via manifest.ts and defineManifest(), plus zod validation.
manifest.ts is the plugin's SSOT (Single Source of Truth).
You declare it with defineManifest(), which gives you type completion. Nearly everything about your plugin — tables, side menu, tabs, permissions, and exposure in the unified palette — is derived from what you declare here.
// src/manifest.ts
import { defineManifest } from "@niyase/plugin-sdk/manifest";
export const manifest = defineManifest({
id: "@your-org/tasks",
scope: "CERTIFIED",
visibility: "PUBLIC",
targetWorkspace: "BUSINESS",
category: "extension",
displayName: "タスク",
description: "シンプルな業務タスク管理",
iconName: "ListTodo",
defaultRole: "LOCAL",
audiences: [
{
role: "executive",
nav: {
label: "タスク",
href: "/plugin/tasks",
activeColor: "text-primary",
},
tabs: [{ value: "list", label: "一覧" }],
},
],
tables: [
{
name: "task",
resource: "task",
columns: {
title: { type: "TEXT", notNull: true },
status: { type: "TEXT" },
},
},
],
paletteMetadata: {
intentTags: [
"タスクを追加",
"TODO 管理",
"担当者を割り当て",
"期限を設定",
"進捗を確認",
],
intentCategories: ["project"],
capabilityKeywords: ["タスク管理", "TODO"],
scenarios: ["朝の段取り", "週次レビュー"],
},
});
Required fields
| Field | Type | Description |
|---|---|---|
id | @scope/name | Globally unique ID. scope is your claimed namespace (@niyase for official plugins, your own org name for certified ones) |
scope | "OFFICIAL" | "CERTIFIED" | Provider category — built by niyase, or by an external developer and reviewed by niyase |
visibility | "PUBLIC" | "PRIVATE" | Marketplace visibility. PUBLIC can be found and activated from any space; PRIVATE is shown only in spaces that have been allow-listed |
targetWorkspace | "BUSINESS" | "PERSONAL" | "BOTH" | Which space type the plugin targets |
category | PluginSidebarCategory | Sidebar category (one of 25 values). Determines where the plugin lives |
displayName | string | Display name in the UI |
description | string | A 1–2 line description |
iconName | string | A lucide-react icon name |
defaultRole | "PROVIDER" | "CLIENT" | "LOCAL" | Default role on activation (see below) |
audiences | PluginAudience[] | Per-role (executive / employee / customer) nav and tabs. At least one entry is required |
tables | PluginTableDef[] | Your own table definitions (use [] if none). Naming convention and auto-added columns are covered in Data Model |
paletteMetadata | PluginPaletteMetadata | Metadata for unified-palette search (required, see below) |
There is no
PRIVATEvalue forscope. The provider category (scope) only takesOFFICIALorCERTIFIED. The separate axis of "free and public to every space vs. paid and limited to specific spaces" is handled byvisibilityplusplugin_allowed_workspace(managed from admin) — don't conflate the two.
paletteMetadata (required)
Required because the unified palette is the primary path for discovering plugins — without it, your plugin never appears in search results. niyase-plugin lint flags a missing declaration.
| Field | Type | Guideline |
|---|---|---|
intentTags | string[] | Free-text, concrete phrases, 5–15 entries (e.g. "経費精算したい", "領収書を仕訳に") |
intentCategories | IntentCategory[] | Top-level category enum, 1–3 entries (too many dilutes ranking) |
capabilityKeywords | string[] | Capability words (e.g. "OCR", "PDF", "CSV import") |
scenarios | string[] | Business-scene phrases (e.g. "month-end close", "fiscal year-end") |
primaryFlow? | string | Flow ID to launch when selected from the palette (optional) |
Optional fields
| Field | Type | Description |
|---|---|---|
categoryTags? | PluginSidebarCategory[] | Additional category tags for search |
industries? | Industry[] | Industry tags. These are discovery labels only and never restrict who can install the plugin (an IT company can install a "real-estate" tagged plugin). Empty/unset = for every industry |
longDescription? | string | A longer description (Markdown allowed) for the marketplace detail page |
requiresCloud? | boolean (default false) | true makes the plugin cloud-only (installable in cloud spaces only). false (default) is hybrid — installable in both local and cloud spaces |
pairedPluginId? | string | Links a PROVIDER ↔ CLIENT pair. When set, requiresCloud: true is required (zod enforces this consistency) |
publisherName? | string | Publisher display name (for CERTIFIED; OFFICIAL plugins default to "niyase") |
version? | string | semver |
bundleUrl? / bundleHash? | string | Bundle URL and integrity hash for CERTIFIED dynamic loading (set by the server at submission time) |
scheduleProvider? | ScheduleProviderDecl[] | Declares which date columns on your tables should feed into the home "schedule" view's cross-cutting timeline |
industryPresets? | PluginIndustryPreset[] | Deprecated (2026-05-30). The old per-industry master-data / conditional-table mechanism. Do not use it in new plugins — see Data Model for how to seed master data today |
defaultRole and pairedPluginId — declaring the operating pattern
A plugin operates either standalone or as a PROVIDER-CLIENT pair (a two-party collaboration).
defaultRole | Meaning | pairedPluginId | requiresCloud |
|---|---|---|---|
LOCAL | Standalone — self-contained within one space | Not needed | Optional (set true if it depends on cloud-only features) |
PROVIDER | The providing side of a collaboration — aggregates data and shares it with a CLIENT | Set to the paired CLIENT plugin's ID | Required to be true |
CLIENT | The receiving side of a collaboration — only sees the data the PROVIDER has shared | Set to the paired PROVIDER plugin's ID | Required to be true |
Separately from the role a user picks after activation, defaultRole declares the role a fresh activation starts in. A PROVIDER/CLIENT pair is always cloud-only (requiresCloud: true), since neither side of the pair can exist in a local space. For how defaultRole relates to the executive / employee / customer audiences shown in the UI, see UI Integration.
Validation
niyase-plugin lint validates the manifest with validateManifest() (zod).
This is identical to the validator the server uses at submission time, so if lint passes, submission will pass too.
niyase-plugin lint
# ✓ tsc --noEmit
# ✓ manifest validation OK (@your-org/tasks)
The type definition's source of truth is packages/plugins/src/types.ts (PluginManifest).