Skip to content

Building a plugin

A third-party plugin is TypeScript plus a declarative yttri-plugin.json manifest. Code talks to Yttri only through the typed YttriHost.

Terminal
# Scaffold from the template
npx @yttri/plugin-cli create my-plugin
cd my-plugin
npm install
# Edit yttri-plugin.json and src/index.ts, then:
npm run build
npx yttri-plugin validate
npx yttri-plugin pack

The build creates my-plugin-0.1.0.yttri-plugin. Install it through Settings → Plugins. For iterations, use the Developer folder: after npm run build, click Update — files are replaced while settings and state survive.

src/index.ts
import { definePlugin, type YttriHost } from '@yttri/plugin-api';
export default definePlugin({
async activate(host: YttriHost) {
host.log.info('activated');
},
tools: {
// The key matches capabilities.tools[].name in the manifest.
async acme_ping(host: YttriHost) {
const token = await host.secrets.get('api_token');
const res = await host.network.fetch({
url: 'https://api.acme.com/ping',
headers: token ? { authorization: `Bearer ${token}` } : {},
});
return { ok: res.ok, status: res.status };
},
},
jobs: {
async sync(host: YttriHost) {
// A background job declared in capabilities.jobs.
},
},
});
  • host.invoke({ capability, operation, payload }) — calls into data domains: notes, tasks, calendar, contacts, projects, and search (read and create), documents, mail, and meetings (read). Write operations require a write grant.
  • host.secrets.{get,set,delete,list} — secrets in the plugin’s isolated namespace; values are encrypted.
  • host.network.fetch(req) — HTTP only to hosts declared in the manifest.
  • host.settings.getAll() — plugin settings; Yttri generates the form from the schema.
  • host.log.{info,warn,error} — a sanitized log.

Tools from an enabled plugin join the AI agent’s registry as plugin_<name>. By default, every mutating call asks for user confirmation. A trusted plugin can be allowed to run without prompts through an explicit toggle.