An in-house app
In-house apps connect with a key the person pastes in Integrations. Their actions are plain functions.1
Write the app
Add
backend/src/integrations/own/<app>.ts, or a folder own/<app>/ with an index.ts. Export an OwnApp (type in own/index.ts): app, name, logo, keyField (the paste box), check(key) that throws if the key fails, and actions. Each action has a description, a zod input, run(input, key), and readOnly: true if it only looks things up. Others ask the person first.2
List it
Add it to
APPS in own/index.ts, and to CATALOG in integrations/catalog.ts with own("<app>", "<Name>", "<category>", "<what it does>").3
Test it
Put
<app>.test.ts next to it, like the others.<app>.<action>. own/indiamart.ts is a small hand-written example.
From an OpenAPI spec
For an API with a spec, writebackend/scripts/openapi/<app>.ts (the spec URL, the output file, names, and which calls only read or return secrets), then generate the actions:
own/<app>/actions.json, which own/openapi.ts runs. See own/neon/ for a complete one.
COVERAGE.md
Each in-house app folder has aCOVERAGE.md: where its actions came from, what was left out and why, how it signs in, and its actions by group, with * on those that ask first.
A Composio app
Add acomposio("<toolkit>", "<Name>", "<category>", "<what it does>") line to catalog.ts, then set up its auth config in the Composio dashboard. It shows up only when both are there.
A polled trigger
Emplio checks an app on a timer and fires only on new items. Writebackend/src/integrations/polls/<app>.ts (copy todoist.ts), exporting triggers by short name. Each has a description, a zod config, its output, every and min minutes, and poll(config, run) returning the current recent items, each with an id that never changes. Add it to APPS in polls/index.ts.
A channel
A channel only moves messages. Writebackend/src/channels/<name>.ts like telegram.ts: a Channel with send, approval and closeApproval, and an Out for showing replies. Add it to CHANNELS in channels/index.ts, add its name to the channel enums in backend/src/db/schema.ts with a migration (bun run db:generate), and start it from backend/src/index.ts the way telegram.start() is.
Open an issue first for a new app or channel, so we can agree on the approach. See Contributing.
Project map
Where everything lives.
Extend Emplio
Skills, agents, automations and MCP.

