Define locally

Author typed workflow, agent, and entity-type definitions with define* factories.

Use the define* factories in @lunnoa/client to describe connections, catalogue actions, linear workflows, agents, and entity types as pure typed config. Nothing is deployed or executed until you call Start runs or the CLI. These examples assume you import from @lunnoa/client. Discover catalogue ids with npx @lunnoa/client tools list / tools get before writing defineAction.

Factories

FactoryRole
defineConnection({ id? })Ref to an app Connection UUID
defineAiConnection({ id? })Ref to an AiProviderConnection UUID
defineAction({ id, connection?, … })Catalogue action binding
defineWorkflow({ slug, steps })Linear workflow (v1), project-scoped slug
defineAgent({ slug, model, instructions, … })Agent definition, project-scoped slug
defineEntityType({ slug, attributeSchema, … })Entity type schema, workspace-scoped slug

Omit connection / aiConnection when the platform can resolve them: sole usable connection for that app, else the workspace default (isDefault), else a 400 with candidates. The platform never picks “first created” among many.

defineEntityType defaults to allowUnknownAttributes: false (strict instance writes). Use the reserved attribute key extensions on records for flexible bags. See Entities.

definitions.ts
import {  defineAction,  defineAgent,  defineAiConnection,  defineConnection,  defineEntityType,  defineWorkflow,} from '@lunnoa/client';const gmail = defineConnection({ id: process.env.GMAIL_CONNECTION_ID });export const invoice = defineEntityType({  slug: 'invoice',  name: 'Invoice',  namePlural: 'Invoices',  icon: 'fileText',  color: '#3B82F6',  attributeSchema: {    version: '1.0',    sections: [      {        id: 'basic',        name: 'Basic',        order: 0,        collapsible: false,        defaultExpanded: true,        fields: [          {            id: 'amount',            name: 'amount',            label: 'Amount',            type: 'currency',            order: 0,            required: true,            visibility: 'always',            config: {},          },        ],      },    ],  },});export const syncOrders = defineWorkflow({  slug: 'sync-orders',  name: 'Sync orders',  steps: [    {      use: defineAction({        id: 'http_action_send-request',        input: { method: 'GET', url: 'https://api.example.com/orders' },      }),    },    {      use: defineAction({        id: 'gmail_action_send-email',        connection: gmail,        input: { to: 'ops@example.com', subject: 'Orders synced' },      }),    },  ],});export const triage = defineAgent({  slug: 'support-triage',  model: 'gpt-4o',  instructions: 'Triage inbound support mail. Be concise.',  aiConnection: defineAiConnection({ id: process.env.AI_CONNECTION_ID }),  tools: [    defineAction({ id: 'http_action_send-request' }),    syncOrders,  ],});

What is deferred

Branches, NEEDS_INPUT, and approvals inside defineWorkflow; MCP / A2A / skills / memory on defineAgent; creating connections from code; ephemeral agents without a row.

Related