Skip to content

Manifest Reference ​

The manifest.json file is the central configuration for your plugin. It declares everything AMC needs to load, display, sandbox, and manage your plugin.

Top-Level Structure ​

json
{
  "plugin": { ... },
  "settings": [ ... ],
  "storage": { "collections": { ... } },
  "migrations": [ ... ],
  "sdkVersion": "^3.0.0",
  "ui": { ... },
  "backend": { ... },
  "permissions": [ ... ],
  "cli": { "endpoints": [ ... ] },
  "cron": { "jobs": [ ... ] }
}
FieldTypeRequiredDescription
pluginobjectYesPlugin identity and metadata
settingsarrayYesUser-configurable settings (can be empty [])
storageobjectYesDatabase collection schemas (can be { "collections": {} })
migrationsarrayYesSchema migration operations (can be empty [])
sdkVersionstringYesRequired SDK version (e.g. "^3.0.0")
uiobjectNoUI entry point and sidebar config
backendobjectNoBackend entry point and resource limits
permissionsarrayNoRequested API permissions
cliobjectNoCLI endpoint declarations
cronobjectNoCron job declarations

plugin Block ​

json
{
  "plugin": {
    "id": "my-plugin",
    "name": "My Plugin",
    "version": "1.0.0",
    "author": "Your Name",
    "description": "Does something useful",
    "icon": "icon.png",
    "category": "development",
    "license": { "type": "free" },
    "minAppVersion": "0.1.30",
    "tags": ["linter", "security"]
  }
}
FieldTypeRequiredDescription
idstringYesUnique identifier, kebab-case (e.g. "my-plugin")
namestringYesHuman-readable display name
versionstringYesSemver version (e.g. "1.0.0")
authorstringYesAuthor name or organization
descriptionstringYesShort description shown in the marketplace
iconstringYesImage filename (e.g. "icon.png") or Lucide icon name as fallback
categorystringYesOne of: planning, development, testing, devops, productivity, other
licenseobjectYes{ "type": "free" }, { "type": "paid" }, or { "type": "trial" }
minAppVersionstringNoMinimum AMC version required to run this plugin
tagsstring[]NoDiscoverability keywords surfaced in marketplace search and shown as chips on the plugin card (up to 10 tags, 30 characters each)

WARNING

The id field is permanent. It is used as the storage namespace, database prefix, and marketplace identifier. Changing it after publishing creates a new, separate plugin.

Plugin Icon ​

Your plugin's icon appears in the Marketplace card (40 × 40 px) and detail page (56 × 56 px). To include a custom icon:

  1. Place an image file in your plugin's root directory (alongside manifest.json)
  2. Reference it in the icon field:
json
{
  "plugin": {
    "id": "my-plugin",
    "name": "My Plugin",
    "icon": "icon.png",
    ...
  }
}

Supported formats: PNG, JPG, SVG, WebP

Recommended: 128 × 128 px PNG with a transparent background. The image is displayed at 40 px in Marketplace cards and 56 px in the detail view, so a 128 px source gives crisp rendering on high-DPI screens.

When you upload your plugin to the Marketplace, AMC automatically extracts the icon from the package and hosts it. If no image file is found, AMC falls back to showing the first letter of the plugin name.

TIP

You can still use a Lucide icon name (e.g. "puzzle") as a lightweight fallback, but an image file gives your plugin a distinctive look in the Marketplace.

settings Array ​

Declare user-configurable settings that appear in AMC's Settings > Plugins > Your Plugin panel. Each setting maps to a key that your plugin reads via ctx.settings.get(key) (backend) or amc.settings.get(key) (frontend).

Setting Types ​

Toggle ​

json
{
  "key": "autoSync",
  "label": "Auto-sync",
  "description": "Sync data automatically on startup",
  "type": "toggle",
  "default": true
}

Text ​

json
{
  "key": "apiEndpoint",
  "label": "API Endpoint",
  "description": "Base URL for the external API",
  "type": "text",
  "default": "https://api.example.com"
}

Password ​

json
{
  "key": "apiKey",
  "label": "API Key",
  "description": "Your API key (stored encrypted)",
  "type": "password",
  "default": ""
}

Number ​

json
{
  "key": "maxRetries",
  "label": "Max Retries",
  "description": "Number of retry attempts",
  "type": "number",
  "default": 3,
  "min": 1,
  "max": 10
}

Select ​

json
{
  "key": "outputFormat",
  "label": "Output Format",
  "type": "select",
  "default": "json",
  "options": [
    { "value": "json", "label": "JSON" },
    { "value": "csv", "label": "CSV" },
    { "value": "markdown", "label": "Markdown" }
  ]
}

