Skip to content

The wamp CLI

wamp is a scaffolder. It creates an extension directory from a template, installs its dependencies, and builds it once. It does not load, install, publish, or sign anything — the runtime lives in the WAMP host.

After this page you know which commands exist, what each flag does to the generated directory, and how to get a scaffolded extension in front of a running host — which is not the step the CLI’s own success message tells you to run.

Everywhere below, wamp stands for that node …/bin/wamp.mjs invocation.

Command What it does
wamp init <name> Scaffolds a new extension directory. The only command that does anything.
wamp help Prints the top-level command list. wamp --help, wamp -h, and wamp with no arguments all print the same text.

That is the entire surface. There is no install, no build, no publish, no login, no add, and no --version. Any other first argument prints Unknown command and exits 2.

Terminal window
wamp init <name> [--template minimal|full] [--install] [--no-deps] [--no-build]
Flag Effect
--template <name>, -t <name> Template to copy: minimal (the default) or full. Any other value exits 2 and names the two that exist.
--install Symlinks the new directory into ~/.wamp/extensions/dynamic/. This is not the directory the host reads — see the caution in Getting it loaded.
--no-deps Skips the npm install run inside the new directory.
--no-build Skips the initial node build.mjs.
--help, -h Prints the usage text above with examples, and exits without creating anything. wamp init with no name prints the same.

Any other --flag prints Unknown flag: <flag> and exits 2. Extra positional arguments are ignored — only the first is read as the name. Passing -t as the very last argument leaves the template unset, which silently means minimal.

In order, init slugifies the name, refuses to continue if ./<slug>/ already exists, copies the template with substitutions applied, runs npm install, runs node build.mjs, and then optionally creates the symlink. A failure in the install or the build stops it with exit 1 and leaves the directory on disk.

The directory name is the slug, not what you typed

Section titled “The directory name is the slug, not what you typed”

The name is lowercased, every run of characters outside [a-z0-9-] becomes a single -, and leading and trailing dashes are stripped. wamp init "Client Tracker" creates ./client-tracker/. If nothing survives the transformation, it exits 2 with Invalid name.

That directory name is the extension’s id — there is no id field in the manifest.

Two more values are derived from the name:

  • The display name in extension.json is title-cased from what you typed: split on hyphens, underscores, and whitespace, then each word gets a capital first letter and a lowercased remainder. MyApp therefore becomes Myapp. Type the name spaced the way you want it read (wamp init "My App"), or edit extension.json afterward.
  • The tool namespace prefix is the slug with hyphens replaced by underscores, so client-tracker contributes tools named client_tracker_*. Tool names may not contain dots; see contributing tools.

The SDK dependency is a relative path into your checkout

Section titled “The SDK dependency is a relative path into your checkout”

The generated package.json lists @wamp/extension-sdk as a file: dependency holding the relative path from your new directory to the SDK inside the checkout the CLI ran from — for example file:../../dev/wamp/packages/extension-sdk. Since the package is not on a registry, there is no version string to substitute for it.

Two consequences worth knowing before you scaffold somewhere permanent: npm install only works while the checkout stays where it is, and the directory cannot be reinstalled by anyone who does not have that same checkout at that same relative path.

A page and nothing else.

my-app/
├── extension.json manifest: one page, activated on onStartupFinished
├── package.json build and dev scripts, esbuild plus the SDK
├── build.mjs esbuild driver, with a --watch mode
├── tsconfig.json extends the SDK's extension config
├── main/activate.ts empty activate() and deactivate()
└── ui/index.tsx the page component, exported under the page id

The manifest it writes declares version 0.1.0, engines.wamp ^12.0.0, compat.pluginApi ^1.0.0, main pointing at dist/main.js, a Sparkles icon, and a single page whose context is global. Every key is explained in the manifest reference.

The same shape plus the parts a complete product uses. It adds shared/schema.ts, declares permissions of database, ai, cron, and notifications, and sets the page’s presentation to app so it takes the window rather than docking.

Its main/activate.ts exercises four subsystems: a typed schema through data.defineSchema (typed data), a 9 a.m. daily digest through cron.schedule (scheduled work), a desktop toast through notifications.show, and one registered tool named <namespace>_create_thing (contributing tools). The page pairs that with an AI session narrowed to the extension’s own tools (AI sessions).

Note the guard at the top of its activate(): permission-gated namespaces are absent from ctx.api unless the manifest declares them, so the template throws a named error rather than dereferencing undefined. data is ambient and always present. See permissions.

npm run build runs node build.mjs; npm run dev runs it with --watch. The script asks the SDK for esbuild configurations, which read extension.json, resolve entry points by convention — main/activate.ts for the main process, ui/index.tsx for the renderer — and emit dist/main.js and dist/plugin.js with the host-provided packages left external.

This is the one way a CLI-scaffolded extension differs from a hand-written or assistant-written one: because it ships a build.mjs, it owns its build, and the host will not build it for you. Keep npm run dev running while you work; each new bundle that lands triggers a reload in the host.

Two approaches do work. The first is to put the extension directory — or your own symlink to it — in the folder the host watches:

Platform Watched folder
macOS ~/Library/Application Support/Wamp/extensions/dynamic/
Windows %APPDATA%\Wamp\extensions\dynamic\
Linux ~/.config/Wamp/extensions/dynamic/

Wamp is the product name; a branded build uses its own.

The second is to keep the source wherever you like and point the host at it with WAMP_DEV_EXTENSIONS, set to a directory that contains extension directories:

Terminal window
WAMP_DEV_EXTENSIONS="$HOME/src/wamp-extensions" open -a Wamp

Every subdirectory holding an extension.json is symlinked into the watched folder and gets the same hot-reload behavior. The linking happens once at startup, so quit the app before setting it. This variable is honored in packaged builds, not only in development ones.

Code Meaning
0 The scaffold succeeded, or help was printed.
1 A step failed — usually npm install or the initial build. The error is printed and the partially-created directory is left in place.
2 A usage error: unknown command, unknown flag, invalid name, unknown template, or a target directory that already exists.
  • Quickstart — the two authoring paths that need nothing installed.
  • Manifest reference — every key the template writes, and what declaring it does.
  • Packages and SDKs — what each published and unpublished package is for.
  • Troubleshooting — what to check when a scaffolded extension does not appear.