> ## 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

> Join, collect, and fan out values across execution contexts.

Each trigger occurrence begins in its own context. Cross-context operators create child contexts that inherit the selected parent histories without copying application values into operator state.

## `.keyBy()`

`.keyBy(getKey, options?)` immutably assigns an encoded partition key to a signal. The synchronous key function must be pure.

```ts theme={null}
const requestById = request.keyBy((value) => value.id, { ttl: "30d" })
```

The optional `ttl` excludes an unmatched occurrence from future coordination after the duration elapses. It does not promise immediate physical deletion. Calling `.keyBy()` replaces a previous keyed or global partition annotation.

## `.globally()`

`.globally()` explicitly places every occurrence in one shared partition for each operator that consumes it:

```ts theme={null}
const batch = collect(message.globally(), 10)
```

Calling `.globally()` replaces a previous keyed or global partition annotation. Prefer `.keyBy()` when independent entities should not affect each other.

## Partition preservation

Operators that preserve one source value also preserve its explicit keyed or global partition. Operators that combine values require an explicit partition on their result before another cross-context operation.

| Preserves the annotation                                                                                                                                 | Produces an ordinary signal                                                                                                                                         |
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gate`, `filter`, `partition`, selecting `funnel`, `debounce`, value-carrying `delay`, `timeout`, `onSuccess`, and a signal directly returned by `scope` | Property access, arbitrary `transform`, `fallback`, `race`, lifecycle projections, `correlate`, `collect`, buffered `funnel`, `window`, and gathered `each` results |

## `correlate()`

`correlate(streams, options?)` eagerly matches one occurrence from every keyed stream. Matching uses exact encoded keys, consumes occurrences one-to-one and oldest-first, and creates a child context containing every selected parent history.

```ts theme={null}
import { correlate, sendEmail, t } from "automate.ax"

const requestById = request.keyBy((value) => value.id, { ttl: "30d" })
const decisionById = decision.keyBy((value) => value.requestId)

correlate([requestById, decisionById], { ordered: true })

sendEmail({
  subject: t`Decision for ${requestById.title}`,
  text: t`The decision was ${decisionById.status}.`,
})
```

Consume the original signals downstream. The returned `Signal<null>` is only an explicit match boundary for lower-level compositions. `{ ordered: true }` additionally requires occurrences to arrive in array order; unordered matching is the default.

TypeScript requires at least two keyed streams. The same durable signal origin cannot occupy multiple positions because one occurrence cannot satisfy two roles; collect distinct occurrences first when that is the intended behavior. A locally filtered or partitioned path that closes contributes no occurrence and does not close future correlation.

## `collect()`

`collect(signal, count, options?)` consumes occurrences FIFO and emits an array for each complete batch. `count` is a positive integer or a signal carrying one.

```ts theme={null}
import { collect } from "automate.ax"

const customerBatch = collect(
  message.keyBy((value) => value.customerId, { ttl: "7d" }),
  10,
)
```

A keyed source maintains one collection per key; `.globally()` creates one shared collection. Signal-derived counts participate in matching, so occurrences batch together only when their resolved count values match. Locally closed inputs contribute no occurrence.

The result is an ordinary `Signal<T[]>`. When selected parents contain conflicting values for another signal, the last parent supplies that value by default; pass `{ inheritConflictingValuesFrom: "first" }` to choose the first. This does not change FIFO result order.

## `each()`

`each(arraySignal, section)` creates one inherited child context for every array position. The synchronous section receives a `Signal<T>` for its item.

```ts theme={null}
import { each, sendEmail } from "automate.ax"

const sentIds = each(recipients, (recipient) =>
  sendEmail({
    to: recipient,
    subject: "Welcome",
    text: "Thanks for joining.",
  }).transform((result) => result.id),
)
```

Return a signal to gather results in source-array order, regardless of completion order. A failed item fails the gathered result; a closed item closes it. Returning nothing fans out the side effects without creating a join signal. An empty input gathers to `[]`.

See [burst control](/reference/signals/control-bursts) to coordinate occurrences by time, or [route and scope work](/reference/signals/route-and-scope) for dependencies within one context.
