How integrations are structured
An integration is a package that exports a validated definition. Everything you declare upfront shapes how Ekanos treats your integration.One call, complete declaration
Every integration starts withdefineIntegration():
defineIntegration() throws a remediation message immediately.
The main surfaces
Widgets
Dashboard cards that render in the grid. They readclientReadable storage with fetchIntegrationStorage(), call APIs from the browser with useIntegrationFetch(), and write through actions with useIntegrationAction(). (ctx.fetch is server-side only.)
Tools
Functions the Ekanos assistant can call. They receive user intent, call your vendor API, and return structured results. The assistant reads thedescription and parameters to understand what they do.
Webhooks
Inbound events from your provider. You declare the expected payload schema and a handler. The host verifies the signature and calls your handler with the validated payload.Schedules
Cron-driven jobs. Samectx as every other handler; the handler receives a ScheduleInvocation and returns { status: 'completed' | 'skipped' }.
Actions
Deterministic write handlers invoked by a widget’s Save button. Unlike tools, they have no LLM governance — a human clicks, the handler runs, the result comes back.The context (ctx)
Every server-side handler (tools, webhooks, schedules, actions, oauth.onTokens, onActivate) receives the same capability context:
Storage schema
Declare what state you’ll hold:Reading and writing
get returns null for a missing key and for an entry past its expiresAt. A read whose stored data no longer matches the schema throws StorageValidationError rather than giving you a shape you didn’t expect.
import type { StorageSchemas } from '@ekanos/sdk'. A key’s part before the / must be an allowed data type for its scope: activation, settings, metrics_summary, sync_state, or cache for account; config, preferences, or cache for user.
Egress allowlist
Declare the origins your handlers call:ctx.fetch refuses anything not covered with EgressDeniedError, before opening a socket — redirect targets included. Entries are https origins only: no path, query, fragment, credentials, or http:. Widening this list is a security-posture change reviewed at promotion.
Naming rules
Everything validates upfront:
Invalid names fail validation with a message that states the rule.
Where everything lives
A typical project afterekanos init and a first ekanos dev (the components/ layout is up to you):
ekanos.json’s entry points at the module to validate. The CLI takes its default export if it has a string slug, otherwise the first named export that does. The scaffold exports it as integration.
The full lifecycle
- Author — Write
src/integration.tswithdefineIntegration() - Validate —
ekanos validatechecks syntax, naming, and structure - Test —
ekanos testruns your project’s test script - Dev —
ekanos devruns the harness and renders everything locally - Publish —
ekanos publishvalidates, packs, and submits - Gate — The host’s submission gate checks the archive (for example
checks/typecheckandchecks/tests); follow it withekanos status --watch - Connect — A user connects through your activation form or OAuth flow
- Run — Handlers execute on schedule, webhook delivery, assistant tool call, or widget action
defineIntegration(), ekanos validate, and the host all validate against the same @ekanos/integration-schema schema. There is no second contract.