Skip to main content

automations/

Automations start durable agent work without a conversational prompt. Every automation declares a trigger and may invoke the default agent, a skill, an agent target, or a playbook. Triggers are either time-based schedules or normalized external events.

Scheduled Automation

// automations/morning_brief.ts
import { defineAutomation } from "@assemblyline-agents/core";

export default defineAutomation({
description: "Run a daily brief.",
trigger: {
type: "schedule",
cron: "0 8 * * *",
timezone: "America/Chicago"
},
idempotencyKey: "starter-agent:morning-brief",
message: "Prepare the morning brief.",
target: { type: "skill", name: "morning-brief" }
});

Schedule automations require idempotencyKey. The runtime appends the due timestamp to this prefix, reserves the resulting key before dispatch, and records one durable run for each cron occurrence.

Event Automation

// automations/process_client_email.ts
import { defineAutomation } from "@assemblyline-agents/core";

export default defineAutomation({
description: "Process important client email.",
trigger: {
type: "event",
source: "gmail",
event: "email.received",
connection: "gmail",
filter: {
label: "important"
}
},
message: "Review the email and extract the required actions.",
target: { type: "skill", name: "process-client-email" }
});

Event filters use recursive JSON-subset matching. Every key in filter must exist with the same value in the normalized event payload; extra payload keys are allowed. Event automations default their idempotency prefix to automation:<filename>, then append the provider's stable eventId.

Trusted hosts can submit normalized events directly:

POST /assembly-line/automations/events
Authorization: Bearer <ASSEMBLY_LINE_ADMIN_TOKEN>
Content-Type: application/json

{
"source": "gmail",
"event": "email.received",
"eventId": "provider-message-id",
"occurredAt": "2026-07-24T13:30:00Z",
"payload": {
"label": "important",
"subject": "Contract follow-up"
}
}

Provider channel modules can return { kind: "event", event } from normalizeHttp() after verifying the provider signature. Long-lived channel listeners can call emit.automation(event). Both paths use the same filtering, capacity, idempotency, and durable run path as direct host dispatch through runtime.dispatchAutomationEvent(event).

Lifecycle Handlers

Trusted prepare/finalize code lives in automation-handlers/. A lifecycle handler can prepare memory and resources before the model turn, select a target, and finalize application state afterward without exposing orchestration tools to the model.

// automation-handlers/llm_wiki_dream.ts
import { defineAutomationHandler } from "@assemblyline-agents/core";

export default defineAutomationHandler({
async prepare(ctx) {
const bundle = await ctx.resources.collect({
sources: ["memory", "history", "connections"],
limit: 100
});

return {
target: { type: "skill", name: "personal-wiki-update" },
promptContext: {
triggerKind: ctx.trigger.kind,
sourceBundle: bundle.markdown
}
};
},

async finalize(ctx, result) {
await ctx.emit("wiki.automation_finished", {
ok: result.ok,
status: result.status ?? "unknown"
});
}
});

Reference it from either trigger kind:

export default defineAutomation({
trigger: {
type: "schedule",
cron: "15 8 * * *",
timezone: "UTC"
},
idempotencyKey: "system-routine:wiki-dream",
lifecycle: { handler: "llm_wiki_dream" },
target: { type: "skill", name: "personal-wiki-update" }
});

The handler context exposes run identity, trigger metadata, memory, resources, blob storage, environment access, routine-run bookkeeping, durable events, idempotency keys, and replayable ctx.step() execution. For event automations, ctx.trigger.event contains the normalized event envelope.

Dynamic Automations

dynamicAutomations in agent.ts controls runtime-created automations:

export default defineAgent({
model: "openai/gpt-5.4",
dynamicAutomations: {
dynamic: true,
approval: false
}
});

Tools use ctx.automationManager:

await ctx.automationManager?.createAutomation({
message: "Prepare a weekly review.",
cron: "0 16 * * 5",
timezone: "America/Chicago"
});

Dynamic automation creation currently supports time-based schedules. Event automation definitions remain reviewed source because provider subscription, authentication, and filtering policy are trusted application concerns.

Hosts trigger due time-based work through runtime.runDueAutomations() or GET/POST /assembly-line/automations/tick. The legacy runDueSchedules() and /assembly-line/scheduler/tick names remain available during deprecation, and the older /openeve/* route aliases stay served (same auth and rate limits) during the rename compatibility window.

Delivery And Reliability

  • Provider event IDs and schedule occurrence IDs are reserved durably.
  • Capacity is checked before consuming an event's idempotency key.
  • Provider delivery is at least once, so external side effects must still use ctx.idempotencyKey() or destination-level deduplication.
  • delivery on a normalized event can route the final result through an originating provider. Omitting it runs the automation silently.
  • Channels remain conversational ingress. Automations are operational ingress and do not require a conversation or reply.

Legacy Compatibility

schedules/, triggers/, defineSchedule(), defineTriggerHandler(), dynamicSchedules, and ctx.scheduleManager remain accepted for compatibility and emit compiler deprecation warnings where applicable. New agents should use automations/, automation-handlers/, defineAutomation(), defineAutomationHandler(), dynamicAutomations, and ctx.automationManager.