Skip to content

Quickstart

By the end of this page you have an extension in an ordinary project directory, linked into WAMP Desktop and rebuilding on every save. Install Node 18 or newer and keep WAMP Desktop running.

Open a WAMP chat in the workspace where the source should live and ask for the app you want. The native agent and each shipped ACP coding runtime receive the extension-development skill and use the same public CLI and declarations.

Build a Reading List extension in this workspace. Store title, author and a
want/reading/done status; add a page with a list and an add form. Run it in WAMP.

The agent scaffolds in the current workspace, implements the extension with wamp ext dev running, and finishes with wamp ext install, so the extension is already in WAMP when it reports back. It does not need a WAMP source checkout or a private import.

  1. Create a full project:

    Terminal window
    wamp ext init reading-list --template full
    cd reading-list
  2. Start the development loop:

    Terminal window
    wamp ext dev

    The command builds first, links this workspace into the WAMP profile, and watches for edits. A failed build leaves the last good version running.

  3. Open Reading List from the WAMP sidebar.

  4. When you are done, stop dev and install it so it stays:

    Terminal window
    wamp ext install
  • Directoryreading-list/
    • extension.json identity, compatibility, permissions and contributions
    • tsconfig.json public extension compiler configuration
    • Directorymain/
      • activate.ts tools, data, services and lifecycle registrations
    • Directoryui/
      • index.tsx pages and views
    • Directoryshared/
      • schema.ts typed-data schema in the full template
    • Directorydist/ validated runtime artifacts
      • …

There is no package.json and no build.mjs. Add a package.json only if you bundle extra npm dependencies; wamp ext dev and wamp ext pack call the SDK builder directly unless a build.mjs is present.

The directory name is the extension id. The manifest declares the runtime contract; the generated minimal form looks like this:

extension.json
{
"name": "Reading List",
"description": "Books to read.",
"version": "0.1.0",
"engines": { "wamp": "^12.0.0" },
"icon": "BookOpen",
"main": "dist/main.js",
"compat": { "pluginApi": "^4.0.0" },
"activationEvents": ["onStartupFinished"],
"contributes": {
"pages": [
{ "id": "reading-list", "title": "Reading List", "icon": "BookOpen", "context": "both" }
]
}
}

The renderer exports a component under the same page id:

ui/index.tsx
function ReadingListPage() {
return (
<div className="h-full p-6 bg-background text-foreground">
<h1 className="text-lg font-semibold">Reading List</h1>
</div>
);
}
export const views = { 'reading-list': ReadingListPage };

React, @wamp/ui, @wamp/plugin-api, Lucide and Zustand are host-provided renderer modules. The public builder bundles ordinary npm dependencies and Node dependencies used by main or server entries.

Make the loop visible. Open ui/index.tsx, add a button that talks to the host, and save:

ui/index.tsx
import { Button } from '@wamp/ui';
import { pluginAPI } from '@wamp/plugin-api';
function ReadingListPage() {
return (
<div className="h-full p-6 bg-background text-foreground">
<h1 className="text-lg font-semibold">Reading List</h1>
<Button className="mt-4" onClick={() => pluginAPI.notify.success('Still here')}>
Say hello
</Button>
</div>
);
}
export const views = {
'reading-list': ReadingListPage,
};

The open window picks up the new code without a restart, and the button raises a host toast. That is the whole authoring loop: edit source, save, see it.

If the page fails to render after a save, the most common cause is importing a symbol @wamp/ui does not export. The build names it exactly, and the interface kit has the list of what exists.

  • Core concepts — the vocabulary, each term building on the last.
  • The manifest — every key, and what declaring it does.
  • Typed data — storage with a schema, shared by your page and your background code, which is where most apps go next.
  • Contributing tools — let the assistant call your app’s own functions.
  • Choosing a path — how this reaches other people.