Skip to content

Manifest Reference

scarecr0w12 edited this page Jun 23, 2026 · 5 revisions

Plugin Manifest Reference

Complete schema reference for manifest.json. All types match the PluginManifest interface in src/plugins/types.ts.

Full Annotated Schema

{
  "name":        "my-plugin",         // required — kebab-case, unique across marketplace
  "version":     "1.0.0",             // required — semver (MAJOR.MINOR.PATCH)
  "description": "Short description", // required
  "kind":        "esm",               // required — "esm" | "mcp" | "wasm"
  "entryPoint":  "./mod.ts",          // required — relative path, absolute path, or URL
  "runtime":     "deno",              // required — "deno" | "wasm"
  "capabilities": ["tools", "network:fetch"], // required — see Capabilities below

  "author":      "acme",              // optional
  "homepage":    "https://example.com",
  "license":     "MIT",               // SPDX identifier recommended
  "repository":  "https://github.com/acme/my-plugin",
  "hash":        "sha256:<hex>",      // SHA-256 of plugin files for supply-chain verification
  "signature":   "<base64>",          // Digital signature (optional, GPG)

  "dependencies":     { "other-plugin": "^1.0.0" }, // semver constraints
  "peerDependencies": { "auth-plugin": ">=2.0.0" },

  "events": ["session:start", "llm:post-call"], // event types to subscribe to

  "tools": [ /* ToolDeclaration[] */ ],
  "cliCommands": [ /* CliCommandDeclaration[] */ ],
  "ui": { /* UiContribution */ },
  "config": { /* ConfigContribution */ }
}

Required Fields

