Getting Started
This guide walks through adding xript to an application from scratch. By the end you’ll have a working sandboxed expression evaluator that users can safely extend.
Before You Start
Section titled “Before You Start”-
Node.js 20 or newer (or a browser project; the universal runtime runs anywhere JavaScript does). Check with
node --version; an error instead of a version number means install Node first. -
A JavaScript project to add xript to. No project yet?
mkdir my-app && cd my-app && npm init -ygives you one. -
The CLI, for the tooling steps. The runtime below is a library you
npm install; thexriptcommand (validate, typegen, init, and friends) is a separate global install:Terminal window npm install -g @xriptjs/clixript --versionIf
xript --versionprints a version, you’re set. If it printscommand not found, the CLI isn’t installed yet. Anywhere this site saysxript <something>,npx xript <something>works without the global install.
Install the Runtime
Section titled “Install the Runtime”The universal runtime uses QuickJS compiled to WebAssembly: it works in browsers, Node.js, Deno, and more. From your project folder:
npm install @xriptjs/runtimeWrite a Manifest
Section titled “Write a Manifest”Create a manifest.json describing what your application exposes to scripts. Start with a few safe bindings:
{ "$schema": "https://xript.dev/schema/manifest/v0.8.json", "xript": "0.8", "name": "my-app", "version": "1.0.0", "bindings": { "greet": { "description": "Returns a greeting for the given name.", "params": [{ "name": "name", "type": "string" }], "returns": "string" }, "add": { "description": "Adds two numbers.", "params": [ { "name": "a", "type": "number" }, { "name": "b", "type": "number" } ], "returns": "number" } }}Only xript and name are required. Everything else is optional and layered on as needed.
Provide Host Bindings
Section titled “Provide Host Bindings”Each binding in the manifest needs a host-side implementation. These are regular JavaScript functions:
const hostBindings = { greet: (name) => `Hello, ${name}!`, add: (a, b) => a + b,};Create a Runtime
Section titled “Create a Runtime”Initialize the WASM sandbox, then wire the manifest and bindings together:
import { initXript } from "@xriptjs/runtime";
const xript = await initXript();const runtime = xript.createRuntime(manifest, { hostBindings, console: { log: console.log, warn: console.warn, error: console.error },});initXript() loads the QuickJS WASM module once. After that, createRuntime() is synchronous: create as many runtimes as you need.
Execute Scripts
Section titled “Execute Scripts”Now you can safely evaluate user expressions:
runtime.execute('greet("World")'); // { value: "Hello, World!", duration_ms: ... }runtime.execute('add(2, 3)'); // { value: 5, duration_ms: ... }runtime.execute('add(1, add(2, 3))'); // { value: 6, duration_ms: ... }Scripts can compose your bindings with standard JavaScript:
runtime.execute('[1, 2, 3].map(n => add(n, 10))'); // { value: [11, 12, 13], ... }Clean Up
Section titled “Clean Up”When you’re done with a runtime, free its WASM resources:
runtime.dispose();See the Sandbox in Action
Section titled “See the Sandbox in Action”Anything not declared in the manifest is inaccessible:
runtime.execute('process.exit(1)'); // Error: process is not definedruntime.execute('require("fs")'); // Error: require is not definedruntime.execute('eval("1 + 1")'); // Error: eval() is not permittedruntime.execute('fetch("https://x")'); // Error: fetch is not definedUser scripts cannot escape the boundaries you define. That’s the whole point.
Next Steps
Section titled “Next Steps”- Scaffold a new project with
npx xript init. See Init CLI. - Add capabilities to gate sensitive operations. See the Capabilities spec.
- Add namespaces to organize related bindings. See the Manifest spec.
- Expose extension points by declaring typed slots that mods fill, and broadcast named events the host emits. Bindings are what mods call, slots are what they fill, events are what the host emits. See the Manifest and Mod Manifest specs.
- Inherit from a base manifest with
extends; fill a base’s abstract holes, refine its concrete pieces. See the Manifest spec. - Measure moddability with
xript score, which rates how much extension surface your host exposes. See Extensibility Score. - Drive the toolchain from an agent by running the CLI as an MCP server with
xript mcp. See MCP Server. - Read the doctrine behind xript’s open-by-default posture with
xript guide. See “More extensible, not less”. - Generate TypeScript definitions from your manifest with
xript typegen. See Type Generator. - Generate documentation from your manifest with
xript docgen. See Doc Generator. - Use the Node.js runtime for file-based workflows and native V8 performance. See Node.js Runtime.
- Explore the runtime API in depth. See JS/WASM Runtime.
- Run the full example in the repository:
examples/expression-evaluator/.