Overview
Architecture
How OXP is structured: the monorepo, the package graph, the WASI runtime, and how everything fits together.
OXP is organized as a pnpm monorepo with a clear separation between the spec, the runtime packages, the CLI, the registry web app, and the host adapters. This page walks through the architecture top-to-bottom.
Monorepo Layout
oxp/
├── spec/v1/ Normative specification (schema, protocol, bundle format)
├── packages/
│ ├── types/ TypeScript types for manifest + protocol (source of truth)
│ ├── schema/ JSON Schema + Ajv validator for oxp.json
│ ├── bundle/ Pack, unpack, sign, verify .oxp bundles
│ ├── sdk/ Author-facing SDK (defineExtension, HostApi, capability helpers)
│ ├── ui/ @oxprotocol/ui component vocabulary + DOM renderer
│ ├── cli/ The `oxp` command-line tool
│ ├── create-oxp/ `npm create oxp` wrapper (reserved, delegates to CLI)
│ ├── host-core/ Runtime-agnostic install + verify + activate pipeline
│ ├── host-runtime/ WASI Component Model runtime (jco backend, capability broker)
│ └── wit/ WIT contracts (oxp:host + oxp:extension worlds)
├── hosts/
│ ├── vscode/ VS Code / Cursor / Windsurf / VSCodium host adapter
│ ├── jetbrains/ IntelliJ Platform host adapter (Kotlin)
│ ├── neovim/ Neovim host adapter (Lua)
│ └── piye/ Piye IDE native L2 host adapter (in progress)
├── apps/
│ └── web/ Registry website + API (Next.js + Prisma + Postgres)
├── examples/
│ ├── hello-world/ HTML template extension
│ ├── hello-rust/ Rust WASI component extension
│ └── security-tests/ Malicious bundle fixtures for security testing
└── docker-compose.yml Local Postgres + MinIO for developmentPackage Dependency Graph
The packages form a clean dependency tree with @oxprotocol/types at the root:
types ─────────┬──── schema
├──── sdk
├──── ui
├──── wit ──────── host-runtime
│ │
├──── bundle ──────────┤
│ │
└──── host-core ───────┘
│
cli ┘Every package is published to npm under the @oxprotocol scope. The workspace:* protocol is used for internal dependencies during development.
The WASI Component Model
OXP extensions run as WASI Preview 2 components. This is not optional — it is the foundation of OXP's security model.
Why WASI
| Property | Traditional (Worker threads) | WASI Component Model |
|---|---|---|
| Isolation | Realm-only; shared OS process | SFI; capabilities are linker-level imports |
| Universality | JS only; per-OS binaries | One .wasm runs on every OS / CPU / host |
| Languages | JS / TS | Rust, Go, C/C++, Python, JS (via jco) |
| Standardization | Ad-hoc | Bytecode Alliance standard |
| Capability model | Runtime checks | Type system (WIT imports) |
| Audit story | "Trust our gate code" | "Diff the import list" |
Runtime Topology
The WIT contract is identical on both backends — that is the entire point.
┌────────────────────── Host ──────────────────────┐
│ @oxprotocol/host-runtime │
│ ┌──────────────────┬────────────────────────┐ │
│ │ NODE / DESKTOP │ BROWSER / WEBVIEW │ │
│ │ wasmtime or │ native WebAssembly │ │
│ │ jco shim │ + jco-transpiled shim │ │
│ └────────┬─────────┴──────────┬─────────────┘ │
│ │ WIT host-funcs │ │
│ ▼ (broker) ▼ │
│ ┌────────────────────────────────────────────┐ │
│ │ Extension component (.wasm) │ │
│ │ imports: oxp:host/ui, oxp:host/fs, … │ │
│ │ exports: lifecycle, ui-handler, … │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘Bundle Kinds
Every OXP bundle has a kind that drives security policy:
| Kind | Description | Code Allowed |
|---|---|---|
ui-v1 | Declarative JSON tree only. No executable code. | ❌ No JS/TS/Wasm |
component-v1 | Ships a WASI component. Must declare a WIT pin. | ✅ Wasm only |
hybrid-v1 | Both a UI tree and a Wasm component. | ✅ Wasm only |
Existing bundles published before the kind field default to ui-v1 on read — backward compatible.
WIT Contracts
The packages/wit/ package is the most important package in the repo. It contains the WIT (WebAssembly Interface Types) contracts that define the interface between host and extension:
- **
oxp:host@0.1.0** — capabilities the host provides:log,storage,ui,fs,net,secrets,commands - **
oxp:extension@0.1.0** — interfaces extensions export:lifecycle,ui-handler,command-handler
The install prompt reads the component's import list at install time. The binary cannot import what the manifest did not declare, because the registry validates manifest.permissions ⊇ component.imports on upload.
The Capability Broker
The CapabilityBroker in packages/host-runtime/src/broker.ts mediates every host call from a Wasm extension. It:
- Checks the manifest's declared permissions
- Validates the call against the granted scope
- Routes to the actual host implementation
- Enforces per-call time limits (
runWithTimeout) - Logs every call for audit
This is the trust boundary. The SDK, the webview, the extension code — none of them are trusted. Only the broker decides what gets through.
The Registry
The registry (apps/web/) is a Next.js application backed by Prisma + Postgres (Neon). It provides:
- REST API (
/api/v1/): resolve, manifest, signature, bundle download, versions, publisher keys, tokens - Web UI: browse, search, detail pages, sign-in, dashboard
- Publish pipeline: manifest validation, bundle policy enforcement, signature verification, WIT pin check, TOFU key pinning
- Auth: NextAuth v5 with credentials + JWT strategy, scoped API tokens
The registry is designed to be replaced — any OCI-compatible registry works for bundle distribution. The oxp.sh registry adds publisher identity and the web UI on top.