Field Type Rules
name string kebab-case, unique across marketplace
version string Valid semver, e.g. 1.2.3
description string Short one-line description
kind "esm" | "mcp" | "wasm" Plugin runtime kind
entryPoint string Relative path (resolved to absolute on install), absolute path, or URL (file://, https://, jsr:, npm:)
runtime "deno" | "wasm" Execution target
capabilities PluginCapability[] Declared permissions and extension points

Optional Fields

Field Type Description
author string Author username (forms the @author/ namespace)
homepage string Plugin homepage URL
license string SPDX license identifier (e.g. MIT, Apache-2.0)
repository string Source repository URL
hash string SHA-256 hash of plugin files (sha256:<hex>) — used for supply-chain verification
signature string Base64-encoded digital signature
dependencies Record<string, string> Required plugin names → semver constraints (^1.0, >=2.0, *)
peerDependencies Record<string, string> Compatible peer plugin names → constraints
events string[] Event type names to subscribe to — requires events:listener capability
tools ToolDeclaration[] Tool declarations (informational; actual tools come from mod.ts exports)
cliCommands CliCommandDeclaration[] CLI subcommand declarations
ui UiContribution UI panels, widgets, settings fields
config ConfigContribution LLM provider registrations and config defaults

ToolDeclaration

interface ToolDeclaration {
  name: string;
  description: string;
  params: {
    name: string;
    type: string;        // 'string' | 'number' | 'boolean' | 'object' | 'array'
    description: string;
    required?: boolean;
    enum?: string[];     // restrict string params to allowed values
  }[];
}

CliCommandDeclaration

interface CliCommandDeclaration {
  name: string;         // becomes 'cortex <name>'
  description: string;
  args?: {              // positional arguments
    name: string;
    type: string;       // 'string' | 'number' | 'boolean'
    description: string;
    required?: boolean;
  }[];
  options?: {           // named flags
    name: string;       // --<name>
    type: string;       // 'string' | 'number' | 'boolean'
    description: string;
    flag: string;       // short flag, e.g. '-v'
  }[];
}

The handler is the default export or a named export matching decl.name (camelCase) from the plugin module. It receives args: Record<string, unknown> where keys are option/arg names.

UiContribution

interface UiContribution {
  panels?: {
    id: string;         // unique within plugin, used in URL: /api/plugins/<name>/panel/<id>
    title: string;      // tab/nav label
    icon?: string;      // icon name (Lucide icon or emoji)
    htmlPath: string;   // path relative to manifest to the panel HTML file
  }[];
  widgets?: {
    id: string;
    title: string;
    type: 'html' | 'chart' | 'table';
    config: Record<string, unknown>;
  }[];
  settings?: {
    section: string;    // settings section heading
    fields: UiSettingField[];
  }[];
}

UiSettingField

interface UiSettingField {
  key: string;          // read via ctx.config.get(key)
  label: string;        // display label in settings UI
  type: 'text' | 'number' | 'boolean' | 'select' | 'secret';
  defaultValue: unknown;
  options?: { label: string; value: string }[]; // for type: 'select'
  description?: string; // optional help text shown below the field
}

Setting type reference:

type Input Notes
text Text input Free-form string
number Number input Stored as number
boolean Toggle/checkbox Stored as boolean
select Dropdown Requires options array
secret Password input Stored encrypted, masked in UI

ConfigContribution

interface ConfigContribution {
  providers?: {
    kind: string;         // provider identifier, matches key in module 'providers' export
    label: string;        // display name in provider selection UI
    defaultModel: string; // default model name
  }[];
  settings?: Record<string, unknown>; // default config values
}

Capabilities

Extension Points

Capability Module export required Description
tools tools: Tool[] Register tools in the agent tool registry
cli:commands cliCommands or named handler Add cortex <name> subcommands
ui:panel — (manifest ui.panels) Add a Web UI panel/tab
ui:widget — (manifest ui.widgets) Add a dashboard widget
config:schema Extend config schema with new settings
config:provider providers: Record<string, ProviderFactory> Register LLM provider factories
memory:store Custom memory backend (reserved for future use)
memory:embedder Custom embedding provider (reserved)
events:listener globalEventBus.on(...) in onLoad Subscribe to the event bus
middleware:pre middlewarePre export Hook into pre-tool pipeline stage
middleware:post middlewarePost export Hook into post-tool pipeline stage

Permissions

Capability Deno Worker permission What it grants
fs:read read: true Read files from the filesystem
fs:list read: true List directory contents
fs:write write: true Write files
fs:edit write: true Edit existing files
fs:delete write: true Delete files
fs:search Search file contents (policy-gated)
shell:run run: true Execute shell commands
network:fetch net: true Make outbound HTTP/HTTPS requests
net:outbound net: true General outbound network access
net:inbound net: true Accept inbound connections
db:read Read from internal databases (policy-gated)
db:write Write to internal databases (policy-gated)

Declare only the capabilities your plugin actually uses. The effective permissions at runtime are declared − admin_denied + admin_granted.

Plugin Kinds

ESM (kind: "esm", runtime: "deno")

TypeScript/JavaScript module loaded via Deno's import(). Entry point must be an absolute path or a URL (file://, https://, jsr:, npm:). Relative paths in the manifest are resolved to absolute during installation.

Exports: tools, providers, cliCommands, onLoad, onUnload, onInstall, onActivate, onDeactivate, onUninstall, onConfigChange, middlewarePre, middlewarePost

MCP (kind: "mcp", runtime: "deno")

Wraps an external JSON-RPC 2.0 server. entryPoint must be an https:// URL pointing to the server. CortexPrism creates a synthetic tool named mcp_<name> that proxies calls:

POST <entryPoint>
{ "jsonrpc": "2.0", "id": 1, "method": "<tool.name>", "params": { ... } }

The server must respond with { "jsonrpc": "2.0", "id": 1, "result": { ... } }.

WASM (kind: "wasm", runtime: "wasm")

WebAssembly binary. entryPoint can be a relative path to a .wasm file or an https:// URL. Memory: initial: 256 pages (16 MiB), maximum: 512 pages (32 MiB). Tools execute in a dedicated Worker with 120 s timeout. HTTP requests have 30 s individual timeout and are gated on network:fetch/net:outbound capability.

ABI Version 1. Plugin must export plugin_get_abi_version() returning 1. Host rejects incompatible versions on load.

Memory layout:

[0x000000 - 0x00FFFF]  Host scratch area (64 KB)
[0x010000 - 0x01FFFF]  Host allocator metadata (64 KB)
[0x020000 - 0x0FFFFF]  Host-managed heap (896 KB) — host_alloc/host_free
[0x100000 - ...]       Plugin memory (__heap_base = 0x100000)

Required WASM exports:

Export Signature Required Purpose
plugin_get_abi_version () → i32 Yes Return supported ABI version (must match host)
plugin_init () → void No Called once on load
plugin_destroy () → void No Called on unload — cleanup
plugin_get_capabilities (outPtr: i32, outLenPtr: i32) → i32 Yes Return JSON capabilities with param schemas
plugin_execute_tool (namePtr, nameLen, argsPtr, argsLen, outPtr, outLenPtr) → i32 Yes Execute a tool
memory WebAssembly.Memory Yes Shared linear memory

Capabilities JSON must include full parameter schemas so LLMs understand tool signatures:

{
  "abi_version": 1,
  "tools": [{
    "name": "my_tool",
    "description": "Does something",
    "params": [
      { "name": "input", "type": "string", "description": "Input", "required": true },
      { "name": "limit", "type": "number", "description": "Max results", "required": false }
    ]
  }]
}

Host import functions (available as env.*):

Function Signature Description
host_alloc (size: i32) → i32 Allocate from host-managed heap
host_free (ptr: i32) → void Free allocation
host_log (ptr: i32, len: i32) → void Log message to CortexPrism
host_get_config (keyPtr, keyLen, outPtr, outLenPtr) → i32 Read CORTEX_PLUGIN_{NAME}_{KEY} or CORTEX_WASM_{KEY} env var
host_set_state (keyPtr, keyLen, valPtr, valLen) → void Persist state (in-memory + SQLite)
host_get_state (keyPtr, keyLen, outPtr, outLenPtr) → i32 Read persisted state
host_http_request (methodPtr, methodLen, urlPtr, urlLen, bodyPtr, bodyLen, headersPtr, headersLen, outStatusPtr, outBodyPtr, outBodyLenPtr) → i32 Synchronous HTTP (Worker + Atomics.wait, 30 s timeout, gated on network:fetch)
host_get_abi_version () → i32 Returns host ABI version
host_get_time_ms () → i64 Current time in ms
host_random (outPtr: i32, len: i32) → void Cryptographically random bytes

All strings are UTF-8 in linear memory. Return 0 on success, non-zero on error. Output is written to outPtr/outLenPtr.

Module Export Reference (mod.ts)

Export name Type Capability required
tools Tool[] tools
providers Record<string, ProviderFactory> config:provider
cliCommands CliCommandDeclaration[] cli:commands
onInstall (ctx) => Promise<void>
onLoad (ctx) => Promise<void>
onActivate (ctx) => Promise<void>
onDeactivate (ctx) => Promise<void>
onUnload (ctx) => Promise<void>
onUninstall (ctx) => Promise<void>
onConfigChange (key, value, ctx) => Promise<void>
middlewarePre (ctx: unknown) => Promise<HookResult> middleware:pre
middlewarePost (ctx: unknown) => Promise<HookResult> middleware:post

Events Reference

Event Payload Notes
session:start { sessionId: string } New chat session
session:end { sessionId: string } Session ended
tool:pre-execute { toolName: string, args: Record<string, unknown> } Before any tool
tool:post-execute { toolName: string, result: unknown } After any tool
llm:pre-call { provider: string, model: string } Before LLM API call
llm:post-call { provider: string, model: string, tokensIn: number, tokensOut: number } After LLM API call
agent:turn-start { sessionId: string, turnId: string } Start of agent turn
agent:turn-end { sessionId: string, turnId: string, response: string } End of agent turn
config:change { key: string, value: unknown } Config key changed
daemon:status { daemon: string, status: 'up' | 'down' } Daemon started/stopped

Requires events:listener capability. Must also list subscribed types in manifest events field.

ToolCallResult (tool execute return value)

interface ToolCallResult {
  toolName: string;   // must match tool definition name
  success: boolean;
  output: string;     // serialize objects with JSON.stringify
  error?: string;     // human-readable error message when success is false
  durationMs: number; // wall-clock execution time in milliseconds
}

See Also

Clone this wiki locally