Getting Started
Project Structure
Anatomy of an OXP extension: every file, every directory, what's required and what's optional.
Every OXP extension follows a standard directory structure. Understanding it helps you organize your code, add features, and avoid common mistakes.
Full Layout
my-extension/
├── oxp.json REQUIRED — the manifest
├── README.md Optional — surfaced on the extension page
├── CHANGELOG.md Optional
├── LICENSE REQUIRED if license is not "UNLICENSED"
├── icons/
│ └── icon.svg Referenced by manifest.icon
├── ui/ Present when manifest.main.ui is set
│ ├── index.html Entry document (CSP-locked)
│ ├── assets/
│ │ ├── main.[hash].js ES2022, no eval
│ │ ├── main.[hash].css Bundled styles
│ │ └── *.{woff2,svg,png} Bundled assets
│ └── chunks/ Code-split lazy chunks
├── wasm/ Present when manifest.main.wasm is set
│ ├── core.wasm WASI Component Model, Preview 2
│ └── core.d.ts Generated TS types (informative)
├── contributions/ Files referenced by manifest.contributes
│ ├── commands.json
│ ├── views.json
│ ├── menus.json
│ └── keybindings.json
└── locales/ Optional i18n catalogues
├── en.json REQUIRED if any locale present
└── <bcp47>.jsonRequired Files
Every extension must have:
- **
oxp.json** — the manifest. This is the heart of your extension. It declares identity, permissions, entry points, and compatibility. - **
LICENSE** — required unless your manifest setslicense: "UNLICENSED". - At least one entry point — either
ui/index.html(for UI extensions) orwasm/core.wasm(for component extensions), or both (hybrid).
The Manifest (oxp.json)
The manifest is a JSON file conforming to spec/v1/manifest.schema.json. See the Manifest Reference for a complete field-by-field guide.
UI Directory
If your extension has a user interface (most do), the ui/ directory contains the HTML, CSS, JavaScript, and assets that render it.
Constraints
These are enforced at oxp pack and again at oxp publish:
| Rule | Limit |
|---|---|
Total ui/** size (gzipped) | ≤ 300 KiB (warn at 200) |
Inline <script> blocks | Forbidden |
eval, new Function | Forbidden |
| External fonts/images/CSS | Forbidden — bundle them |
| Service workers | Forbidden |
Wasm Directory
For component-v1 and hybrid-v1 extensions, the wasm/ directory contains your compiled WASI component.
| Rule | Value |
|---|---|
| Format | WASI Component Model, Preview 2 |
| Max size | ≤ 8 MiB per component |
| Initial memory | ≤ 16 MiB |
| Max memory | ≤ 256 MiB |
Contributions Directory
The contributions/ directory contains JSON files that declare commands, views, menus, keybindings, and other IDE-level contributions. Each file is referenced by a field in manifest.contributes.
Locales Directory
If your extension supports internationalization, place BCP 47 locale files in locales/. If any locale is present, en.json is required as the fallback.
Reserved Paths
The following paths are reserved and must not appear in your source:
| Path | Purpose |
|---|---|
.oxp/integrity.json | Per-file SHA-256 manifest (added by oxp publish) |
.oxp/SIGNATURE | Ed25519 or Sigstore signature (added by oxp publish) |
Path Rules
All files must follow these rules:
- File names must match
^[A-Za-z0-9._-][A-Za-z0-9._/-]{0,254}$ - No symlinks, hardlinks, devices, FIFOs, or sockets
- No path may resolve outside the bundle root (no
../traversal) - Total uncompressed size must not exceed 64 MiB
- Individual files must not exceed 16 MiB
- File count must not exceed 2,000
Build Output
When you run oxp pack, a .oxp file is created in dist/:
dist/
└── hello-world-0.0.1.oxpThis is a POSIX tar archive compressed with zstd (level 19). The .oxp suffix is the public contract — it's what gets uploaded to the registry and installed by users.