> ## Documentation Index
> Fetch the complete documentation index at: https://docs.automate.ax/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Automate.ax automations are TypeScript programs.
> Use Bun for installation and command examples.
> Use Automate.ax for the product name and automate.ax for the package, CLI, and domain.
> Treat documented public APIs as current; do not invent transitional or deprecated names.

# Coordinate occurrences

> Key, join, batch, or fan out values that arrive in separate execution contexts.

Every trigger occurrence starts a root context. A cross-context operator selects occurrences and creates a child context containing their parent histories.

| Result                                                       | Operators                                                                                                                                                                         |
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Run the same flow for every occurrence from several triggers | [`merge`](/reference/runtime/signal-operators#merge)                                                                                                                              |
| Join related events from different triggers                  | [`keyBy`](/reference/runtime/signal-operators#keyby), then [`correlate`](/reference/runtime/signal-operators#correlate)                                                           |
| Batch a fixed number of occurrences                          | [`keyBy`](/reference/runtime/signal-operators#keyby) or [`globally`](/reference/runtime/signal-operators#globally), then [`collect`](/reference/runtime/signal-operators#collect) |
| Admit once or a bounded number of times                      | [`once`](/reference/runtime/signal-operators#once-and-take) or [`take`](/reference/runtime/signal-operators#once-and-take)                                                        |
| Enforce a rolling quota                                      | [`rateLimit`](/reference/runtime/signal-operators#ratelimit)                                                                                                                      |
| Run one section per item already in an array                 | [`each`](/reference/runtime/signal-operators#each)                                                                                                                                |
| Prevent overlapping work for one partition                   | [`serialize`](/reference/runtime/signal-operators#serialize)                                                                                                                      |
| Bound overlapping work for one partition                     | [`concurrent`](/reference/runtime/signal-operators#concurrent)                                                                                                                    |
| Time or buffer a burst                                       | [Control event bursts](/guides/control-event-bursts)                                                                                                                              |

## Partition the streams

Use `keyBy` when each customer, record, conversation, or other business key needs its own coordination state. Use `globally` only when every occurrence should enter one shared batch or timer.

```ts automations/match-decisions.automation.ts theme={null}
import { automation, correlate, onInvocation, sendEmail, t } from "automate.ax"

export default automation("Match approval decisions", () => {
  const request = onInvocation<{ id: string; title: string }>("request").keyBy(
    (value) => value.id,
  )
  const decision = onInvocation<{ requestId: string; status: string }>(
    "decision",
  ).keyBy((value) => value.requestId)

  correlate([request, decision])
  sendEmail({
    subject: t`Decision for ${request.title}`,
    text: t`The decision was ${decision.status}.`,
  })
})
```

The email can consume both original signals because the correlation child is their closest shared boundary.

## Merge independent triggers

Use `merge` when every occurrence should continue independently through the same flow. Unlike `correlate`, it doesn't wait for another stream or consume occurrences in pairs.

```ts automations/process-contact-events.automation.ts theme={null}
import {
  automation,
  merge,
  onInvocation,
  sendEmail,
  serialize,
  t,
} from "automate.ax"

interface ContactEvent {
  contactId: string
  user: string
}

export default automation("Process contact events", () => {
  const created = onInvocation<ContactEvent>("contactCreated")
  const updated = onInvocation<ContactEvent>("contactUpdated")
  const contactEvent = merge([created, updated])

  serialize(
    contactEvent.keyBy((event) => event.user),
    () => {
      sendEmail({
        subject: t`Contact ${contactEvent.contactId} changed`,
        text: t`Processing the change for ${contactEvent.user}.`,
        to: "operations@example.com",
      })
    },
  )
})
```

Here the merged signal supplies each queued occurrence, the user key creates one queue per user, and the signal's value remains available inside the serialized section. Two actions declared inside the section without a dependency on each other would still run concurrently. The next event for that user waits for the entire section's work region to close; events for other users don't wait.

Value-preserving operators retain a keyed or global annotation. Arbitrary derivations and multi-input selections can return an ordinary signal; apply `keyBy` or `globally` again before another cross-context operation.

## Choose an identity and time

Prefer a provider's entity or conversation ID when it expresses the relationship. Use [`correlationId`](/reference/runtime/signal-operators#correlationid) when you need a stable opaque identity for one durable occurrence. Use [`timestamp`](/reference/runtime/signal-operators#timestamp) when you need Automate.ax ingestion, completion, or coordination time instead of a provider timestamp.

## Batch or fan out

Use `collect` when a count closes the group. The result is a nonempty array in arrival order. Use `each` when one existing array should create a durable child context per item; return a signal from the section only when you need to gather the per-item results.
