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

# Ruby SDK Reference

> Pure API reference for the bitfab RubyGem.

Gem: `bitfab`. Ruby ≥ 3.1. Uses a global singleton client pattern (`Bitfab.configure` / `Bitfab.client`).

## Framework Integrations

No framework-native adapters are shipped for Ruby yet. Instrument Ruby code manually via `Bitfab::Traceable` / `Bitfab.span`. See the [Ruby SDK guide](/ruby-sdk). Framework coverage status: [Frameworks overview](/frameworks/overview).

## Module Layout

```ruby theme={null}
Bitfab                   # top-level module & singleton facade
Bitfab::Client           # the underlying client class
Bitfab::BitfabFunction   # fluent wrapper bound to one trace_function_key
Bitfab::Traceable        # mixin for declarative span tracing
Bitfab::CurrentSpan      # span handle
Bitfab::CurrentTrace     # trace handle
Bitfab::NoOpCurrentSpan  # returned outside a span context
Bitfab::NoOpCurrentTrace # returned outside a span context
Bitfab::Replay           # replay orchestration (internal)
Bitfab::ReplayContext    # thread-local replay context (internal)
Bitfab::ReplayEnvironment # per-trace DB branch exposed during replay
Bitfab::SpanContext      # thread-local span stack (internal)
Bitfab::TraceState       # trace state storage (internal)
Bitfab::MOCK_STRATEGIES  # %w[none all marked]
Bitfab::BITFAB_PROGRESS_PREFIX # wire prefix used by report_replay_progress
```

## Module-Level API

### `Bitfab.configure(api_key:, service_url: nil, enabled: true)`

Creates the global client. Subsequent calls replace it.

| Param          | Type          | Default               |
| -------------- | ------------- | --------------------- |
| `api_key:`     | `String`      | required              |
| `service_url:` | `String, nil` | `"https://bitfab.ai"` |
| `enabled:`     | `Boolean`     | `true`                |

Empty/whitespace `api_key` prints a warning and sets `enabled = false`.

### `Bitfab.client`

Returns the configured `Bitfab::Client`. Raises `RuntimeError("Bitfab not configured...")` if `configure` has not been called.

### `Bitfab.reset!`

Resets the global client to `nil`. Intended for tests.

### `Bitfab.current_span`

Returns the active `CurrentSpan`, or `Bitfab::NO_OP_SPAN` outside a span context.

### `Bitfab.current_trace`

Returns the active `CurrentTrace`, or `Bitfab::NO_OP_TRACE` outside a span context.

### `Bitfab.report_replay_progress(progress)`

Ready-made `on_progress`-shaped callback. Pass it straight into `replay` as `on_progress: Bitfab.method(:report_replay_progress)`. It writes the running totals to stderr (prefixed with `Bitfab::BITFAB_PROGRESS_PREFIX`), which the Bitfab plugin polls to report live progress while the replay runs in the background, while stdout remains available for direct-run `ReplayResult` JSON. It never raises.

## `class Bitfab::Client`

### `SPAN_TYPES`

```ruby theme={null}
Bitfab::Client::SPAN_TYPES  # => %w[llm agent function guardrail handoff custom]
```

### `attr_reader :api_key, :service_url, :enabled`

### `get_trace_span`

```ruby theme={null}
get_trace_span(trace_id, id: nil, name: nil, occurrence: "last")
```

Fetches one persisted span without loading its trace. `trace_id` is the canonical Bitfab trace ID. Exactly one of the span's Bitfab `id` or `name` is required. `occurrence` accepts `"first"`, `"last"`, or a zero-based integer and defaults to `"last"`. Returns `nil` when no trace or span matches.

### `initialize(api_key:, service_url: nil, enabled: true)`

Same semantics as `Bitfab.configure`.

### `replay(receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil, max_concurrency: 10, code_change_description: nil, code_change_files: nil, mock: "marked", experiment_group_id: nil, dataset_id: nil, grader_ids: nil, environment: nil, on_progress: nil)`