Setting Fields Reference ​

FieldTypeRequiredDescription
keystringYesUnique key used to read the setting value
labelstringYesDisplay label in the settings UI
descriptionstringNoHelp text shown below the label
typestringYesOne of: toggle, select, text, number, password
optionsarrayOnly for selectArray of { value, label } objects
defaultanyYesDefault value when the user has not changed the setting
minnumberNoMinimum value (for number type)
maxnumberNoMaximum value (for number type)
testActionobjectNoAdds a test button next to the setting (see below)

Test Actions ​

A testAction adds a button next to the setting that calls a backend method, useful for "Test connection" buttons:

json
{
  "key": "apiKey",
  "label": "API Key",
  "type": "password",
  "default": "",
  "testAction": {
    "namespace": "myPlugin",
    "method": "testConnection",
    "label": "Test Connection"
  }
}
FieldTypeDescription
namespacestringBackend namespace for the method call
methodstringMethod name to invoke
labelstringButton label (e.g. "Test Connection")

storage Block ​

Declare database collections your plugin uses. Each collection has named columns with types. AMC creates SQLite tables for each collection, namespaced to your plugin.

json
{
  "storage": {
    "collections": {
      "tasks": {
        "columns": {
          "title": "text",
          "priority": "integer",
          "metadata": "json",
          "score": "real"
        },
        "indexes": ["priority", "title"]
      },
      "logs": {
        "columns": {
          "message": "text",
          "level": "text"
        }
      }
    }
  }
}

Column Types ​

TypeSQLite TypeDescription
textTEXTString values
integerINTEGERWhole numbers
realREALFloating-point numbers
jsonTEXT (JSON)Serialized JSON objects/arrays

Indexes ​

The optional indexes array lists column names to index for faster queries. Each entry creates a standard B-tree index on that column.

The optional uniqueIndexes array declares composite-unique tuples — each inner array is a set of columns that together must be unique:

json
{
  "findings": {
    "columns": { "scan_id": "text", "category": "text", "detail": "json" },
    "uniqueIndexes": [["scan_id", "category"]]
  }
}

AMC emits a real CREATE UNIQUE INDEX per tuple, de-duplicating existing rows (keep-latest) the first time it creates one. This is not decoration: ctx.db.upsert() performs an INSERT ... ON CONFLICT (<tuple>) DO UPDATE, so a tuple declared here is what makes that call atomic. An upsert against an undeclared tuple raises a SQLite error rather than silently inserting a duplicate.

id, created_at and updated_at are managed by AMC and may not be declared as columns.

TIP

Every collection automatically gets an id column (TEXT, primary key), a created_at column, and an updated_at column. You do not need to declare these.

migrations Array ​

Declared migrations are never executed

AMC parses and validates this block, keeps it in memory, and then nothing reads it. There is no migration runner, no applied-migrations ledger, and no code path that can drop a plugin column or index. Do not plan a schema change around it.

What actually evolves your schema is an automatic ADD COLUMN sweep. When your plugin's version increases, AMC diffs storage.collections against the live table and adds any column that is missing. So a new column appears if you declare it in storage.collections and bump plugin.version — whether or not you write a migration here. Renames and drops are not possible through any AMC path; migrate the data yourself in onEnable if you need one.

Declaring migrations stays harmless and still validates, so existing manifests keep working.

json
{
  "migrations": [
    {
      "version": "1.1.0",
      "operations": [
        {
          "type": "add_column",
          "collection": "tasks",
          "column": "dueDate",
          "columnType": "text"
        },
        {
          "type": "add_index",
          "collection": "tasks",
          "column": "dueDate"
        }
      ]
    }
  ]
}

Migration Operations ​

OperationRequired FieldsDescription
add_columncollection, column, columnTypeAdd a new column to an existing collection
add_indexcollection, columnCreate an index on a column
drop_indexcollection, columnDrop the index on a column

collection and column are required on every operation, including the index ones — an index operation identifies its index by a single column, and there is no index field.

Ops this SDK used to document

remove_column and remove_index appeared in earlier versions of this guide. AMC has never accepted either, and amc-plugin validate now rejects them. The real drop operation is drop_index. column may not be id, created_at or updated_at — AMC manages those itself.

ui Block ​

Declares the frontend entry point, sidebar appearance, and how AMC frames your plugin.

