Getting started
This walkthrough takes you from a fresh checkout of Aero to a working extension sideloaded into the editor.
1. Install & run Aero
Aero is an Electron app. Clone it, install dependencies (the postinstall step rebuilds the native terminal module against Electron), then launch:
git clone https://github.com/aeroide/aero
cd aero
npm install # also rebuilds node-pty for Electron (postinstall)
npm start # launch the editor
# npm run dev # launch with DevTools detachedIf the native terminal module fails to build, the editor still runs — the terminal just degrades gracefully. You don't need a terminal to author extensions.
Versions
The manifest's optional engines.aero field is a semver range checked against the running app version (e.g. ">=0.5.0"). Extensions install when the range matches. Check About Aero for your version.
2. Scaffold with aero-ext init
The aero-ext CLI scaffolds a ready-to-edit extension folder. Run it with npx (no global install needed):
npx aero-ext init my-extension
cd my-extensioninit asks for a publisher handle, machine name, display name, and which contribution types you want, then writes a starter tree:
my-extension/
├── aero.json # manifest, pre-filled and schema-valid
├── themes/
│ └── my-theme.json # if you chose themes
├── snippets/
│ └── javascript.json # if you chose snippets
└── extension.js # if you chose commands (sandboxed entry)The generated aero.json already validates against aero-manifest.schema.json. Open it in Aero and edit away — see the manifest reference for every field.
Naming rules
name and publisher are kebab-case (^[a-z0-9][a-z0-9-]*$). Together they form your canonical id "<publisher>.<name>", which is globally unique in the marketplace and becomes the on-disk folder name.
3. Build the package
A .aero-ext file is just a ZIP with aero.json at its root. The CLI validates your manifest against the schema and zips the folder for you:
npx aero-ext package
# → my-extension/aero-publisher.my-extension-1.0.0.aero-extpackage enforces the contract before it writes the archive:
aero.jsonmust pass the JSON Schema.- Every
pathincontributesmust be relative, forward-slash, and resolve inside the archive (no.., no absolute paths, no symlinks). - The archive must stay under 50 MB (the Storage bucket's hard limit).
4. Sideload it into Aero
To test before publishing, sideload the local .aero-ext. In the editor open the Extensions view in the activity rail and choose Install from file…, then pick your .aero-ext. Under the hood this calls the preload bridge:
api.ext.installLocal(aeroExtPath) -> { ok, id, version }Aero unzips it into your home directory (never the workspace):
~/.aero/extensions/
├── installed.json
└── aero.my-extension/
└── 1.0.0/ # your unpacked .aero-ext
├── aero.json
└── themes/my-theme.jsonThe extension is enabled immediately. Declarative contributions (themes/snippets/keybindings) register from the manifest right away; command JS loads lazily on its activation event.
5. Try it
- Theme: open the command palette and run your theme's apply command, or pick it from the theme list. Aero sets each
--<token>CSS custom property on<html>, flipsdata-theme, and callsmonaco.editor.setTheme(...). - Command: open the palette (
Cmd/Ctrl+Shift+P) and search for your commandtitle. - Keybinding: press your chord (e.g.
cmd+k cmd+t). - Snippet: in a file of the target language, type your
prefixand accept the completion.
6. Iterate
Edit files, re-package, and re-install. To manage installs, the Extensions view maps onto the preload surface:
ext.list() -> [{ id, version, enabled, manifest, dir, source }]
ext.setEnabled(id, enabled) -> { ok } # enable/disable, no file changes
ext.uninstall(id) -> { ok } # removes the <id> folder + index entryWhen you're happy, head to Publishing to push it to the marketplace.
Next steps
- Manifest reference — every
aero.jsonfield. - Themes · Commands · Keybindings · Snippets.
- The
aero.*API — for command logic. - Example extensions — two full walkthroughs.