Ship an automation,
not an app.
A plugin adds your own commands to the ilml CLI. Publish one package and it runs in someone else’s terminal, under their own account, writing into their graph — so the login screen, the settings UI and the database are all things you never build.
A manifest and a script.
A plugin is an npm-style package: a manifest that names your commands and the settings they need, plus the code that runs them. Install it once and it’s available in every login scope on that machine.
{
"name": "acme",
"version": "1.0.0",
"commands": {
"sync": { "run": "node dist/sync.mjs" },
"report": { "run": "node dist/report.mjs" }
},
"config": { "sections": [
{ "title": "Acme account", "fields": [
{ "key": "ACME_TOKEN", "label": "API token",
"type": "secret", "required": true } ] },
{ "title": "iLiveMyLife", "fields": [
{ "key": "REPORT_NODE", "label": "Where to post",
"type": "nodeId", "required": true,
"hint": "Reports land in this node's chat" } ] },
{ "title": "Limits", "fields": [
{ "key": "PER_RUN", "label": "Items per run",
"type": "number", "default": 50 } ] }
] }
}import { getPluginConfig, getCachedUser,
createGraphClient } from '@ilivemylife/graph-sdk'
// No arguments: the SDK walks up to your manifest,
// and THROWS if a required field is still blank —
// naming the keys and the command that sets them.
const cfg = await getPluginConfig()
// who is running it — no network call
const user = getCachedUser()
// the SDK, as that user
const graph = createGraphClient({
token: process.env.ILML_TOKEN })
await graph.addItem(cfg.REPORT_NODE, {
title: `Acme sync — ${user.displayName}` })
graph.destroy()That’s the contract in full: the CLI finds your manifest, collects what’s missing, injects the token, and runs the command the user typed.
Three quarters of the product, already there.
The reason a plugin is a weekend and an app is a quarter: sign-in, settings and storage arrive with the runtime.
The user is already signed in
The CLI hands your process ILML_TOKEN, so the whole SDK works as that person — their nodes, their permissions, nothing of yours to store.getCachedUser() tells you who they are without a network call.
Settings you didn’t have to design
Declare them in your manifest, grouped into sections, each field typed —secret, number, url, path, evennodeId for “pick a node in your graph”. The CLI collects what’s missing, stores it and masks the secrets; your command refuses to start until it’s complete.
A database with an AI in it
Write results straight into the user’s graph — and ask askLifebot about their own data mid-run, with a node as the context. No schema to design, no prompt to engineer, no storage to host.
import { LifebotTimeoutError } from '@ilivemylife/graph-sdk'
// A form wants something you don't know. Lifebot does —
// it reads the node the user pointed you at, so the
// answer comes from THEIR data, on THEIR token.
try {
const reply = await graph.askLifebot(
cfg.REPORT_NODE,
`Form field "${label}" — reply with ONLY the value.`,
{ timeout: 120000 }) // max 300000
await form.fill(reply.content) // and carry on
} catch (e) {
if (e instanceof LifebotTimeoutError) retryLater()
}
// askLifebot forces a reply and waits for it — no
// "@Lifebot" prefix, no polling, no prompt plumbing.
// This is how the LinkedIn plugin answers job forms
// in the user's own voice.Their assistant finds your plugin.
The MCP server reports installed plugins to whatever AI the user talks to — name, version, commands, and which settings are still blank (secrets masked). So the assistant can suggest your command at the right moment, and run it in the terminal.
graph_plugins → acme 1.0.0 · sync, report
graph_plugin_config → ACME_TOKEN ✓ · REPORT_NODE (unset)
$ ilml plugin config acme set REPORT_NODE <node>
$ ilml acme reportPublish it your way.
A plugin is a tarball. Put it on npm and everyone types a short name — or host it yourself and hand the URL only to the people you choose.
On npm — short name, real updates
Publish as ilml-plugin-<name> and the user just types ilml plugin install <name>. npm sources are version-aware: ilml plugin update compares the installed version against the latest and downloads only when there’s something new.
Or from your own URL — private, or paid
ilml plugin install acme https://you.example/acme-1.0.tgz installs from anywhere you can host a file. Nothing goes through us: who gets the link, and on what terms, is between you and them.
While you build it — straight off disk
Point the installer at a local tarball with file:///…, or run your script directly and let the SDK read a .env instead of the stored settings. Same code path, no publishing round-trip.
ilml plugin install acme # npm:ilml-plugin-acme
ilml plugin install acme npm:ilml-plugin-acme@1.2.0
ilml plugin install acme https://you.example/acme.tgz
ilml plugin list # what's installed
ilml plugin config acme show # secrets masked
ilml plugin update acme # newer? then download
ilml plugin remove acmeAnything the terminal can reach.
Your plugin is ordinary Node running on the user’s machine — with their graph, their AI and their permissions already wired in.
Bring a closed service home
Pull a service the user is locked out of programmatically — their orders, their bookings, their inbox — into nodes they own, and keep it in sync. That’s exactly what the LinkedIn plugin does.
Turn a night’s work into one node
Crunch whatever you’re good at — logs, prices, a codebase — and post the result as a node with its own chat, where the team can argue with it and Lifebot can answer follow-ups.
A domain expert that runs on a schedule
Your command wakes up, reads the graph for context, asks Lifebot to judge what changed, and writes back a decision — under the user's account, so the history shows who did what.
Push the graph where the work happens
Read a branch and drive something outside — a printer, a stock list, a deployment. Nodes in, real-world action out.
A plugin runs where the user runs it. For automation that fires on its own, inside the graph, a node can hold code and run it whenever anything in its branch changes — that’s contracts, and the two work together: a contract reacts, your plugin does the heavy lifting.
Read one that’s real.
ilml-plugin-linkedin is the worked example: it keeps a local mirror of someone’s LinkedIn, drafts replies they approve before sending, and reports into their graph — all through the same manifest, config schema and token you’d use.
One package. Everyone’s graph.
The authoring example ships inside the SDK — examples/plugin-author.mjs, right there after you install it.