json
{
  "ui": {
    "entryPoint": "dist/ui/index.html",
    "sidebar": {
      "title": "My Plugin",
      "icon": "puzzle"
    },
    "hideProjectPanel": false,
    "hideSessionsPane": false,
    "sessions": {
      "label": "My Plugin sessions",
      "contextTemplate": "You are working inside {{projectName}} on {{date}}.",
      "showDivider": true,
      "suggestedPrompts": [
        { "label": "Audit", "prompt": "Audit this project for security issues" }
      ]
    }
  }
}
FieldTypeRequiredMaxDescription
entryPointstringNo500Path to the HTML file (relative to plugin root)
sidebar.titlestringNo50Label shown in AMC's sidebar
sidebar.iconstringNo50Lucide icon name
overlay.entryPointstringNo500A separate always-on-top window AMC opens on enable
hideProjectPanelbooleanNo—Suppress AMC's project panel while your view is open. Half of "full width" — see below
hideSessionsPanebooleanNo—Suppress the plugin sessions pane. The other half — set it alongside hideProjectPanel
sessions.labelstringNo100Heading above your plugin's session list. Defaults to the plugin name
sessions.contextTemplatestringNo5000Extra context appended to AMC's built-in primer for every session on your plugin's project
sessions.showDividerbooleanNo—Defaults to true
sessions.suggestedPromptsarrayNo4 itemsTappable prompts under the session list (label ≤ 60, prompt ≤ 2000)

entryPoint and sidebar are both optional — a ui block is useful for its side effects alone, e.g. { "hideProjectPanel": true }. (Earlier SDK versions required them, so a manifest AMC installed happily could fail amc-plugin validate.)

"Full width" is two flags, not one

The column AMC clears for you has two owners, and each has its own opt-out. Hiding one alone just hands the column to the other, so a plugin that wants the full width must set both:

json
{ "ui": { "hideProjectPanel": true, "hideSessionsPane": true } }

hideSessionsPane was missing from this SDK's schema until 2026-08-21. Because the schema is non-strict, a manifest declaring both kept hideProjectPanel and silently dropped its sibling on the way through amc-plugin validate and package — so the plugin looked correct dev-loaded and un-full-widthed itself once packaged. If you worked around that by giving up on full width, you can stop.

contextTemplate supports single-pass substitution. Available variables are date, projectName, sessionName, workDir and pluginName. A whitespace-only template is treated as absent rather than rejected.

entryPoint and sidebar are both optional, matching AMC. A ui block carrying only hideProjectPanel or sessions is valid -- those are useful without a webview. Omit the whole block if you need none of them.

contextTemplate is folded after AMC's built-in plugin context, so your text adds to the system context rather than replacing it.

workspace Block ​

Declares the Workspace capability's command slots and binding granularity. Requires one or more workspace.* permissions.

json
{
  "workspace": {
    "binding": { "granularity": "package" },
    "commandSlots": [
      { "name": "vitest.run",  "args": ["--config", "{reporterConfig}", "{files}"] },
      { "name": "generic.run", "args": [] }
    ]
  }
}
FieldTypeRequiredDescription
binding.granularity"package"NoHow command bindings are keyed. "package" is the only value.
commandSlots[].namestringYesSlot name you pass to exec()
commandSlots[].argsstring[]YesStatic argument template. May be empty.

args is manifest-static by design -- there is no runtime placeholder -- so every flag your plugin can pass is visible at marketplace review. The user supplies the base command; AMC appends these arguments and spawns without a shell.

No host runtime yet

AMC does not implement the workspace namespace. This block validates and packages, but every ctx.workspace.* call rejects at runtime. See the Workspace API.

backend Block ​

Declares the backend entry point and optional resource limits.

json
{
  "backend": {
    "entryPoint": "dist/backend/index.js",
    "resourceLimits": {
      "memoryMb": 128
    }
  }
}
FieldTypeRequiredDescription
entryPointstringYesPath to the compiled JS file exporting activate
resourceLimits.memoryMbnumberNoMemory limit for the backend worker (in MB)

Omit the entire backend block if your plugin is UI-only.

permissions Array ​

List the permissions your plugin needs. AMC shows these to the user during installation.

json
{
  "permissions": ["storage", "sessions", "ai", "network", "cron", "cli", "notifications", "rss"]
}

See Permissions for a detailed breakdown of what each permission grants.

cli Block ​

Declare CLI endpoints that external tools can call through AMC's control server.

json
{
  "cli": {
    "endpoints": [
      {
        "method": "GET",
        "path": "status",
        "description": "Get plugin status",
        "auth": true
      },
      {
        "method": "POST",
        "path": "trigger",
        "description": "Trigger a plugin action",
        "auth": true
      }
    ]
  }
}
FieldTypeDescription
methodstringHTTP method: GET, POST, PUT, or DELETE
pathstringEndpoint path (appended to /plugins/<plugin-id>/)
descriptionstringHuman-readable description
authbooleanWhether the endpoint requires bearer-token authentication

