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

# Rivet

> Trace business functions inside Rivet workflow steps

Trace the business function inside an existing Rivet step with `withTrace()`. Bitfab records its input, output, errors, and first-party calls. Rivet continues to own step scheduling and recovery.

<Note>
  This initial integration is a tracing recipe using the existing TypeScript SDK.
  Subtree tracing is experimental. The actor fixture is verified with RivetKit
  2.3.15 on Node.js using the TypeScript transform. Tool mocking and full actor
  replay are separate work.
</Note>

## Configure capture

Install `@bitfab/sdk` and configure a [TypeScript transform adapter](/typescript-sdk#experimental-subtree-tracing) for your server build. The transform records first-party functions called beneath `withTrace()`.

Without a transform, the root still records its input and output. Its descendants are absent. Use `withNode()` to name or type a discovered call. A node does not create a span by itself.

## Trace an existing step

Keep the step name and callback in place. Create the traced function inside the callback so the live step context stays in a closure. Pass the message as the recorded input.

```typescript theme={null}
import { Bitfab, getCurrentTrace } from "@bitfab/sdk"

const bitfab = new Bitfab({ apiKey: process.env.BITFAB_API_KEY })

// Inside your existing workflow callback, after receiving a message:
await ctx.step("process-turn", async (step) => {
  const runTurn = bitfab.withTrace(
    "chat-turn",
    { name: "Process turn", type: "agent" },
    async (input: { turnId: string; message: string }) => {
      getCurrentTrace().setSessionId(step.actorId)
      getCurrentTrace().setMetadata({
        framework: "rivet",
        actorId: step.actorId,
        actorName: step.name,
        turnId: input.turnId,
      })
      return processTurn(input)
    },
  )

  return runTurn(message.body)
})
```

`processTurn` is your existing application function. It may close over the step context when it needs actor state or database access. Await all work that uses that context before the step callback returns. Rivet restricts actor capabilities to an active step callback. See [Rivet's step context rules](https://rivet.dev/workflows/docs/steps/).

Record message data as input. Store actor and turn identifiers in trace metadata. Passing a live context as input would record runtime internals without reconstructing actor state.

## Trace shape and retries

The root represents one execution attempt of the business function. Calls such as input preparation, model invocation, and persistence appear underneath it when their first-party code is transformed.

* Queue waits and workflow sleeps stay outside the root. Waiting for a message does not create a failed turn trace.
* A failed business function records its error and rethrows it. Rivet applies its existing retry policy.
* A retry creates a new trace for the new attempt. The actor session and turn metadata let you correlate attempts.
* A completed step restored from Rivet's history does not invoke the callback again. It produces no new business-function trace.

This boundary does not produce one continuous trace across actor eviction or process restart. It does not import Rivet's journal or display recovered model outputs as new model calls. A turn spanning several durable steps can trace each existing step body with the same actor session and turn metadata.

Do not merge or reorder durable steps to obtain a larger trace. Keep tracing inside the existing execution boundary. Leave workflow-level retry and error hooks unchanged.

## Verified scope

The real actor tests exercise queue delivery, local SQLite, actor state, concurrent actors, workflow sleep, and a failed model attempt followed by a successful retry. They assert root input/output, child parenting, actor metadata, session identity, and error capture. The same successful workload is tested with capture disabled.

The tests intercept Bitfab transport and use a model test double. They do not verify delivery to a hosted Bitfab service, forced eviction, process restart, streaming, or every Rivet version. Whole-workflow suspension status handling remains outside this step-body recipe.

Tracing does not make external operations safe to replay. This recipe adds no tool mocking. See [Instrumentation](/instrumentation) for capture configuration.
