> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-beta.getzep.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-beta.getzep.com/_mcp/server.

# Import Trajectories from Braintrust

If your agent already sends traces to Braintrust, Zep can import those traces as Trajectories. You do not have to add capture code to the agent first. Imported Trajectories go through the same summary, compilation, admission, and retrieval steps as [captured Trajectories](/agent-skills/capture-trajectories). An import does not create or admit a Skill directly.

You can do these steps in the Dashboard or with the SDK. In the Dashboard, add the Braintrust credential in the project settings under **Trace Connections**. Then open the Agent and add an import.

## How an import works

1. A trace connection stores one Braintrust credential for the project. Zep verifies the credential before it stores it, and Zep never returns the credential.
2. A Trajectory import selects Braintrust traces for one Agent. A one-time import reads a list of trace IDs or the traces that match a filter. A scheduled import reads new traces that match a filter at a fixed interval.
3. A mapping tells Zep how to set the task family, the objective, and the outcome of each Trajectory from the trace data.
4. Each run of the import creates or updates one Trajectory for each trace.

## Connect Braintrust

Use a Braintrust service token that can read only the projects that you import. A Braintrust API key also works.

**`Python`**

```python Python
import os

from zep_cloud.client import Zep

client = Zep(api_key=os.environ["ZEP_API_KEY"])

connection = client.trace_connection.create(
    provider="braintrust",
    name="Production Braintrust",
    credential=os.environ["BRAINTRUST_SERVICE_TOKEN"],
)

project = next(
    p
    for p in client.trace_connection.project.list(connection.uuid_)
    if p.name == "support-agent"
)
```

**`TypeScript`**

```typescript TypeScript
import { Zep, ZepClient } from "@getzep/zep-cloud";

const client = new ZepClient({ apiKey: process.env.ZEP_API_KEY });

const connection = await client.traceConnection.create({
  provider: "braintrust",
  name: "Production Braintrust",
  credential: process.env.BRAINTRUST_SERVICE_TOKEN,
});

let projectId: string | undefined;
for await (const p of await client.traceConnection.project.list(connection.uuid!)) {
  if (p.name === "support-agent") {
    projectId = p.id;
    break;
  }
}
```

The project list is paged. The SDK reads the next pages when you iterate. If you change the credential of a connection later, the new credential must belong to the same Braintrust organization. Zep returns HTTP `409 Conflict` for a credential from a different organization.

## Map traces to Trajectories

The `mapping` object sets the Trajectory fields from each trace:

| Field         | Sources                                                                                                         | Default                                                            |
| ------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `task_family` | A fixed value, a metadata key, a tag prefix, or the trace name                                                  | No default. If the source gives no value, the run skips the trace. |
| `objective`   | The first user message, the root input, or a metadata key                                                       | The first user message                                             |
| `outcome`     | A list of rules on a score, a metadata value, or the trace error. The first rule that matches sets the outcome. | `unknown`                                                          |

In these examples, `agent` is an Agent that you created, as in the [quickstart](/agent-skills/quickstart).

Use a Braintrust score that your evaluation already computes. A score rule sets external verification, so a successful run can increase the `trust` of a Skill. A Trajectory with outcome `unknown` gives a summary, but it gives weak evidence for admission. For more about outcomes and verification, see [Capture Trajectories](/agent-skills/capture-trajectories).

To test a mapping before you save an import, read one trace with the mapping. The `preview` field of the response shows the task family, objective, outcome, and verification that the mapping gives. If the run will skip the trace, `preview` shows the skip reason.

**`Python`**

```python Python
mapping = {
    "task_family": {"source": "fixed", "value": "billing.support"},
    "objective": {"source": "first_user_message"},
    "outcome": [
        {
            "rule": "score",
            "name": "resolution",
            "succeeded_at_or_above": 0.8,
            "failed_below": 0.4,
        }
    ],
}

preview = client.trace_connection.trace.get(
    connection.uuid_,
    provider_project_id=project.id,
    trace_id="trace-123",
    mapping=mapping,
)
```

**`TypeScript`**

