nimi-mods/ is the example and authoring workspace for Nimi runtime mods.
If you are a third-party developer and want to build your first mod, start here.
If you are working inside the Nimi monorepo and need the deeper maintenance rules, read ONBOARDING.md after this file.
If you are releasing an official Nimi-maintained mod from this workspace, read RELEASE.md.
A Nimi mod is a small package that Desktop can load at runtime.
Typical things a mod can do:
- add a page to the app
- add a sidebar entry
- call AI capabilities through the mod SDK
- store mod-local state
- register hook-based data or UI integrations
Important constraint:
- a mod talks to Nimi through the public mod SDK
- a mod does not import Desktop private code
Before you start, make sure you have:
- Node.js
24+ pnpm 10+- access to the Nimi monorepo
- Nimi Desktop available locally
Install dependencies once:
cd nimi-mods
pnpm installThese directories are already working examples:
runtime/test-ai: small diagnostic UI mod, easiest starting point for a page-style modruntime/local-chat: large production-style runtime modruntime/kismet: immersive full-screen mod pageruntime/buddy: animated character mod with more complex runtime cleanup
Loadable runtime mods:
audio-bookbuddydaily-outfitkismetknowledge-baselocal-chatmint-youtest-aitextplayvideoplayworld-studio
Non-loadable support package:
narrative-engine
Not part of the runtime workspace contract:
cashbookmeeting-scribere-life
The simplest path is:
- Pick an existing mod, for example
test-ai - Build it
- Add the mod folder to Desktop
- Reload it after changes
Build:
cd nimi-mods/runtime/test-ai
pnpm run buildValidate:
pnpm run doctorLoad in Desktop:
- Open Desktop
- Go to
Settings > Mod Developer - Add either:
nimi-mods/runtime, or- one specific mod directory such as
nimi-mods/runtime/test-ai
- Reload the source after every rebuild
A basic runtime mod should look like this:
my-mod/
├── index.ts
├── mod.manifest.yaml
├── package.json
├── tsconfig.json
├── tsconfig.build.json
├── src/
│ ├── index.ts
│ ├── runtime-mod.ts
│ └── my-page.tsx
└── spec/
Your package.json should expose:
{
"scripts": {
"build": "nimi-mod build",
"dev": "nimi-mod dev",
"doctor": "nimi-mod doctor",
"pack": "nimi-mod pack"
}
}Your mod.manifest.yaml should have at least:
id: world.nimi.my-mod
name: My Mod
version: 0.1.0
kind: capability-mod
iconAsset: ./assets/icon.svg
entry: ./dist/mods/my-mod/index.js
styles:
- ./dist/mods/my-mod/index.css
capabilities:
- ui.register.ui-extension.app.sidebar.mods
- ui.register.ui-extension.app.content.routesNotes:
entrymust point to the built JS fileiconAsset, if declared, must point to a package-local.svgfile such as./assets/icon.svg- UI mods must also declare
styles - capabilities must be explicit; do not use wildcard grants
Example src/runtime-mod.ts:
import { createHookClient, type RuntimeModRegistration } from '@nimiplatform/sdk/mod';
const MOD_ID = 'world.nimi.my-mod';
export function createRuntimeMod(): RuntimeModRegistration {
return {
modId: MOD_ID,
capabilities: [
'ui.register.ui-extension.app.sidebar.mods',
'ui.register.ui-extension.app.content.routes',
],
setup: async ({ sdkRuntimeContext }) => {
const hookClient = createHookClient(MOD_ID, sdkRuntimeContext);
await hookClient.ui.register({
slot: 'ui-extension.app.sidebar.mods',
priority: 100,
extension: {
type: 'nav-item',
tabId: 'mod:my-mod',
label: 'My Mod',
icon: 'puzzle',
strategy: 'append',
},
});
await hookClient.ui.register({
slot: 'ui-extension.app.content.routes',
priority: 100,
extension: {
type: 'tab-page',
tabId: 'mod:my-mod',
strategy: 'append',
component: async () => null,
},
});
},
teardown: async () => {},
};
}If your mod renders UI, the page root must include a mod root marker:
export function MyPage() {
return (
<div data-nimi-mod-root="my-mod" className="h-full min-h-0">
Hello from My Mod
</div>
);
}Why this matters:
- Desktop no longer supplies the old implicit page styling
- your mod's built CSS uses this marker to scope its baseline styles
If you use portal UI like dialogs or tooltips, the portal content also needs a mod portal marker:
<div data-nimi-mod-portal="my-mod">...</div>Use these in mod code:
@nimiplatform/sdk/mod@nimiplatform/sdk/mod/shell@nimiplatform/sdk/mod/lifecycle
Avoid these in runtime mod source:
@nimiplatform/sdk@nimiplatform/sdk/runtime@tauri-apps/*- Desktop source imports
@nimiplatform/sdk/mod/ui@nimiplatform/sdk/mod/host../../sdk/src/*
Inside one mod:
pnpm run dev
pnpm run build
pnpm run doctor
pnpm run packAt the nimi-mods/ root:
pnpm run check
pnpm run check:spec
pnpm run typecheck
pnpm run build
pnpm run verifyWhat they mean:
check: package/manifest/style contract checkscheck:spec: spec consistency checkstypecheck: TypeScript checks across the workspacebuild: builds all runtime modsverify: full tests plus build checks
Check:
- did you add the correct folder in
Settings > Mod Developer? - did
pnpm run buildsucceed? - does
mod.manifest.yamlpoint to./dist/mods/<mod>/index.js?
Check:
- does the manifest declare
styles:? - does the page root have
data-nimi-mod-root="<mod-name>"? - did you reload the dev source after rebuild?
Check:
- does the portal content include
data-nimi-mod-portal="<mod-name>"?
Check:
- did you clean long-lived state in
teardown?
Check:
- remove old
tsconfigpath aliases to../../sdk/src - depend on
@nimiplatform/sdkthroughpackage.json
If this is your first mod:
- Read
test-ai - Copy its basic package/manifest/runtime structure
- Add one simple page
- Make
pnpm run doctorpass - Load it in Desktop
- For internal workspace and maintenance rules:
ONBOARDING.md - For official first-party mod publishing:
RELEASE.md - For strict workspace conventions:
AGENTS.md - For a specific mod contract:
runtime/<mod>/spec/AGENTS.md