How-to guides
Building a Custom Capability Package
A developer's guide to OOMU Mods.
This guide is a practical recipe for packaging a custom capability into a .oomu file that any OOMU user can install. It assumes you're comfortable with the command line and JSON.
For the formal, field-by-field standard, see the Capability Package Specification. This page is the hands-on walkthrough.
What you're building
A .oomu package is a ZIP archive with a known layout. At minimum it contains:
manifest.json; the metadata and behaviour declaration that OOMU reads.- An entrypoint file; the compiled engine that carries your capability's logic (conventionally
engine.wasm).
You may also include supporting files such as a README.md or LICENSE; OOMU carries them with the package.
OOMU validates the archive on install, unpacks it into the user's private workspace, and records what it declares. A Mod influences a conversation through two mechanisms it declares in its manifest:
- A default system prompt that shapes how a bound assistant behaves, and/or
- Hooks that let the Mod participate at defined points (such as intercepting a prompt before it's processed).
When a Mod is active and bound, OOMU injects its instructions into the turn as an active runtime contract; the assistant treats the Mod's declared behaviour as something to *perform*, not merely describe, while preserving safety and the agent's persona.
Step 1; Create your project folder
Lay out a working directory:
my-mod/
├── manifest.json
├── engine.wasm
├── README.md (optional)
└── LICENSE (optional)
Keep it lean. OOMU enforces limits on packages; an archive may contain at most 256 entries and must stay under 200 MB uncompressed, so include only what your capability needs.
Step 2; Write your manifest.json
The manifest is the heart of your Mod. Here is a complete, working example that declares access to a folder and a web host:
{
"$schema": "https://oomu.ai/schemas/mod-manifest-v1.json",
"id": "com.example.mods.house-style",
"name": "House Style",
"version": "1.0.0",
"author": "Example Corp",
"description": "Enforces our company tone and formatting on every reply.",
"category": "Writing",
"min_host_version": "0.1.0",
"entrypoint": "engine.wasm",
"permissions": {
"allowed_paths": ["/Users/shared/house-style"],
"allowed_hosts": ["style.example.com"]
},
"endpoints": [],
"hooks": {
"shield_gate": {
"on_prompt": "on_prompt_intercept"
}
},
"default_system_prompt": "Always reply in clear, plain English. Use short paragraphs, never marketing language, and end with a one-line summary."
}
Key fields:
| Field | Purpose |
|---|---|
id | A globally unique, reverse-DNS identifier. This is how OOMU tracks and de-duplicates your Mod across versions. |
name, description | What the user sees in the Mods list and on the install screen. |
version | Semantic version. A new version with the same id upgrades the installed Mod in place. |
author | Shown to the user so they know who made it. |
min_host_version | The minimum OOMU version your Mod requires. |
entrypoint | The file inside the archive that holds your engine. |
permissions | A structured object declaring the folders and hosts your Mod may reach. See Step 3. |
hooks | Where your Mod participates. shield_gate.on_prompt names the function that runs when a prompt is intercepted. |
default_system_prompt | Instructions applied to any assistant the Mod is bound to. |
category, endpoints | Optional display category and named endpoints. |
The manifest is strict about permissions. The
permissionsobject rejects unknown keys; onlyallowed_pathsandallowed_hostsare accepted. A typo won't be silently ignored; it will fail validation. Every other top-level field tolerates unknown keys for forward compatibility.
Step 3; Declare only the access you need
Permissions are the contract between your Mod and the user. OOMU enforces them at runtime; your engine cannot reach a folder or host it didn't declare.
"permissions": {
"allowed_paths": ["/Users/shared/house-style"],
"allowed_hosts": ["style.example.com", "https://api.example.com"]
}
allowed_paths; a list of absolute directory prefixes. Your Mod may read within these paths and nowhere else. Relative paths are rejected; each entry is resolved to its real location and access is granted only if the target sits inside a declared prefix.allowed_hosts; a list of hostnames or absolute URL origins (e.g.api.example.comorhttps://api.example.com). Requests must usehttp/https, and the requested host must match a declared entry. Entries with paths, queries, or fragments are rejected; declare origins, not URLs.
If your Mod only shapes how the assistant responds and never touches files or the network, declare no permissions at all:
"permissions": {}
Declare the minimum your capability genuinely needs; every path and host is shown to the user on the install screen as something they're agreeing to, and OOMU blocks anything you didn't declare.
Step 4; Build your engine
Compile your capability's logic into the entrypoint file you named in the manifest (e.g. engine.wasm). Your engine is the unit that OOMU stores alongside the manifest as the carrier of your Mod's behaviour.
Design for the boundary. Your capability runs inside OOMU's safety model, not with free access to the user's machine. File and network access are mediated by OOMU against your declared
allowed_pathsandallowed_hosts. Build assuming least privilege. See Privacy & Sandboxing for the boundaries you're designing against.
Step 5; (Optional) Ship reference material
If your capability is built around a body of reference material; a style guide, a product catalogue, a policy set; package it as compact, structured data your engine can read at runtime. Keep it within the archive's entry and size limits, and prefer a single lightweight file your engine queries over many loose documents.
Step 6; Package it as a .oomu archive
A .oomu file is a plain ZIP archive with a .oomu extension. From inside your project folder:
# Zip the contents (not the parent folder) so manifest.json sits at the archive root
cd my-mod
zip -r ../house-style.oomu manifest.json engine.wasm README.md LICENSE
The important rule: manifest.json must be at the root of the archive, not nested inside a subfolder. OOMU reads the manifest from the archive root on install.
Step 7; Test the install
- Open OOMU → Mods.
- Install
house-style.oomu(choose the file or drag it in). - Confirm your name, description, and the declared folders/hosts appear as you intended on the install screen.
- Toggle the Mod Active, bind it to a test assistant, and send a message to see it take effect.
If OOMU rejects the package, the most common causes are: the file isn't a valid ZIP, manifest.json isn't at the archive root, the manifest is missing a required field, an allowed_paths entry isn't absolute, an allowed_hosts entry includes a path/query, the permissions object contains an unknown key, or the archive exceeds the entry/size limits.
Checklist before you distribute
idis unique and reverse-DNS.versionis bumped from any previous release.permissions.allowed_pathsare absolute;allowed_hostsare hostnames/origins only.permissionscontains no keys other thanallowed_paths/allowed_hosts.- You declared the *minimum* access you actually use.
descriptionis honest and clear; it's what users decide on.manifest.jsonis at the archive root.- The package installs cleanly on a fresh workspace.
Related
- Capability Package Specification: the formal manifest and archive standard.
- Adding Custom Capabilities: the user's side of installing your Mod.