Skip to content

CLI Reference ​

The amc-plugin CLI is a Commander.js-based tool for building, validating, packaging, and publishing Omniscio plugins.

Install ​

bash
npm install -g @agent-mc/plugin-cli

Commands ​

create ​

Scaffold a new plugin project with starter files, manifest, and optional git init.

Usage:

bash
amc-plugin create <name> [options]

Arguments:

NameDescription
namePlugin name in kebab-case (e.g. my-plugin)

Options:

FlagDescriptionDefault
-t, --template <template>Template variant: basic, with-backend, fullbasic
--display-name <name>Display name (skips interactive prompt)—
--description <desc>Plugin description—
--author <author>Plugin author—
--category <category>Category: planning, development, testing, devops, productivity, otherother
--tags <tags>Comma-separated discoverability tags (≤10, ≤30 chars each). Blank falls back to the categorycategory
--icon <icon>Path to your logo inside the package, or a Lucide icon name for a generic glyph. A placeholder SVG is written at the default path for you to replaceassets/icon.svg
--skip-installSkip npm install after scaffoldingfalse
--skip-gitSkip git init and initial commitfalse

Example:

bash
# Interactive mode
amc-plugin create my-plugin

# Non-interactive (CI-friendly)
amc-plugin create my-plugin \
  --template with-backend \
  --display-name "My Plugin" \
  --description "Does cool things" \
  --author "Jane Doe" \
  --tags "linter, security" \
  --skip-git

Exit codes: 0 success, 1 error (invalid name, template, or cancelled prompt).


build ​

Compile TypeScript, copy non-TS UI files to dist/, and scan for banned imports.

Usage:

bash
amc-plugin build

Options: None.

What it does:

  1. Validates manifest.json against the SDK schema.
  2. Runs tsc to compile TypeScript to dist/.
  3. Copies non-TS files from src/ui/ to dist/ui/ (HTML, CSS, images).
  4. Scans dist/ for banned imports (electron, better-sqlite3, worker_threads, child_process — the last two in both their bare and node:-prefixed spellings) and warns on a hit. validate runs the same scan and fails instead.

Example:

bash
cd my-plugin
amc-plugin build

Exit codes: 0 success, 1 manifest invalid or TypeScript compilation failed.


validate ​

Run all validation checks without building. CI-friendly -- returns a non-zero exit code on any failure.

Usage:

bash
amc-plugin validate

Options: None.

Checks performed:

CheckDescription
Manifest schemaValidates manifest.json against the SDK schema
Command tablesFails on a table that can hold a runnable command; warns on fuzzier shapes — see Command tables
SDK versionEnsures sdkVersion field is present
UI entry pointVerifies the declared UI entry file exists
Backend entry pointVerifies the declared backend entry file exists
TypeScriptRuns tsc --noEmit to check for type errors
Banned importsScans dist/ for disallowed Node/Electron imports — see below

Banned imports, in detail. The scan reads every .js, .mjs and .cjs file under dist/ (for a flat plugin: the entry folders and single entry files you ship as authored) and rejects electron, better-sqlite3, worker_threads and child_process, matching all four forms a plugin can emit (require('x'), import … from 'x', side-effect import 'x', and dynamic import('x')), for both the bare and node:-prefixed spellings of the two Node builtins. Only the module name inside the quotes is matched, so a package that merely starts with a banned name — electron-store, child_process-promise — is not flagged.

Because the scan walks all of dist/, it also sees any dependency you vendor in there. child_process in particular is common in third-party code, so if you bundle dependencies into dist/ rather than declaring them, expect the scan to find them. That is working as intended: whatever ships in dist/ runs under Node's --permission, which denies spawning a process regardless of which file asked.

