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

# From Raindrop

> Mechanical translation from Raindrop (raindrop-ai) to Bento.

Bento's `bento.track_ai` was modeled on Raindrop's, so most call shapes survive the port unchanged. Two things differ. Bento requires `provider=` on every call, and Bento's native integration ships for Google ADK only. To keep Raindrop's auto-capture for OpenAI, Anthropic, and Bedrock, swap to OpenInference instrumentors.

## Migrate with an AI coding tool

Install Bento's Agent Skills so your AI coding tool knows how to do the migration. Copy this prompt into Claude Code, Cursor, Codex, OpenCode, or Windsurf:

````markdown theme={null}
Migrate this project from Raindrop to Bento.

```bash
npx skills add BentoLabs-ai/skills
```

Use the `bentolabs-migrate` skill. Walk me through it step by step and confirm before editing.
````

The skill carries the full playbook: find your Raindrop call sites, install Bento alongside, translate each construct, verify traces land, then remove Raindrop. The rest of this page is the same guide if you'd rather do it by hand.

## The three paths

Pick the smoothest applicable one and fall through. Most migrations end up using **B** for the bulk and **C** for the handful of bespoke decorators.

| Path                                                                          | When                                                                                 | Effort                                            |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------- |
| [A: Google ADK integration](#path-a-google-adk-integration)                   | ADK is in use                                                                        | 3 lines at startup                                |
| [B: Auto-capture with OpenInference](#path-b-auto-capture-with-openinference) | Raindrop's `auto_instrument=True` captured OpenAI / Anthropic / Bedrock for you      | Drop the Raindrop init, register one instrumentor |
| [C: Manual translation](#path-c-manual-translation)                           | `@raindrop.interaction` / `@raindrop.tool` / `@raindrop.task`, bare `track_ai` calls | Per-call-site rename, add `provider=`             |

***

## Path A: Google ADK integration

If your app runs Google ADK agents, this captures every model call, tool call, and agent step automatically.

```bash theme={null}
pip install "bentolabs-sdk[adk]"
```

```python theme={null}
import bentolabs_sdk as bento

bento.init(
    user_id=lambda: get_current_user_id(),
    session_id=lambda: get_current_session_id(),
)
bento.instrument()
```

That's it. Full reference: [Integrations](/python/integrations).

***

## Path B: Auto-capture with OpenInference

Raindrop's `auto_instrument=True` (powered by Traceloop) wrapped OpenAI, Anthropic, and Bedrock automatically. You get the same auto-capture from OpenInference instrumentors registered against a `BentoLabsSpanProcessor`. **Your call sites stay untouched.** Every LLM call is captured at the SDK level.

```bash theme={null}
pip install openinference-instrumentation-openai
# Other libs as needed: -anthropic, -bedrock, -langchain, -llama-index
```

```python theme={null}
from openinference.instrumentation.openai import OpenAIInstrumentor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry import trace

from bentolabs_sdk import BentoLabsSpanProcessor

provider = TracerProvider()
provider.add_span_processor(BentoLabsSpanProcessor())
trace.set_tracer_provider(provider)

OpenAIInstrumentor().instrument(tracer_provider=provider)
```

Drop `raindrop.init(...)` and the `auto_instrument=True` flag. The instrumentor captures your OpenAI call sites:

```python theme={null}
from openai import OpenAI

client = OpenAI()
resp = client.chat.completions.create(model="gpt-4o", messages=[...])
# Bento captures the call. Nothing else to do.
```

For Anthropic and Bedrock, install the matching `openinference-instrumentation-*` and register it the same way.

Full reference: [OTel transport](/python/otel-transport).

***

## Path C: Manual translation

For bespoke decorators, manual `track_ai` calls, and identity helpers, translate per the tables.

### Setup

| Raindrop                                                 | Bento                                |
| -------------------------------------------------------- | ------------------------------------ |
| `pip install raindrop-ai`                                | `pip install bentolabs-sdk`          |
| `RAINDROP_WRITE_KEY`                                     | `BENTOLABS_API_KEY`                  |
| `import raindrop.analytics as raindrop`                  | `import bentolabs_sdk as bento`      |
| `raindrop.init(api_key=...)`                             | `bento.init(api_key=...)`            |
| `raindrop.init(auto_instrument=True, instruments={...})` | Use Path B instead                   |
| `raindrop.flush()` / `raindrop.shutdown()`               | `bento.flush()` / `bento.shutdown()` |

### Tracking

| Raindrop                      | Bento                                      |
| ----------------------------- | ------------------------------------------ |
| `raindrop.track_ai(...)`      | `bento.track_ai(...)`, **add `provider=`** |
| `raindrop.begin(...)`         | `bento.begin(...)`                         |
| `interaction.track_tool(...)` | `with interaction.tool_span(...) as ts:`   |

### Decorators

| Raindrop                                 | Bento                                                     |
| ---------------------------------------- | --------------------------------------------------------- |
| `@raindrop.interaction("X")`             | `@bento.interaction(event="X")`                           |
| `@raindrop.tool("X")`                    | `@bento.tool(name="X")`                                   |
| `@raindrop.task("X")` / `task_span(...)` | `@bento.tool` / `tool_span(...)`, no separate "task" kind |

### What's gone

| Raindrop                                   | Where it goes                                        |
| ------------------------------------------ | ---------------------------------------------------- |
| `raindrop.identify(user_id, traits)`       | Move traits to `properties=` or init-time `tags`     |
| `raindrop.track_signal(...)`               | `bento.track_ai(event="feedback", properties={...})` |
| `raindrop.set_redact_pii(True)`            | Scrub at the app boundary                            |
| `Attachment(...)` / `add_attachments(...)` | Fold metadata into `properties=`; no binary support  |

***

## Watch out for

* **`provider=` is required.** Raindrop infers it via Traceloop; Bento does not. Bedrock model IDs need `provider="aws_bedrock"`, not `"anthropic"`.
* **`identify()` data is lost.** No user-profile store in Bento. Port traits to per-call `properties=` or init-time `tags`.
* **OTel context.** Bento detaches from any outer OTel context; Raindrop participates in it. Agent runs become standalone traces.

## Side-by-side

```python Raindrop theme={null}
import raindrop.analytics as raindrop

raindrop.init(os.getenv("RAINDROP_WRITE_KEY"), auto_instrument=True)

@raindrop.interaction("answer_question")
def answer(user_id, convo_id, question):
    raindrop.identify(user_id, {"plan": "pro"})

    resp = openai_client.chat.completions.create(
        model="gpt-4o", messages=[{"role": "user", "content": question}],
    )
    reply = resp.choices[0].message.content
    raindrop.track_ai(
        user_id=user_id, event="answer", convo_id=convo_id,
        model="gpt-4o", input=question, output=reply,
    )
    return reply
```

```python Bento theme={null}
import bentolabs_sdk as bento

bento.init(api_key=os.getenv("BENTOLABS_API_KEY"))

@bento.interaction(event="answer_question")
def answer(user_id, convo_id, question):
    resp = openai_client.chat.completions.create(
        model="gpt-4o", messages=[{"role": "user", "content": question}],
    )
    reply = resp.choices[0].message.content
    bento.track_ai(
        event="answer",
        user_id=user_id,
        convo_id=convo_id,
        model="gpt-4o",
        provider="openai",                  # NEW — explicit
        input=question,
        output=reply,
        properties={"plan": "pro"},          # was raindrop.identify(...) traits
    )
    return reply
```

## See also

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/python/configuration">
    `init()`, identity getters, env vars.
  </Card>

  <Card title="Tracking events" icon="code" href="/python/track-ai">
    The `bento.track_ai` reference.
  </Card>
</CardGroup>