| Param                      | Type                             | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| -------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `receiver`                 | `Object` or `Class`              | Instance for instance methods; class for class methods                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `method_name`              | `Symbol`                         | Method to replay                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `trace_function_key:`      | `String`                         | Trace function key for this method. Must match the key the method is traced under (`bitfab_span` / `Bitfab::Traceable.wrap`); a contradicting key raises `ArgumentError`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `limit:`                   | `Integer, nil`                   | Max recent traces to replay (default `5`; maximum 5,000). Ignored when `trace_ids:` or `dataset_id:` is passed                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `trace_ids:`               | `Array<String>, nil`             | Optional explicit trace IDs (max 100; the ID count determines how many traces replay)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `name:`                    | `String, nil`                    | Optional display name for the resulting experiment/test run                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `max_concurrency:`         | `Integer, nil`                   | Max parallel threads (default `10`; `nil` = unlimited)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `code_change_description:` | `String, nil`                    | Optional rationale for the code change being tested (stored on the experiment)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `code_change_files:`       | `Array<Hash>, nil`               | Optional list of edited files, each `{ path:, before:, after: }`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `mock:`                    | `String`                         | Mock strategy for child spans: `"marked"` (default), `"none"`, or `"all"`. Raises `ArgumentError` on any other value.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `experiment_group_id:`     | `String, nil`                    | Optional UUID that groups multiple replay runs into a single experiment batch                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `dataset_id:`              | `String, nil`                    | Optional UUID of the dataset this replay runs against; durably attributes the experiment to that dataset                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `grader_ids:`              | `Array<String>, nil`             | Optional UUIDs of graders attached directly to this run (max 100), unioned with the dataset's runnable graders when the experiment is graded. Each must be an active grader in the same organization and trace function, or the replay is rejected with a 400                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `environment:`             | `Bitfab::ReplayEnvironment, nil` | Optional. When passed, the server resolves a per-trace DB branch and exposes it inside the replayed method via `environment.database_url` (read `environment.active?` first; it is `false` when no branch was resolved)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `on_progress:`             | `#call, nil`                     | Optional callback fired per item as it settles, with a running-totals hash `{ test_run_id:, completed:, total:, succeeded:, errored:, item: }`. `item[:trace_id]` is `nil` during the run (the server replay id isn't known until completion), while `item[:original_trace_id]` is the original historical trace (`:source_trace_id` is a deprecated alias); the item also carries `input`, `result`, `original_output`, `error`, `duration_ms`, `tokens`, `model`, and `db_snapshot_ref`. Render live progress while replay runs; totals only split ran-ok vs errored (pass/fail isn't known yet). A raising callback never crashes the run. The SDK provides a ready-made reporter, `Bitfab.report_replay_progress`, you can pass straight in (`on_progress: Bitfab.method(:report_replay_progress)`): it writes the running totals plus settled item payload to stderr, which the Bitfab plugin polls to report live progress and write per-item result files while the replay runs in the background, so scripts never hand-format the protocol. |

**Returns:** `Hash` with keys `:items`, `:test_run_id`, `:test_run_url`.
Each item has `:input`, `:result`, `:original_output`, `:error`, `:duration_ms` (`Integer, nil`), `:tokens` (`{ input:, output:, cached:, total: }` or `nil`), `:model` (`String, nil`), `:trace_id` (`String, nil`), `:original_trace_id` (`String, nil`), `:original_span_id` (`String, nil`), the deprecated aliases `:source_trace_id` and `:source_span_id`, and `:db_snapshot_ref` (`Hash, nil`, the source trace's snapshot pin, if any). `:duration_ms` and `:model` come from the historical trace the item replays; `:tokens` is the replayed run's token usage (compare it against the original trace's recorded usage); `:trace_id` is the new replay trace's server id, written in after the run completes (`nil` on older servers); `:original_trace_id` and `:original_span_id` identify the original trace and root span being replayed.

**Mock strategies:**

* `"marked"`: only child spans declared with `mock_on_replay: true` return historical output. Falls through to real execution when no historical entry matches. Default.
* `"none"`: every child span runs real code.
* `"all"`: every child span returns its historical output; real code is not executed.

Repeated calls to the same `trace_function_key` are distinguished by call order (`step:0`, `step:1`, ...). The per-key counter advances on every non-root child invocation (including unmarked ones), so a marked sibling following an unmarked sibling lines up with the right historical entry.

### `get_function(trace_function_key)`

Returns a `Bitfab::BitfabFunction` bound to `trace_function_key`. Mirrors `client.get_function` in the Python SDK and `client.getFunction` in TypeScript.

### `execute_span(...)` (internal)

Called by `Traceable`. Not intended for direct use.

## `class Bitfab::BitfabFunction`

Fluent wrapper bound to a single `trace_function_key`, returned by `Bitfab::Client#get_function`.

### `attr_reader :trace_function_key`

### `wrap(klass, method_name, name: nil, type: "custom", mock_on_replay: false)`

Wraps `method_name` on `klass` with span tracing under the bound `trace_function_key`. Delegates to `Bitfab::Traceable.wrap`.

## `module Bitfab::Traceable`

Mixin for declarative instance-method tracing.

### `include Bitfab::Traceable`

Extends the including class with `ClassMethods` below.

### Class Methods (after `include`)

#### `bitfab_function(key)`

Sets the default `trace_function_key` for all `bitfab_span` declarations in this class.

#### `bitfab_span(method_name, trace_function_key: nil, name: nil, type: "custom", mock_on_replay: false)`

Wraps `method_name` with span tracing.

| Param                 | Type          | Default                                                                                                       |
| --------------------- | ------------- | ------------------------------------------------------------------------------------------------------------- |
| `method_name`         | `Symbol`      | required                                                                                                      |
| `trace_function_key:` | `String, nil` | falls back to the class-level `bitfab_function` key                                                           |
| `name:`               | `String, nil` | defaults to `method_name.to_s`                                                                                |
| `type:`               | `String`      | `"custom"` (one of `SPAN_TYPES`)                                                                              |
| `mock_on_replay:`     | `Boolean`     | `false`; when `true`, replay returns this span's historical output under the default `"marked"` mock strategy |

Supports three call styles:

1. **Before `def`**: registered via `method_added` hook, wrapped when method is defined
2. **Inline**: `bitfab_span def foo ... end, type: "function"` (Ruby's `def` returns `:foo`)
3. **After `def`**: wraps immediately if the method already exists

Raises `RuntimeError` if no `trace_function_key` is provided and no class-level `bitfab_function` was set.

### Module-Level Wrapping

#### `Bitfab::Traceable.wrap(klass, method_name, trace_function_key:, name: nil, type: "custom", mock_on_replay: false)`

Wraps a method on a class you do not own. Uses `Module#prepend`.

| Param                 | Type                |
| --------------------- | ------------------- |
| `klass`               | `Class` or `Module` |
| `method_name`         | `Symbol`            |
| `trace_function_key:` | `String`            |
| `name:`               | `String, nil`       |
| `type:`               | `String`            |
| `mock_on_replay:`     | `Boolean`           |

## `class Bitfab::CurrentSpan`

```ruby theme={null}
def id        # => canonical Bitfab span ID
def trace_id  # => String
def add_context(context)  # Hash → appends one entry; ignores non-Hash; never raises
def set_prompt(prompt)    # String → overwrites; ignores non-String; never raises
```

## `class Bitfab::CurrentTrace`

```ruby theme={null}
def set_session_id(session_id)  # String
def set_metadata(metadata)      # Hash → shallow-merge, later keys win
def add_context(context)        # Hash → appends entry
def drop                        # flags the trace to be dropped at completion
```

All methods swallow exceptions internally; they never raise.

`drop` flags the trace to be dropped: once flagged, spans that complete afterward are not uploaded at all, and the flag rides out on the completion payload, so at completion the server scrubs any payloads that already raced out (the trace, its external trace, and sibling spans), deletes the archived S3 objects, and marks it `dropped` instead of `completed`, keeping only a skeleton audit row. Calling it outside a span (on `NO_OP_TRACE`) is a no-op.

## `class Bitfab::NoOpCurrentSpan` / `NoOpCurrentTrace`

Singleton instances exposed as `Bitfab::NO_OP_SPAN` and `Bitfab::NO_OP_TRACE`. All methods are no-ops. `id` and `trace_id` return `""`.

## Thread & Concurrency Model

* Span stack is stored in `Thread.current[:__bitfab_span_stack]` (**not** propagated to child threads automatically)
* Trace state is stored in a mutex-protected module-level hash (`Bitfab::TraceState`) keyed by `trace_id`
* Span HTTP sends run in background threads; the client tracks pending threads per trace

## Error Behavior Summary

| Situation                                                                | Behavior                                                             |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| Empty `api_key`                                                          | Warning via `warn`, `enabled` forced to `false`                      |
| `bitfab_span` method raises                                              | Span records `error` and `error_source: "code"`, exception re-raised |
| `add_context` / `set_prompt` with invalid input                          | Silently ignored. Never raises                                       |
| Span transport failure                                                   | Swallowed. Host app never crashes                                    |
| `Bitfab.client` before `configure`                                       | `RuntimeError("Bitfab not configured...")`                           |
| `bitfab_span` without `trace_function_key`                               | `RuntimeError`                                                       |
| `replay` -- `trace_function_key:` differs from the method's declared key | `ArgumentError` (key mismatch)                                       |
