Build an extension with your agent
The normal way to create a Neon Pilot extension is to ask your agent to build it for you.
Extensions are how Neon Pilot grows new product features. You usually should not hand-write one from scratch: describe the workflow you want, then ask your agent to create, build, reload, and test the extension. The manifest and SDK docs are reference material for the agent and for debugging.
Copy-paste prompt
Build a Neon Pilot extension that [does what].
Before implementation, produce a short UX brief and ask me focused product/design questions for anything ambiguous so you can build the right first version in one pass. The brief must name the primary user, the job-to-be-done, the primary surface, the default/empty/loading/error/success states, the main actions, and the shared UI primitives you will reuse from `@neon-pilot/extensions/ui`.
Use the extension manager/template if helpful. Pick the right surface:
- main page for a full app/workflow
- tab-local right rail for a compact conversation-specific tool panel inside the workbench
- workbench detail for split-pane workflows
Implement it with editable source files, build it, reload it, visually test the exact user path, fix any layout or interaction problems you see, and checkpoint the changes.
Add concrete product details after the first sentence: what data it should show, what actions it should support, and what “done” looks like.
Production agent loop
Use this as the no-ambiguity loop for an agent building an extension in a repo checkout:
-
Read this guide,
docs/extensions.md,packages/extensions/README.md, and the closest existing extensionREADME.md. - Inspect existing extension ids, routes, nav labels, action ids, commands, settings components, and tools before choosing names.
- Write a short UX brief before implementation:
- Ask focused questions for unresolved UX/product decisions before writing code. If the user gave enough detail, state the assumptions and proceed.
-
Start from
docs/extension-templates/when the feature matches a template; otherwise copy the closest first-party extension shape. -
Create editable source files in
src/, declare every contribution inextension.json, and keep generated bundles indist/. - Build with
pnpm run extension:build -- <extension-dir>. -
Run
neon-pilot-extension doctor <extension-dir>when the CLI is available; in a packaged app, runneon-pilot extensions validate --package-root <extension-dir>before install orneon-pilot extensions validate <extension-id>after install. For repo extension or boundary work, also runpnpm run check:extensions:static. - Reload extensions from Settings -> Extensions, or restart the desktop app when reload is unavailable.
-
Run
neon-pilot extensions smoke <extension-id>when the app is running, then validate through the same surface the user will use: open the route, rail, Settings section, command, composer control, or agent tool. - Exercise empty, loading, error, success, disabled, and long-running states when the surface has UI; for backend tools/actions, run one representative invocation and inspect the transcript or visible result.
- Visually inspect the UI against the brief. Check layout density, text wrapping, keyboard/focus behavior, responsive constraints, empty/error copy, command availability, and whether shared primitives were used instead of one-off chrome.
- Update the extension
README.mdwith install/build/use notes and any non-obvious behavior. -
If the extension is meant for other users, prepare
.neon-extension.ziprelease artifacts and document the GitHub release tag users should install from. - Checkpoint only the files touched for this extension and its docs.
- Primary user and job: who uses it, what they are trying to accomplish, and what they should inspect or change
first. - Primary surface: exactly one first-version surface: main-page, right-rail,
workbench-detail, settingsComponent, backend tool/action, or theme. -
Information architecture: the core sections, list/detail structure, controls, and command-backed actions. -
State model: default, empty, loading, error, success, disabled, and long-running states. -
Primitive plan: which @neon-pilot/extensions/ui components will be used for page shell,
lists/tables, forms, feedback, dialogs, runtime status, rails, or workbench chrome. - Visual acceptance: what
must be visible in the app screenshot or manual inspection before calling the UI correct.
Do not stop after a successful build. A built extension is only ready after its manifest diagnostics are clean and the user-visible path has been exercised.
Templates
Before writing from scratch, check
docs/extension-templates/
for copy-paste stubs derived from real first-party extensions:
| Template | Pattern |
|---|---|
data-dashboard
|
Read-only page — load from backend, render table or cards |
crud-page
|
List + slide-in form editor. Full CRUD. |
settings-section
|
Section in the shared Settings page. No separate route. |
Copy the matching folder, rename the extension id, replace domain types, and build.
Pick the right surface
Use this as agent guidance, not homework for the user:
| If you want... | Ask for... |
|---|---|
| A full app, dashboard, or workflow | main-page extension |
| Context inside a workbench tab-local rail | right-rail extension |
| A compact rail panel plus workbench pane detail view | workbench-detail extension |
| Something the agent can call | backend tool or action |
| A command palette, slash command, or composer button | command/composer contribution |
| Settings for an integration | settings contribution |
| Recurring or background behavior | automation/scheduled-task backed extension |
| A color theme only | theme contribution |
When unsure, tell the agent the user experience you want and let it choose the smallest surface that fits.
What your agent should do
For a new extension, the agent should:
- Inspect existing extension IDs, routes, commands, and nearby examples before choosing names.
- Create the package through Extension Manager when available, or create the same package layout by hand.
- Keep editable source files in
src/; do not create dist-only extensions. - Declare surfaces, commands, tools, settings, skills, and permissions in
extension.json. - Use
@neon-pilot/extensionsas the SDK seam; do not import app internals. - Build outside the desktop app using repo or CLI extension tooling.
- Validate and fix Extension Manager diagnostics.
- Reload extensions.
- Open the contributed page/panel and visually inspect UI changes.
- Add or update the extension
README.mdwhen behavior is non-obvious. -
If publishing through an extension repo, build release artifacts; source folders plus
neon.extensions.jsonare not enough for normal GitHub install. - Checkpoint only the files it touched.
Where files live
User-created extensions live in runtime state by default:
~/.local/state/neon-pilot/extensions/{extension-id}/
Bundled first-party system extensions live in the repo under extensions/. Optional first-party extensions live in
patleeman/neon-pilot-extensions and install from
GitHub release artifacts. See Extension Distribution before publishing packages for
other users.
A normal native extension package looks like:
my-extension/
extension.json
package.json
README.md
src/
frontend.tsx
backend.ts
styles.css
dist/
frontend.js
frontend.css
backend.mjs
src/ is the source of truth. dist/ is generated output that every desktop runtime loads.
Extension repositories and releases
When building an extension repository for other users, do not stop at source folders and neon.extensions.json. GitHub
install expects prebuilt release assets:
<extension-id>.neon-extension.zip
neon-extension-catalog.json
Use patleeman/neon-pilot-extensions as the example
repo. Its release flow is:
NEON_PILOT_REPO=/path/to/neon-pilot pnpm run release:prepare -- --tag v0.9.1-rc.6
gh release create v0.9.1-rc.6 \
release-artifacts/v0.9.1-rc.6/*.neon-extension.zip \
release-artifacts/v0.9.1-rc.6/neon-extension-catalog.json \
--repo owner/repo
Use the app version tag unless the catalog package explicitly declares another compatible tag. A repo without release
assets can be inspected, but normal users cannot install its packages through the GitHub install flow.
Good extension requests
Build a tab-local right-rail extension that shows a checklist for the current conversation. It should let me add, complete, and delete items, and persist per conversation.
Build a main-page extension for reviewing background work. It should list recent executions, show status and duration, and open background command or subagent logs in a detail pane.
Build an extension that adds an agent-callable tool for looking up snippets from my local workspace glossary. Include a small settings panel for the glossary path.
Build a theme-only extension with a calm dark palette. Install it, reload extensions, and tell me how to enable it.
Build, reload, validate
Build outside the desktop app:
pnpm run extension:build -- /path/to/my-extension
# or, when linked/installed:
neon-pilot-extension build /path/to/my-extension
In the packaged app, use Extension Manager actions to create, validate, and reload built artifacts. Extension UI communicates with
backend actions through the native PA client/IPC bridge; do not build extension frontends that fetch
/api/extensions/*.
Validation is not optional. The extension doctor catches missing bundles, stale output, bad manifest references, missing frontend/backend exports, tool schema problems, forbidden backend imports, non-portable paths, and backend import crashes.
Acceptance criteria for agent-built extensions:
-
extension.jsonuses schema v2, stable kebab-case ids,/ext/{extension-id}routes for main pages, and matching frontend/backend export names. -
Runtime code imports only from
@neon-pilot/extensions,@neon-pilot/extensions/ui, and narrow@neon-pilot/extensions/backend/*subpaths for host access. - Backend actions validate their inputs enough to return useful errors instead of crashing on malformed agent/tool calls.
-
UI calls backend actions through
pa.extension.invoke(...)and shows loading, empty, error, and success states. - Dist files are current, diagnostics are clean, and the extension has been reloaded in the app.
- The contributed surface or tool was exercised through the app/extension host, not only by unit tests or direct module imports.
Troubleshooting
-
The page or panel does not appear — reload extensions and check manifest
contributes.views/contributes.nav. - The UI opens blank — check frontend export names and Extension Manager diagnostics.
- Backend action/tool is missing — check backend import errors and handler export names.
-
Works from source but not in the app — build
dist/; the app does not compile extensions at runtime. -
Settings section does not appear — use one
contributes.settingsComponentobject withid,component,sectionId, andlabel; the component export name must matchcomponent. -
Agent tool returns an opaque failure — validate action/tool input and return a structured
{ text, details }result when the transcript should show more than a raw object. -
Need an app capability the SDK lacks — add the smallest reusable API to
@neon-pilot/extensions; do not import desktop/server internals.