Iris Apps

Build plugins for Iris

A plugin teaches Iris something new: a command she can run, a slash command in the chat, a window or a whole screen. Moneybird invoices, the weather, a WhatsApp digest, your own tools. Once it is in the marketplace, every Iris can install it by being asked.

There are two ways to build one:

  • Ask your Iris. Tell her what you want ("build a plugin that lists my open Moneybird invoices") and she writes it, tests it and can publish it for you. She follows this same guide.
  • Write it yourself. A plugin is a plain folder with a manifest and a few scripts. No SDK, no build step.

If you are a language model: this page is also at /docs.md as plain Markdown, and /llms.txt points to everything you need.

What a plugin is

One flat folder in ~/plugins/<name>/ inside an Iris home: a plugin.json plus the files it names. No subfolders. Your code runs in that Iris's own private workspace (Linux, with Python 3, Node and the usual command line tools), never on anyone else's.

~/plugins/moneybird/
  plugin.json
  moneybird.py        the command `moneybird`
  moneybird.jsx       a window with the open invoices
  icon.svg            its icon in the marketplace
  README.md           its page in the marketplace

plugin.json

{
  "name": "moneybird",
  "version": "1.0.0",
  "author": "Woodst",
  "description": "Open invoices, payments and contacts from Moneybird.",
  "permissions": ["internet", "secrets"],
  "commands": { "moneybird": "moneybird.py" },
  "slash": { "moneybird": "open invoices" },
  "window": "moneybird.jsx",
  "category": "finance",
  "icon": "icon.svg"
}
FieldRequiredMeaning
nameyesThe name, equal to the folder name: lowercase letters, digits and -, at most 40 characters.
versionyesThree numbers, like 1.0.0. Every published version is final; change anything and raise it.
authoryesWho made it, shown in the marketplace.
descriptionyesOne sentence: what it does for the person, not how it is built.
permissionsyesThe permissions it needs, see below. An empty list is fine and trusted most.
commandsnoCommand name to file in the folder. The file starts with a #! line.
slashnoCommands that also appear in the / menu of the chat, with a short explanation.
windownoA .jsx window shown over the conversation.
screennoA .jsx screen that rearranges the whole page.
categorynoOne of communication, finance, productivity, home, media, knowledge, developer, other.
iconnoA square .svg or .png in the folder. Without one the marketplace draws a letter.
screenshotsnoUp to 6 .png, .jpg or .webp files in the folder, shown on its marketplace page in this order.

Screenshots show the plugin at work: its window, its screen, or a conversation where Iris uses it. Use made-up demo content, never someone's real messages or data. A phone shot (1170 x 2532) or a window shot (1280 x 800) both work; keep the whole folder under 6 MB.

A README.md in the folder becomes the plugin's page in the marketplace: what it does, what the person needs (an account, an API key), and a few example sentences to say to Iris.

Permissions

Say honestly what the plugin needs. People see this list before they install, and a new version that asks for more is never installed without their yes.

PermissionMeans
internetFetches something from the internet.
filesReads or writes files outside its own folder.
secretsUses a key from the owner's vault (an API token, a login).
phoneSends something to the owner's phone.
voiceSpeaks or listens.
messagesReads and sends messages in the owner's name (WhatsApp, mail, Telegram).

Commands

A command is any executable file. What it prints is what Iris reads back, so keep output short and readable: it is an answer, not a log.

#!/usr/bin/env python3
import sys
print("3 open invoices, 1.240 euro in total. The oldest is 34 days overdue.")

Commands under slash show up in the chat's / menu once the plugin is on. Choosing /moneybird overdue runs moneybird overdue and shows what it prints. Words after the command arrive as arguments, never through a shell.

A command never replaces an existing one: if web or klus already exists, pick another name.

Keys and logins

A plugin never sees a secret. The owner keeps tokens in the vault; your command asks the vault to make the call and gets back only the response. {g} is replaced by the secret inside the vault.

vault call moneybird GET https://moneybird.com/api/v2/administrations.json --header "Authorization: Bearer {g}"

For HTTP Basic auth use {g:base64}. Missing key? Tell the owner in one sentence which key to add and where to get it: vault ask moneybird --domain moneybird.com "your Moneybird API token" opens a safe window for them to paste it. Such a plugin needs the secrets permission.

Windows and screens

A window is a picture over the conversation; a screen rearranges the whole page. Both are one .jsx file with a default export, built from the same kit Iris uses for her own screens. plugin open <name> shows it.

export default () => (
  <Card label="Moneybird" title="3 open invoices" icon="euro">
    <Row left="Bakkerij Jansen" right="480 euro" />
    <Row left="Studio Noord" right="760 euro" />
    <Buttons>
      <Button primary say="Remind Studio Noord about their invoice">Send a reminder</Button>
    </Buttons>
  </Card>
);
ComponentProps
Screentitle, subtitle, icon: the frame of a whole screen
Cardlabel, title, icon
Rowleft, right, icon
Stats, Statvalue, label, icon: numbers side by side
Buttons, Buttonprimary, onClick, or say: the sentence Iris receives when it is tapped
Textdim
Listitems
Iconname, size

say("...") sends a sentence to Iris from your own code, as if the owner said it.

Try it out

Inside an Iris home:

plugin check moneybird     # is plugin.json right? (changes nothing)
plugin enable moneybird    # put its commands on the path
moneybird                  # run it
plugin open moneybird      # show its window or screen
plugin disable moneybird   # and off again

Publish

plugin publish moneybird

This sends the version to the marketplace. It waits for a review first; once approved it is listed here and any Iris can install it. The first home that publishes a name owns it: later versions of moneybird can only come from that same home.

Before you publish:

  • No keys, passwords, names or personal data of your owner in the files. Other people will run this.
  • The permissions match what the code does.
  • One flat folder, at most 6 MB in total.
  • The version is higher than the one already listed.

A review looks at exactly these points and at what the code does. A rejected version can be fixed and submitted again with a higher version number.

Updates

Every Iris checks the marketplace once an hour. A new version that asks for no more permissions than the one installed goes in by itself. One that asks for more waits: Iris asks her owner, and only on a yes does she run plugin update <name>. Folders you wrote yourself are never replaced; only plugins installed from the marketplace are.

plugin update             # everything that can update without asking
plugin update moneybird   # this one, also when it asks for more (after a yes)

Install

In any Iris, say "install moneybird", or run:

plugin browse                # what is in the marketplace
plugin install moneybird     # the newest version, enabled
plugin install moneybird@1.0.0

Price

All plugins are free for now. Paid plugins, with the money going to their maker, come later.

API

Read-only and public. Every published version is immutable and carries one SHA-256 hash over its files.

RequestReturns
GET /api/pluginsAll plugins, newest version first: the manifest plus versions, hash, published.
GET /api/plugins/<name>The newest package: manifest, files (file name to base64), hash, published.
GET /api/plugins/<name>/<version>That exact version.