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>.json

Required 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 sets license: "UNLICENSED".
  • At least one entry point — either ui/index.html (for UI extensions) or wasm/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:

RuleLimit
Total ui/** size (gzipped)≤ 300 KiB (warn at 200)
Inline <script> blocksForbidden
eval, new FunctionForbidden
External fonts/images/CSSForbidden — bundle them
Service workersForbidden

Wasm Directory

For component-v1 and hybrid-v1 extensions, the wasm/ directory contains your compiled WASI component.

RuleValue
FormatWASI 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:

PathPurpose
.oxp/integrity.jsonPer-file SHA-256 manifest (added by oxp publish)
.oxp/SIGNATUREEd25519 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.oxp

This 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.