```typescript TypeScript
const mapping: Zep.TrajectoryMapping = {
  taskFamily: { source: "fixed", value: "billing.support" },
  objective: { source: "first_user_message" },
  outcome: [
    {
      rule: "score",
      name: "resolution",
      succeededAtOrAbove: 0.8,
      failedBelow: 0.4,
    },
  ],
};

const preview = await client.traceConnection.trace.get(connection.uuid!, {
  providerProjectId: projectId!,
  traceId: "trace-123",
  mapping,
});
```

To find trace IDs, list the traces of a project with `trace_connection.trace.list`. The list accepts a filter on start time, tags, metadata, scores, and errors.

## Import traces one time

A one-time import starts a run immediately. Use it to learn from a set of traces that you selected. Send up to 1,000 trace IDs, or send a `filter` instead of `trace_ids`. A `filter` must contain `started_after`, `started_before`, or both.

**`Python`**

```python Python
once = client.agent.trajectory_import.create(
    agent.uuid_,
    name="Billing backfill",
    connection_uuid=connection.uuid_,
    provider_project_id=project.id,
    selection={"trace_ids": ["trace-123", "trace-456"]},
    mapping=mapping,
)
```

**`TypeScript`**

```typescript TypeScript
const once = await client.agent.trajectoryImport.create(agent.uuid!, {
  name: "Billing backfill",
  connectionUuid: connection.uuid,
  providerProjectId: projectId,
  selection: { traceIds: ["trace-123", "trace-456"] },
  mapping,
});
```

## Import new traces on a schedule

A scheduled import keeps learning from production traffic without a change to the agent. An import with a `schedule` is a scheduled import. The filter must contain a time bound, as in a one-time import. Each run reads the traces that match the filter and that changed after the previous run. Zep waits until a trace stops changing before it imports the trace.

**`Python`**

```python Python
scheduled = client.agent.trajectory_import.create(
    agent.uuid_,
    name="Billing production",
    connection_uuid=connection.uuid_,
    provider_project_id=project.id,
    selection={"filter": {"started_after": "2026-10-01T00:00:00Z", "tags_all": ["production"]}},
    schedule={"interval_hours": 4, "start_from": "now"},
    mapping=mapping,
)
```

**`TypeScript`**

```typescript TypeScript
const scheduled = await client.agent.trajectoryImport.create(agent.uuid!, {
  name: "Billing production",
  connectionUuid: connection.uuid,
  providerProjectId: projectId,
  selection: { filter: { startedAfter: "2026-10-01T00:00:00Z", tagsAll: ["production"] } },
  schedule: { intervalHours: 4, startFrom: "now" },
  mapping,
});
```

The interval is 1, 4, 12, or 24 hours. `start_from` is `now` or an RFC 3339 time. To also import earlier traces, set `start_from` to a time in the past. To start a run before the next interval, call `agent.trajectory_import.run.create`.

## Check the results

Each run reports counts of the traces that it imported, updated, skipped, or could not import, and a count for each skip reason. Use `agent.trajectory_import.run.list` and `agent.trajectory_import.run.get` to read the runs. Use `agent.trajectory_import.run.item.list` to read the result and the reason for each trace. A skip is a decision of a mapping rule, for example a trace with no task family. A skip is not an error.

To list the Trajectories of one import, call `agent.trajectory.list` with `import_uuid`. Then follow the [learning state](/agent-skills/learning-and-admission) of the Agent, as you do for captured Trajectories.

## Review imported evidence

Imported Trajectories follow the approval settings of the Agent. To require human review for each candidate that uses evidence from one import, set `require_review=True` on the import. This rule applies also when the Agent `approval` is `auto`. For more about approval, see [Configure Learning and Admission](/agent-skills/learning-and-admission).

## Pause or delete an import

| Task                                        | Method                                                        |
| ------------------------------------------- | ------------------------------------------------------------- |
| Stop the scheduled runs                     | `agent.trajectory_import.pause`                               |
| Start the scheduled runs again              | `agent.trajectory_import.resume`                              |
| Delete the import and keep its Trajectories | `agent.trajectory_import.delete`                              |
| Delete the import and its Trajectories      | `agent.trajectory_import.delete` with `trajectories="delete"` |

When you delete an import, Zep keeps its Trajectories by default. When you set `trajectories="delete"`, Zep deletes them asynchronously. When you delete a trace connection, Zep keeps all of the imported Trajectories.