Requires the cli permission.

cron Block ​

Declare scheduled jobs that AMC runs on a cron schedule.

json
{
  "cron": {
    "jobs": [
      {
        "id": "heartbeat",
        "label": "Heartbeat Check",
        "schedule": "*/30 * * * *",
        "description": "Periodic health check",
        "approvalRequired": true
      }
    ]
  }
}
FieldTypeDescription
idstringUnique job identifier
labelstringHuman-readable label shown in the AMC UI
schedulestringCron expression (standard 5-field format)
descriptionstringDescription of what the job does
approvalRequiredbooleanIf true, the user must approve each run in the inbox

Requires the cron permission.

sdkVersion ​

Declares the SDK version your plugin was built against. AMC uses this for compatibility checks.

json
{
  "sdkVersion": "^3.0.0"
}

Use semver range syntax. The scaffolder sets this to "^3.0.0" by default.

Complete Examples ​

Basic Template (UI Only) ​

json
{
  "plugin": {
    "id": "my-widget",
    "name": "My Widget",
    "version": "1.0.0",
    "author": "Your Name",
    "description": "A simple UI widget",
    "icon": "layout-dashboard",
    "category": "productivity",
    "license": { "type": "free" }
  },
  "settings": [],
  "storage": { "collections": {} },
  "migrations": [],
  "sdkVersion": "^3.0.0",
  "ui": {
    "entryPoint": "dist/ui/index.html",
    "sidebar": { "title": "My Widget", "icon": "layout-dashboard" }
  }
}

With-Backend Template ​

json
{
  "plugin": {
    "id": "data-sync",
    "name": "Data Sync",
    "version": "1.0.0",
    "author": "Your Name",
    "description": "Syncs data from external sources",
    "icon": "refresh-cw",
    "category": "devops",
    "license": { "type": "free" }
  },
  "settings": [
    {
      "key": "syncInterval",
      "label": "Sync Interval (minutes)",
      "type": "number",
      "default": 15,
      "min": 1,
      "max": 60
    }
  ],
  "storage": {
    "collections": {
      "sync_records": {
        "columns": {
          "source": "text",
          "status": "text",
          "data": "json"
        },
        "indexes": ["source"]
      }
    }
  },
  "migrations": [],
  "sdkVersion": "^3.0.0",
  "ui": {
    "entryPoint": "dist/ui/index.html",
    "sidebar": { "title": "Data Sync", "icon": "refresh-cw" }
  },
  "backend": {
    "entryPoint": "dist/backend/index.js"
  },
  "permissions": ["storage"]
}

Full Template ​

json
{
  "plugin": {
    "id": "monitor-suite",
    "name": "Monitor Suite",
    "version": "1.0.0",
    "author": "Your Name",
    "description": "Full monitoring and automation suite",
    "icon": "activity",
    "category": "devops",
    "license": { "type": "free" }
  },
  "settings": [
    {
      "key": "enabled",
      "label": "Enable Monitoring",
      "type": "toggle",
      "default": true
    },
    {
      "key": "webhookUrl",
      "label": "Webhook URL",
      "type": "text",
      "default": ""
    },
    {
      "key": "alertLevel",
      "label": "Alert Level",
      "type": "select",
      "default": "warn",
      "options": [
        { "value": "info", "label": "Info" },
        { "value": "warn", "label": "Warning" },
        { "value": "error", "label": "Error only" }
      ]
    }
  ],
  "storage": {
    "collections": {
      "checks": {
        "columns": {
          "name": "text",
          "status": "text",
          "last_run": "text",
          "result": "json"
        },
        "indexes": ["name", "status"]
      }
    }
  },
  "migrations": [],
  "sdkVersion": "^3.0.0",
  "ui": {
    "entryPoint": "dist/ui/index.html",
    "sidebar": { "title": "Monitor Suite", "icon": "activity" }
  },
  "backend": {
    "entryPoint": "dist/backend/index.js"
  },
  "permissions": ["storage", "cron", "cli"],
  "cli": {
    "endpoints": [
      { "method": "GET", "path": "status", "description": "Get plugin status", "auth": true }
    ]
  },
  "cron": {
    "jobs": [
      {
        "id": "heartbeat",
        "label": "Heartbeat Check",
        "schedule": "*/30 * * * *",
        "description": "Periodic health check",
        "approvalRequired": true
      }
    ]
  }
}

AMC Plugin SDK