---
title: Correlation, identity, and causation
description: The three pieces of context Chronicle carries with every event — who caused it, what operation it belongs to, and why it happened.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';


Every event Chronicle appends carries more than its own data. Three pieces of context travel alongside it, scoped to the current call and captured automatically on every append:

- **Correlation ID** — ties together every event, command, and side effect that belong to the same logical operation (a single HTTP request, a message-bus handler invocation).
- **Identity** — records *who* caused the change: a user, a system, or a service.
- **Causation** — records *why*: the chain of operations, from a root action down to the specific command that triggered this event.

All three are set once at the start of an operation (a request, a background job) and flow into every event appended during it, without threading them through every function call.

## Correlation ID

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Execution;

public class CorrelationIdentityCausationCorrelation(ICorrelationIdAccessor accessor, ICorrelationIdModifier modifier)
{
    public CorrelationId GetCurrent() => accessor.Current;

    public void SetForRequest() => modifier.Modify(CorrelationId.New());
}
```

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.correlation.correlationIdManager
import java.util.UUID

class CorrelationIdentityCausationCorrelation {
    fun getCurrent(): UUID = correlationIdManager.current

    fun setForRequest() = correlationIdManager.set(UUID.randomUUID())
}
```

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.correlation.CorrelationIdManagerKt;
import java.util.UUID;

class CorrelationIdentityCausationCorrelation {
    UUID getCurrent() {
        return CorrelationIdManagerKt.getCorrelationIdManager().getCurrent();
    }

    void setForRequest() {
        CorrelationIdManagerKt.getCorrelationIdManager().set(UUID.randomUUID());
    }
}
```

</TabItem>
<TabItem label="Elixir">

```elixir
defmodule MyApp.CorrelationIdentityCausationCorrelation do
  alias Chronicle.Correlation.CorrelationId

  def get_current do
    Chronicle.current_correlation_id()
  end

  def set_for_request do
    Chronicle.set_correlation_id(CorrelationId.create())
  end
end
```

</TabItem>
<TabItem label="TypeScript">

```typescript
import { correlationIdManager, CorrelationId } from '@cratis/chronicle';

class CorrelationIdentityCausationCorrelation {
    getCurrent(): CorrelationId {
        return correlationIdManager.current;
    }

    setForRequest(): void {
        correlationIdManager.setCurrent(CorrelationId.create());
    }
}
```

</TabItem>
</Tabs>

Kotlin's correlation manager scopes the id per-thread (`ThreadLocal`); Elixir and TypeScript scope it per logical call context (Elixir's process dictionary, TypeScript's `AsyncLocalStorage`) — in both cases automatically, without extra code, as long as you don't spawn new threads/processes/async contexts without carrying the value across explicitly.

## Identity

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Identities;

public class CorrelationIdentityCausationIdentity(IIdentityProvider identityProvider)
{
    public void SetForRequest(string subject, string name, string userName) =>
        identityProvider.SetCurrentIdentity(new Identity(subject, name, userName));

    public Identity GetCurrent() => identityProvider.GetCurrent();
}
```

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.identity.Identity
import io.cratis.chronicle.identity.identityProvider

class CorrelationIdentityCausationIdentity {
    fun setForRequest(subject: String, name: String, userName: String) {
        identityProvider.setCurrentIdentity(Identity(subject, name, userName))
    }

    fun getCurrent(): Identity = identityProvider.currentIdentity
}
```

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.identity.Identity;
import io.cratis.chronicle.identity.IdentityProviderKt;

class CorrelationIdentityCausationIdentity {
    void setForRequest(String subject, String name, String userName) {
        IdentityProviderKt.getIdentityProvider().setCurrentIdentity(new Identity(subject, name, userName, null));
    }

    Identity getCurrent() {
        return IdentityProviderKt.getIdentityProvider().getCurrentIdentity();
    }
}
```

</TabItem>
<TabItem label="Elixir">

```elixir
defmodule MyApp.CorrelationIdentityCausationIdentity do
  alias Chronicle.Identity

  def set_for_request(subject, name, user_name) do
    Chronicle.set_identity(Identity.new(subject, name, user_name))
  end

  def get_current do
    Chronicle.current_identity()
  end
end
```

</TabItem>
<TabItem label="TypeScript">

```typescript
import { identityProvider, Identity } from '@cratis/chronicle';

class CorrelationIdentityCausationIdentity {
    setForRequest(subject: string, name: string, userName: string): void {
        identityProvider.setCurrentIdentity(new Identity(subject, name, userName));
    }

    getCurrent(): Identity {
        return identityProvider.getCurrent();
    }
}
```

</TabItem>
</Tabs>

Every client provides the same three sentinel identities for well-known cases — `System`, `NotSet`, and `Unknown` — and supports on-behalf-of delegation chains (an identity that acted *for* another identity) via a `withoutDuplicates()`/`without_duplicates/1` helper that collapses repeated subjects in a long chain.

## Causation

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Auditing;

public class CorrelationIdentityCausationCausation(ICausationManager causationManager)
{
    public void RecordPlaceOrder(string orderId) =>
        causationManager.Add(
            "MyApp.Commands.PlaceOrder",
            new Dictionary<string, string> { ["orderId"] = orderId });
}
```

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.auditing.CausationType
import io.cratis.chronicle.auditing.causationManager

class CorrelationIdentityCausationCausation {
    fun recordPlaceOrder(orderId: String) {
        causationManager.add(CausationType("MyApp.Commands.PlaceOrder"), mapOf("orderId" to orderId))
    }
}
```

</TabItem>
<TabItem label="Java">

```text
Java does not support this workflow yet.
```

</TabItem>
<TabItem label="Elixir">

```elixir
defmodule MyApp.CorrelationIdentityCausationCausation do
  alias Chronicle.Auditing.CausationManager

  def record_place_order(order_id) do
    CausationManager.add("MyApp.Commands.PlaceOrder", %{order_id: order_id})
  end
end
```

</TabItem>
<TabItem label="TypeScript">

```typescript
import { causationManager, CausationType } from '@cratis/chronicle';

class CorrelationIdentityCausationCausation {
    recordPlaceOrder(orderId: string): void {
        causationManager.add(new CausationType('MyApp.Commands.PlaceOrder'), { orderId });
    }
}
```

</TabItem>
</Tabs>

TypeScript also has a real `causationManager.add(type, properties)` — the client-specific pages linked below cover it, along with more Kotlin/Elixir/TypeScript causation detail than fits here (defining/redefining the root cause, reading the full chain, framework-integration examples for scoping context per request).

## Client-specific reference

Each client's own documentation covers the full API in depth — provider interfaces, framework-integration examples (Express middleware, and similar), and thread/process/async-context caveats specific to that runtime:

- [.NET client](/chronicle/clients/dotnet/) — `Cratis.Execution.ICorrelationIdAccessor`/`ICorrelationIdModifier`, `Cratis.Chronicle.Identities.IIdentityProvider`, `Cratis.Chronicle.Auditing.ICausationManager`
- [Kotlin client](/chronicle/clients/kotlin/) — `io.cratis.chronicle.correlation`, `io.cratis.chronicle.identity`, `io.cratis.chronicle.auditing`
- [Elixir client](/chronicle/clients/elixir/) — `Chronicle.CorrelationId`, `Chronicle.Identity`, `Chronicle.Auditing.CausationManager`
- [TypeScript client](/chronicle/clients/typescript/) — `correlationIdManager`, `identityProvider`, `causationManager`