Where the scan looks — and its one limit. It reads your project on disk (dist/, or a flat plugin's as-authored entry dirs), not the .amcplugin archive itself. build, validate and publish's preflight all resolve that location the same way, so they never disagree about what "the shipped files" means. The limit: if you build an archive and then delete the output it was made from, there is nothing left to inspect — which is exactly why that case warns instead of passing. Treat this as a guardrail against accident, not a sandbox; the runtime boundary is the worker itself, which cannot reach these modules no matter what passes the scan.

Example:

bash
# In a GitHub Actions workflow
amc-plugin validate

Exit codes: 0 all checks passed, 1 one or more checks failed.

Command tables ​

A plugin's backend must act only on commands from its own panel or its own code, never on a table row: AI agents on the person's computer can read every table, and on older Omniscio builds write them too (see Panel commands). So validate, preflight and publish all run one rule over the tables your manifest declares. It reads only manifest.json, so the three always agree. It is the same checkCommandTables function the SDK exports.

Column names are read by their words: payloadJson, payload_json and payload-json all read as "payload", and a trailing json / text / raw word is ignored.

ResultWhen
FailsA table has an instruction column (any word type, command, cmd, action, op, operation, kind, method, verb), an argument column (last word payload, args, arguments, params, parameters, input, inputs, body, data, prompt) and a status column (last word status or state)
WarnsA prompt-like column (last word prompt, instruction(s), script) with a status; a queue-like table name (queue, job(s), command(s), action(s), outbox…) with a status and an instruction or argument column; a table that is agentWritable and has a status
Warns (validate only)Shipped JS that asks a table for its pending or queued rows (.query(…, { where: { status: 'pending' } }), also when the column has a longer name such as summary_status or jobState)
Passes with a noticeA failing table that carries a written commandTableWaiver (20–500 characters) and is not agentWritable

How to fix a failure: move the commands onto the command channel and reduce the table to a job list (label, status, error, times), or — if the table is genuinely safe — add a commandTableWaiver explaining why. Marketplace review sees the waiver.

What it cannot catch. It is a second line of defence, not a proof:

  • an instruction without an instruction column (a prompt + status table only warns);
  • programs stored as data (a workflow graph in a row), or a re-armable status over plain data;
  • authority fields (an approval flag, a spending cap, a host that receives secrets);
  • a JSON blob hiding the shape, or table names built at run time;
  • anyone who skips it: publish --skip-preflight, a CLI older than 3.2.0, or a raw upload.

The plugin-table fence in Omniscio (agentWritable) and the command channel are the real protection; this check stops the classic mistake from shipping by accident.


package ​

Bundle the plugin into a .amcplugin archive (zip) for distribution or marketplace upload.

Usage:

bash
amc-plugin package

Options: None.

What it does:

  1. Validates manifest.json.
  2. Builds if dist/ does not exist.
  3. Creates <plugin-id>-<version>.amcplugin in the project root.
  4. Includes manifest.json, dist/, assets/ (if present) and the root README.md (if present — the marketplace renders it as the listing's long description; CLI 3.1 and later).
  5. Warns if the archive exceeds the 50 MB marketplace limit.

Example:

bash
amc-plugin package
# Packaged: my-plugin-1.0.0.amcplugin (0.12 MB)

Exit codes: 0 success, 1 manifest invalid or build failed.


preflight ​

Run publish-readiness checks without uploading. This is the same gate publish runs before an upload, exposed as a standalone dry-run so you can fix issues first.

Usage:

bash
amc-plugin preflight [options]

Options:

FlagDescriptionDefault
--changelog <text>Changelog for this version (checked for presence)—

Checks performed:

CheckFails whenWarns when
VersionManifest version is already published (marketplace versions are immutable) or older than the latest published version—
Changelog—No changelog provided
PermissionsAn unknown permission is declaredDuplicate permissions
Command tablesA table can hold a runnable command (the rule) and carries no valid waiverA fuzzier command-like shape
Banned importsThe shipped files import a banned module (details)There is no built output to scan
Package sizeArchive exceeds the 50 MB marketplace limitArchive exceeds 25 MB
Listing—No README.md at the plugin root, an absent or empty plugin.screenshots, or an absent or empty plugin.links — the marketplace detail page would be bare (see Publishing → What your listing shows)

If the marketplace registry is unreachable, the version check is skipped rather than blocking.

Why the banned-import check appears twice

validate is a check you choose to run; this is the one standing between a banned import and the marketplace. Both use the same rule and look in the same place, so a plugin that passes validate passes here.

"No built output to scan" warns rather than fails — with nothing inspected, zero hits proves nothing, and reporting a pass would be a false all-clear. Run amc-plugin build first so the files you are about to upload are the ones that get checked.

Example:

bash
amc-plugin preflight --changelog "Added dark mode support"
# ✓ Version: 1.1.0 is newer than the published 1.0.0
# ⚠ Permissions: Duplicate permission(s): storage
#   → Remove the duplicate entries from manifest.json permissions.
# ⚠ Listing: Listing will be bare — missing: screenshots (plugin.screenshots), support links (plugin.links)
#   → Add a README.md next to manifest.json, hosted http(s) image URLs under plugin.screenshots, and support/homepage URLs under plugin.links — the marketplace detail page renders all three.
# ✓ Package size: 0.12 MB

Exit codes: 0 all checks passed (warnings allowed), 1 one or more checks failed.


publish ​

Upload a .amcplugin archive to the Omniscio Marketplace for review. Authenticates via GitHub OAuth on first use.

Usage:

bash
amc-plugin publish [options]

Options:

FlagDescriptionDefault
--changelog <text>Changelog text for this version—
--watchPoll until the submission is approved or rejected (up to 3 hours)false
--skip-preflightSkip the pre-upload readiness checksfalse
--as <github-user>Assert the expected GitHub account; aborts before upload on mismatch—
--switch-accountSign out first and re-authenticate as a different accountfalse
-y, --yesSkip the upload-identity confirmation prompt (for CI)false

What it does:

  1. Checks for a stored auth token; prompts GitHub OAuth if missing.
  2. Confirms the uploading identity before upload (see the account trap below).
  3. Locates a .amcplugin file (runs amc-plugin package if none found).
  4. Runs preflight readiness checks (unless --skip-preflight); aborts on any failure.
  5. Uploads the archive to the marketplace.
  6. With --watch, polls every 30 seconds for the review decision.

The GitHub account trap

GitHub sign-in reuses whatever account your default browser is already logged into — there is no account chooser, so a publish can silently go out under the wrong identity (marketplace ownership is tied to the GitHub account).

Before uploading, publish shows Uploading as: <github> and asks you to confirm. If it's the wrong account:

  • Run amc-plugin publish --switch-account to sign out and re-authenticate, or
  • Use --as <github-user> in scripts to hard-assert the intended account (aborts on mismatch).

To land on the right account during sign-in, open an incognito / private window signed into the correct GitHub account first, or sign out at https://github.com/logout.

Example:

bash
# Interactive — confirms "Uploading as: <you>" before upload
amc-plugin publish --changelog "Added dark mode support" --watch

# Publish under a specific account, re-authenticating if needed
amc-plugin publish --switch-account

# CI — assert the account and skip the prompt
amc-plugin publish --as my-org-bot --yes

Exit codes: 0 success (or approved with --watch), 1 preflight failed, upload failed, rejected, or --as mismatch.


status ​

Show the marketplace submission status for the current plugin.

Usage:

bash
amc-plugin status

Options: None.

What it does:

Reads manifest.json to determine the plugin ID, then queries the marketplace for all submissions matching that ID. Displays status, version, and review feedback.

Example:

bash
amc-plugin status
# Submissions for "my-plugin":
#   [OK] my-plugin v1.0.0 — approved (5/15/2026)
#   [?]  my-plugin v1.1.0 — pending (5/17/2026)

Exit codes: 0 success, 1 auth failed.


whoami ​

Show the authenticated GitHub username.

Usage:

bash
amc-plugin whoami

Options: None.

Example:

bash
amc-plugin whoami
# Signed in as: janedoe (uid: abc123)

Exit codes: 0 always.


logout ​

Clear the stored marketplace authentication token.

Usage:

bash
amc-plugin logout

Options: None.

Example:

bash
amc-plugin logout
# Signed out (was: janedoe)

Exit codes: 0 always.


dev ​

Launch the dev shell with hot-reload for rapid plugin development.

Usage:

bash
amc-plugin dev [options]

Options:

FlagDescriptionDefault
--no-buildSkip the initial TypeScript buildfalse

What it does:

  1. Builds the plugin (unless --no-build is passed).
  2. Opens the dev shell -- an Electron window that loads your plugin UI with a mock AgentMC context.
  3. Watches src/ for changes and hot-reloads automatically.

Example:

bash
amc-plugin dev
amc-plugin dev --no-build

Exit codes: 0 clean exit, 1 build failed.


info ​

Show a summary of the current plugin project (name, version, author, category, discoverability tags, permissions, entry points).

Usage:

bash
amc-plugin info [options]

Options:

FlagDescriptionDefault
--jsonOutput the summary as JSONfalse

Example:

bash
amc-plugin info
# Plugin:      my-plugin
# Version:     1.0.0
# Category:    other
# Tags:        other, productivity
# Permissions: storage, cron
# UI:          dist/ui/index.html
# Backend:     dist/backend/index.js

amc-plugin info --json
# {"id":"my-plugin","version":"1.0.0", ...}

Exit codes: 0 success, 1 no manifest.json found.


update ​

Self-update the @agent-mc/plugin-cli package to the latest version.

Usage:

bash
amc-plugin update [options]

Options:

FlagDescriptionDefault
--checkCheck for updates without installingfalse

Example:

bash
amc-plugin update --check
# Current: 1.0.0, Latest: 1.2.0 — update available

amc-plugin update
# Updated @agent-mc/plugin-cli to 1.2.0

Exit codes: 0 success (or already up to date), 1 update failed.


test ​

Run the plugin test suite with vitest. Uses the plugin's local vitest if installed, otherwise falls back to npx vitest.

Usage:

bash
amc-plugin test [patterns...] [options]

Arguments:

NameDescription
patternsOptional test file patterns to filter (passed through to vitest)

Options:

FlagDescriptionDefault
--watchRun vitest in watch modefalse

Testing your backend with the SDK harness:

The SDK ships a test harness at @agent-mc/plugin-sdk/testing that gives you a faithful in-memory PluginContext — real storage and db (query / where / orderBy / limit, paged like Omniscio: 100 rows unless you pass a limit), plus capture surfaces for toasts, notifications, logs, events, sidebar, and inbox, and triggers for cron jobs and CLI handlers. No Omniscio or Electron needed.

ts
import { describe, it, expect } from 'vitest'
import { createTestContext } from '@agent-mc/plugin-sdk/testing'
import activate from './index.js'

describe('my backend', () => {
  it('stores a note and shows a toast', async () => {
    const h = createTestContext({ settings: { apiKey: 'sk-test' } })
    const backend = activate(h.ctx)
    backend.onEnable?.()

    await h.ctx.db.insert('notes', { title: 'hello' })
    expect(await h.ctx.db.query('notes')).toHaveLength(1)
    expect(h.toasts.map((t) => t.message)).toContain('Saved')
  })

  it('runs a cron job and answers a CLI request', async () => {
    const h = createTestContext()
    activate(h.ctx)
    await h.runCron('heartbeat')                       // invoke a registered cron handler
    const res = await h.callCli('status', { method: 'GET', path: 'status' })
    expect(res.status).toBe(200)
  })
})

Inject fetch, ai, and auth via options to control outbound calls:

ts
const h = createTestContext({
  fetch: async () => new Response('{"ok":true}', { status: 200 }),
  ai: { generateMessage: async () => 'stubbed reply' },
  auth: { user: { uid: 'u1', email: 'a@b.co', displayName: null, photoURL: null } },
})

The with-backend and full scaffold templates come with vitest, a test script, and a starter src/backend/index.test.ts wired to this harness.

Example:

bash
amc-plugin test
amc-plugin test --watch
amc-plugin test src/backend

Exit codes: propagates vitest's exit code (0 all passed, 1 failures), 1 if vitest can't run.


doctor ​

Diagnose your local environment for plugin development. Run it any time something isn't working -- it reports a pass / warning / fail for each dependency the toolchain relies on, with a fix suggestion for anything that isn't right.

Usage:

bash
amc-plugin doctor [options]

Options:

FlagDescriptionDefault
--jsonOutput the results as JSONfalse

Checks performed:

CheckDescription
Node.jsNode version is supported (>= 18, 20+ recommended)
Plugin SDK@agent-mc/plugin-sdk is installed and up to date with npm
Manifestmanifest.json (if present) is valid against the SDK schema
Omniscio hostA running Omniscio is reachable on 127.0.0.1:19519 (for local install / hot-reload)
Omniscio CLI tokenA control-server token is available (~/.amc/cli-token or $AMC_CLI_TOKEN)
Marketplace APIThe marketplace backend is reachable (needed to publish)

Warnings never fail the command -- only a hard failure (unsupported Node, or an invalid manifest.json while inside a plugin project) sets a non-zero exit code. Host, token, and marketplace checks are environmental and only ever warn.

Override the host port with the AMC_CLI_PORT environment variable.

Example:

bash
amc-plugin doctor
# Omniscio Plugin Doctor
# ✓ Node.js: Node v22.11.0
# ✓ Plugin SDK: @agent-mc/plugin-sdk 1.1.0
# ✓ Manifest: manifest.json is valid
# ⚠ Omniscio host: No running Omniscio on 127.0.0.1:19519
#     → Start Omniscio to enable local install and hot-reload.
# ✓ Omniscio CLI token: Omniscio CLI token available
# ✓ Marketplace API: Reachable
#
# ⚠ 5 passed, 1 warning, 0 failed

amc-plugin doctor --json

Exit codes: 0 no failures, 1 an unsupported Node or invalid manifest.

Omniscio Plugin SDK