Build & self-host · 6 min read
Building extensions (plugins)
Add capabilities - notes, scribe, new connectors, Otter tools - without forking.
Some needs are too specific to live in the core - a note-taker wired to your wiki, a scribe that kicks off transcription, a connector to an internal tool. DayOtter's plugin system lets you add those as small, separate packages that work in tandem with the product, so you never fork the core to cover an edge case.
A plugin is a package that default-exports `definePlugin({...})` and contributes capabilities. It's built against `@dayotter/plugin-sdk`, which has no dependency on DayOtter's internals - the host supplies everything at runtime.
What a plugin can contribute
- Otter tools - new AI capabilities. `read` tools answer questions inline; `action` tools are confirm-first (Otter proposes a card, the human approves before it runs).
- Booking lifecycle hooks - react to a meeting being created, rescheduled, or cancelled (seed a note, start a scribe, sync to an external system).
- Connectors - reach external services through a scoped, SSRF-guarded HTTP client and store credentials in encrypted per-plugin storage.
A minimal plugin
Every runtime function receives a context with scoped `storage` (JSON + encrypted secrets), a safe `http` client, a namespaced `logger`, and `config`. Here's a plugin that adds one confirm-first Otter tool:
- id / name - a stable kebab-case id (namespaces your tools and storage) and a display name.
- tools[] - each has a name, JSON-schema input, a kind (read | action), and an async `run(ctx, input)`.
- bookingHooks[] - each declares which events it runs on and an async `handle(ctx, event, booking)`.
Tip
Start from the reference plugins in packages/plugins/ - `notes` (an Otter tool + a booking hook + storage) and `webhook-relay` (a connector that forwards booking events to a URL you control). Copy one and edit.
Enable a plugin
- Add the plugin package to the build and import it in the host's enabled list (packages/plugin-host/src/enabled.ts).
- Set DAYOTTER_PLUGINS to a comma-separated list of the plugin ids you want on, e.g. DAYOTTER_PLUGINS=notes,webhook-relay.
- Restart. Plugins are OFF by default - the core behaves exactly as before until you opt in.
Confirm-first and safe by design
- Action tools never run on their own - they flow through the same propose→approve card as core tools; set `danger` for a second confirmation.
- Storage is scoped to (your plugin, the user) - a plugin can't read another's data. Secrets are encrypted at rest.
- `ctx.http` refuses non-public hosts and won't follow redirects, so a plugin can't be tricked into hitting internal infrastructure.
Heads up
Plugins run in-process with real access - only enable ones you trust. On the DayOtter cloud, plugins are a curated set; self-hosters choose exactly what to install and enable.
Related guides
Developer: API, webhooks & embed
Keys and REST endpoints, signed booking events, and the embeddable widget.
Ask Otter (the AI assistant)
Chat or talk to your calendar - it drafts every change and never acts without a tap.
Self-hosting DayOtter
Run the whole platform on your own infrastructure, with every feature unlocked.
Ready to try it? Get started free, or browse all guides.