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

# Python SDK

> Reference for the overmind package — init(), provider auto-instrumentation, the run boundary, span decorators, behaviours and capabilities, and runtime expectations.

The `overmind` package instruments your LLM stack over OpenTelemetry and exports spans to Overmind. One `init()` call captures every supported provider call automatically; `run()` brackets one agent run; decorators trace the code around the model calls; a few one-line calls declare what the run was asked to do and what it delivered, which is what [trace scoring](/agent-testing/trace-scoring) judges.

```bash theme={"dark"}
pip install "overmind[tracing]"   # the tracing SDK, every provider instrumentor, LangChain coverage
pip install overmind              # the `overmind` CLI and the inference client only
```

The base package is the [CLI](/platform/cli) and the OpenAI-compatible [inference client](/models/inference#calling-your-model). Tracing is the one extra: on a bare install, accessing `overmind.init` or any tracing name raises `ImportError` with the install line to run. There are no other extras.

## `init()`

Call once at process startup, before any LLM call. Idempotent and thread-safe — calling again refreshes identity, enables more `providers`, and updates the orphan-export policy without rebuilding the exporter. Without an API key it logs once, returns `False`, and every decorator and helper below becomes a no-op; set `OVERMIND_STRICT_MODE=true` to make a missing key raise.

```python theme={"dark"}
import overmind

overmind.init(
    service_name="my-service",
    environment="production",
    providers="auto",
    capability_id="support-triage",  # the capability's UUID, or its slug from overmind.toml
)
```

| Parameter             | Type                       | Description                                                                                                                                                                                                                                         |
| --------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `overmind_api_key`    | `str \| None`              | The first positional argument. Resolution order: the argument, `.overmind/credentials.toml` (written by `overmind sync`; used only when its `project-id` and `base-url` match `overmind.toml`), then `OVERMIND_API_KEY`                             |
| `service_name`        | `str \| None`              | `service.name` on the resource; falls back to `OVERMIND_SERVICE_NAME`, then `overmind-telemetry`                                                                                                                                                    |
| `environment`         | `str \| None`              | `deployment.environment` on the resource; falls back to `OVERMIND_ENVIRONMENT`, `ENVIRONMENT`, then `development`                                                                                                                                   |
| `providers`           | `list[str] \| str \| None` | `"auto"` instruments every provider whose library and instrumentor are both installed; a list pins the set (`"openai"`, `"anthropic"`, `"google"`, `"agno"`, `"langchain"`); `[]` enables all known; omit to enable none                            |
| `overmind_base_url`   | `str \| None`              | Falls back to `OVERMIND_API_URL`, `overmind.toml` `base-url`, then `https://api.overmindlab.ai`                                                                                                                                                     |
| `capability_id`       | `str \| None`              | Stamped as `overmind.capability.id`, the only key ingest binds by. Accepts the capability's UUID or its slug from `overmind.toml`; without a local manifest the slug is sent as-is and resolves server-side. Falls back to `OVERMIND_CAPABILITY_ID` |
| `capability`          | `str \| None`              | Display label, stamped as `overmind.capability.name`; never resolves a capability. Falls back to `OVERMIND_CAPABILITY_NAME`                                                                                                                         |
| `project_id`          | `str \| None`              | Project UUID (`overmind.project.id`), only needed for account-scoped keys or session auth; falls back to `OVERMIND_PROJECT_ID`, then `overmind.toml`                                                                                                |
| `redact_keys`         | `Iterable[str] \| None`    | Extra dict keys (exact match, case-insensitive) redacted from captured payloads, beyond the built-in secret-name patterns                                                                                                                           |
| `export_orphan_spans` | `bool`                     | Export `function` spans that start a trace outside any run boundary (dropped by default)                                                                                                                                                            |
| `debug`               | `bool`                     | Logs the endpoint, resolved identity, enabled instrumentors, and export mode, and raises the `overmind` logger to DEBUG                                                                                                                             |

Passing either `capability_id` or `capability` suppresses the env fallback for both — a declared half never picks up the other from the environment.

Environment variables: `OVERMIND_API_KEY`, `OVERMIND_API_URL`, `OVERMIND_SERVICE_NAME`, `OVERMIND_ENVIRONMENT`, `OVERMIND_CAPABILITY_ID`, `OVERMIND_CAPABILITY_NAME`, `OVERMIND_PROJECT_ID`, `OVERMIND_STRICT_MODE`; `OVERMIND_SPAN_FLUSH_INTERVAL_MS` (default 2000) and `OVERMIND_SPAN_MAX_EXPORT_BATCH_SIZE` (default 256) tune the batch exporter; `OVERMIND_GIT_SHA` overrides commit detection (then `GIT_SHA`, `GIT_COMMIT`, `GITHUB_SHA`, `RENDER_GIT_COMMIT`, `VERCEL_GIT_COMMIT_SHA`, `HEROKU_SLUG_COMMIT`, `CI_COMMIT_SHA`, then `.git/HEAD`); `SERVICE_VERSION` sets `service.version`; a `TRACEPARENT` env var is attached as the remote parent. In a repository where `overmind sync` has run, the SDK reads the key from `.overmind/credentials.toml` and the API URL and project id from `overmind.toml`. Deployments provide credentials through their runtime secret configuration.

After `init()`, calls made with the OpenAI, Anthropic, Google Gemini, Agno, and LangChain client libraries produce `llm_call` spans automatically, capturing messages and tool calls, model and request parameters, token usage, latency, and errors. Spans export via a batching OTLP/HTTP exporter to `POST {base_url}/api/v1/traces` with the key in `X-Api-Key`. The resource carries `vcs.ref.head.revision`, so a unit binds to the behaviour contract analysed at that commit.

If the app already owns an OpenTelemetry `TracerProvider`, skip `init()`, add an OTLP exporter for the endpoint to that provider, and call `overmind.tracing.enable_tracing(providers)`: it attaches the SDK's stamping and usage processors to the existing provider and enables the instrumentors, so decorators and `run()` work unchanged.

## `run()` — the run boundary

Every agent execution needs exactly one run boundary. `run()` is the one scope that covers it: capability identity, the entry-point span (`overmind.unit_kind = "run"`), the intent, the conversation id, tags, error status, and a flush on exit. Use it as a context manager or as a decorator on the entry point:

```python theme={"dark"}
with overmind.run("triage-run", intent=request["question"], conversation_id=ticket_id) as run:
    answer = agent.invoke(request)
    run.deliver(answer)  # the terminal deliverable
```

```python theme={"dark"}
class Agent:
    @overmind.run(
        intent=lambda self, *a, **k: self.task,
        conversation_id=lambda self, *a, **k: self.task_id,
    )
    async def run(self): ...
```

| Parameter                      | Description                                                                                                                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                         | Span name; defaults to `"run"` as a context manager and to the function's qualified name as a decorator                                                                                           |
| `capability` / `capability_id` | The capability this run belongs to. When both are omitted, `OVERMIND_CAPABILITY_ID` / `OVERMIND_CAPABILITY_NAME` fill them; with no identity anywhere, the ambient identity from `init()` applies |
| `intent`                       | What the user asked for; judges ground in it                                                                                                                                                      |
| `conversation_id`              | Groups this run into a [session](/core/observability#sessions)                                                                                                                                    |
| `tags`                         | Attributes stamped on the run span                                                                                                                                                                |

As a decorator, every parameter except `name` also accepts a callable receiving the wrapped call's arguments, resolved per invocation (a failing callable resolves to `None`). The run span carries the function's `code.namespace` / `code.function.name`, so one decoration also satisfies the entry-point anchor a scanned behaviour expects. An exception marks the run span failed and re-raises; the exporter is flushed either way. The return value is not delivered automatically: call `deliver()` (or the handle's `run.deliver()`) inside the unit that produced it.

A `function` span (the `@observe` and `start_span` default) that would start its own trace **outside** a run boundary is dropped as an orphan fragment, and the SDK warns once. Boundary spans, `@tool` / `@workflow` roots, auto-instrumented roots, and spans continuing a remote `TRACEPARENT` still export. If a trace is missing, add the bracket — do not reach for `export_orphan_spans`.

## `deliver()` — the terminal deliverable

```python theme={"dark"}
overmind.deliver(payload, *, grounded_by=None, name="deliver", provenance="agent")
```

Captures the run's result on its own child span: the payload is serialised into `outputs` and the span is stamped `overmind.delivery = true`. Trace scoring judges this span as the unit's terminal. `grounded_by` names the evidence spans the deliverable rests on (span-id hex strings or span handles), written as `overmind.grounded_by`; when omitted, the environment-provenance spans (tools, retrieval) collected in the current trace are used, so call it inside the run.

## Tracing your own code

Auto-instrumentation only sees model calls. Wrapping the code around them — tools, retrieval steps, the phases of a run — turns flat spans into a tree that mirrors your agent's structure, and gives trace scoring the anchors it binds to.

### Span types

```python theme={"dark"}
from overmind import SpanType
```

| `SpanType`             | Attribute value | Meaning                                                    |
| ---------------------- | --------------- | ---------------------------------------------------------- |
| `SpanType.ENTRY_POINT` | `entry_point`   | The run root (`overmind.unit_kind = "run"`); one per trace |
| `SpanType.WORKFLOW`    | `workflow`      | A multi-step process or pipeline                           |
| `SpanType.TOOL`        | `tool_call`     | A tool or function the agent invokes                       |
| `SpanType.RETRIEVAL`   | `retrieval`     | A RAG / vector-search step                                 |
| `SpanType.FUNCTION`    | `function`      | Any other traced function (the default)                    |
| `SpanType.LLM`         | `llm_call`      | A model call (set by auto-instrumentation)                 |

The value lands in `overmind.span.type`; ingest stores it verbatim.

### Decorators

`@observe` is the general decorator; `@entry_point`, `@workflow`, `@tool`, and `@retrieval` are typed shortcuts. All work on sync and async functions, record duration and status, and re-raise exceptions after recording them. An `@entry_point` interrupted by `KeyboardInterrupt` or cancellation force-flushes before re-raising, so the run still lands.

```python theme={"dark"}
import overmind

@overmind.tool(ignore=("session",))  # tool evidence; `session` is never captured
def search(query: str, session) -> list[dict]: ...

@overmind.observe(type="llm", capture="messages")  # full chat evidence
def call_model(messages: list[dict]) -> dict: ...

@overmind.workflow()
def research(topic: str) -> str:
    return summarise(search(topic, session))
```

| Option                           | Meaning                                                                                                                                                            |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `span_name`                      | Span name (first positional); defaults to the function's qualified name. May be a callable receiving the call's arguments                                          |
| `type`                           | A `SpanType`, its wire value (`"tool_call"`), or its short name (`"tool"`, `"llm"`, `"entry_point"`)                                                               |
| `capture`                        | `"auto"` (scrubbed args and result — the default), `"none"`, or `"messages"` (normalise the `messages` argument and a list result into role/content chat evidence) |
| `ignore`                         | Argument names never captured (sessions, clients, model handles)                                                                                                   |
| `format_input` / `format_output` | `fn(bound_args)` / `fn(result, bound_args)` hooks that replace the captured payload                                                                                |
| `provenance`                     | Evidence class for judges: `user`, `agent`, `environment`, `harness`. Tool and retrieval spans get `environment` and LLM spans `agent` automatically               |
| `unit`                           | `"turn"` marks the span as an independently scored unit; `"run"` is set by `entry_point`                                                                           |
| `capability`                     | Capability slug or display name for the scope, stamped as `overmind.capability.name`; a differing identity mid-trace marks a handoff. It never binds on its own    |
| `capability_id`                  | The capability's UUID — the key ingest binds the span and its children by                                                                                          |

Captured arguments land in the `inputs` attribute and the return value in `outputs`, both as JSON. Payloads are scrubbed: keys containing `password`, `secret`, `token`, `credential`, `authorization`, `api_key`, `apikey`, or `sensitive` are redacted, data URLs and base64-looking strings of 512+ characters become placeholders, byte strings over 256 bytes become placeholders, dataclasses and Pydantic models are dumped, and text is kept in full. For code that handles credentials, use `capture="none"` — and prefer masking values before they reach traced functions. `normalize_messages` is exported for callers that build chat evidence themselves.

The span name may be a callable receiving the call's arguments — for a polymorphic dispatcher, each invocation then emits its own tool span and `tool.name` follows the resolved action:

```python theme={"dark"}
class Tools:
    @overmind.tool(name=lambda self, action, **params: action.name)
    def act(self, action, **params): ...
```

Every decorated span carries the function's `code.namespace` / `code.function.name`; tool spans add `tool.name` and `tool.arg_keys`.

<Tip>
  Decorate every function the scan anchors on. An undecorated anchor emits no `code.namespace` / `code.function.name`, so the behaviour it belongs to never binds and its step judges skip it.
</Tip>

### Instrumenting a scanned repository

After `overmind sync`, each capability's behaviours carry the anchors trace scoring binds to. The `get_instrumentation_plan` MCP tool turns them into tickets: call it with no capability for project-wide work, or with a capability and optional behaviour for a scoped change. Each ticket names the target file and qualname, import line, required scope, required decorators, capability id, behaviour key, version, and grain. Apply the placements verbatim so the resulting spans bind to the pushed contracts; the `/overmind ensure-tracing` command does exactly this. A missing registry means capabilities have not been synced — run `/overmind setup` then `overmind sync` first.

Two identity forms tie code to a capability declared in `overmind.toml`:

* `overmind.init(capability_id="<slug>")` (or `run(capability_id=...)`) — ingest binds by the capability's UUID; a slug resolves server-side.
* `@overmind.capability("<slug>", id="...")` on an entry function — at runtime the name is a label only; pass `id=` or set `capability_id` in `init()` to bind.

Verification is a bounded, read-only MCP smoke: run with a unique `conversation_id`, flush, find the trace with `query_traces(session=..., all_spans=true)`, read `overmind://traces/{trace_id}`, and hand its spans to `verify_instrumentation`, which checks capability attribution, nesting, inputs and outputs, usage, and timing without writing traces or scores.

### `task()` — carve a run into units

`task(key, unit="turn")` makes a phase an independently scored unit bound to a declared behaviour; `key` is the behaviour's key (its slug — the mode id from the scan). Re-entering the same key re-uses the still-open turn span, so a re-entrant phase (a tool loop, debate rounds) lands in one unit; the span ends when the run-boundary span ends. Without `unit`, `task()` only stamps `overmind.behaviour.key` on the spans inside. `unit` accepts `"turn"` only — run boundaries come from `run()` / `entry_point`.

```python theme={"dark"}
with overmind.task("investment-debate", unit="turn"):
    ...  # spans here nest under the debate's turn unit
```

Rules that matter: call `deliver()` inside the unit that produced the deliverable; internal fan-out, retries, and loop bodies must not declare `unit`.

### `capability()` — multi-capability agents

`capability(name=None, *, id=None)` declares that all work inside belongs to one capability: every span created inside carries `overmind.capability.id` / `.name`, and the outer identity is restored on exit. It works as a context manager (`with` / `async with`) or a decorator. `id` — the capability's UUID — is the binding; a name-only scope labels the spans and leaves them unbound. Entering a different capability mid-trace (by id, or by name on the slug grain) is a **handoff** — the first span of the new scope is stamped `overmind.unit_kind = "turn"`, so the platform scores it as a new unit against that capability's eval set. Only declared identities are stamped; nothing is created.

```python theme={"dark"}
with overmind.capability("dom-element-locator", id="..."):
    locate(prompt)
```

### `start_span()` — blocks and loops

```python theme={"dark"}
start_span(name, span_type=SpanType.FUNCTION, attributes=None, *, provenance=None, unit=None)
```

A context manager for regions that aren't whole functions. It opens a child span under whatever span is active and captures nothing automatically — attach metadata via `attributes` or `set_tag()`. Before `init()` it yields a non-recording span.

```python theme={"dark"}
from overmind import start_span, set_tag, SpanType

for i, doc in enumerate(documents):
    with start_span("process_document", span_type=SpanType.FUNCTION, attributes={"doc.index": i}):
        result = process(doc)
        set_tag("doc.tokens", result.tokens)
```

### LangChain / LangGraph

`providers=["langchain"]` (or `"auto"`) mounts the OpenInference LangChain instrumentor that ships with `overmind[tracing]`, which covers LangGraph: every chain, model, and tool invocation gets a span with model, token, and cost evidence. For the scoring semantics no instrumentor can know, `overmind.integrations.langgraph.bind` maps graph nodes to behaviour units — call it on the `StateGraph` after `add_node()`, before `compile()`:

```python theme={"dark"}
from overmind.integrations import langgraph as overmind_langgraph

overmind_langgraph.bind(
    workflow,
    # Default key per node: the slugified node name. Override where the scan
    # groups nodes differently; None opts a node out.
    behaviours={"Bull Researcher": "investment-debate", "Bear Researcher": "investment-debate"},
    deliver="Portfolio Manager",  # this node's return value is the deliverable
)
app = workflow.compile()
```

Each node runs inside `task(key, unit="turn")`; nodes backed by your own function also get an `@observe(capture="none")` span carrying that function's code identity.

## Runtime expectations

These declare evidence the platform evaluates server-side; each is a span event (`overmind.eval.*`, with a JSON payload) on the current span and a no-op when nothing is recording.

| Call                                                        | Effect                                                                                                                                                                                                                                                                                                                                                                                                              |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `intent(text, *, source="declared")`                        | What the user asked for in this run. Undeclared runs fall back to the first user message                                                                                                                                                                                                                                                                                                                            |
| `expect(kind, spec, *, id=None, scope="trace", gate=False)` | A runtime expectation — `"contains"` or `"regex"` over the output, `"schema"` with required keys, `"constraint"` with a plain-language rule, or `"checkpoints"` with an ordered list of names — checked when the trace is scored; `scope` is `span`, `trace`, or `conversation`; `gate=True` makes a miss cap the score. `id` defaults to a hash of kind and spec; an unknown `kind` or `scope` raises `ValueError` |
| `checkpoint(name)`                                          | A named trajectory milestone the run must reach                                                                                                                                                                                                                                                                                                                                                                     |
| `eval_context(**facts)`                                     | Facts the judge may use; values are coerced like `set_tag`                                                                                                                                                                                                                                                                                                                                                          |
| `end_conversation()`                                        | Signals the conversation is complete and triggers conversation-scope scoring                                                                                                                                                                                                                                                                                                                                        |

```python theme={"dark"}
with overmind.run("triage", intent=question) as run:
    overmind.expect("schema", {"required_keys": ["category", "summary"]}, id="triage-shape", gate=True)
    overmind.expect("constraint", "Never promise a refund amount.", id="no-refund-promise")
    result = triage(question)
    overmind.checkpoint("classified")
    run.deliver(result)
```

How the platform uses them is on [Trace scoring](/agent-testing/trace-scoring#runtime-expectations-from-the-sdk).

## Context helpers

All operate on the current span or context — call them inside a traced function or request handler.

| Helper                                         | Effect                                                                                                                       |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `set_conversation_id(id)`                      | Stamp `conversation.id` on every subsequent span, grouping traces into a [session](/core/observability#sessions)             |
| `set_workflow_name(name)`                      | Label every subsequent span with a Traceloop-compatible workflow name                                                        |
| `set_user(user_id, email=None, username=None)` | Set `user.id`, `user.email`, `user.username` on the current span                                                             |
| `set_tag(key, value)`                          | Attach filterable metadata to the current span; rich values are JSON-encoded                                                 |
| `capture_exception(exc)`                       | Record a handled exception and mark the span as an error                                                                     |
| `force_flush_traces()`                         | End every open turn span, then flush; call it before scripts and serverless handlers exit when nothing else brackets the run |
| `overmind.tracing.flush_traces()`              | Flush buffered spans without ending open turn spans — what `run()` does on exit                                              |
| `overmind.tracing.get_tracer()`                | The raw OpenTelemetry tracer for span lifetimes that don't fit one block; raises before `init()`                             |

```python theme={"dark"}
from fastapi import FastAPI, Request
from overmind import set_user

app = FastAPI()

@app.middleware("http")
async def add_user_context(request: Request, call_next):
    user = getattr(request.state, "user", None)
    if user:
        set_user(user_id=user.id, email=user.email)
    return await call_next(request)
```

## `PromptString` — explicit prompt structure

`PromptString` (re-exported from the `opentelemetry-overmind` package that ships with the tracing extra) is a `str` subclass that keeps the template and its arguments. When a provider instrumentor sees one in a request, it stamps `overmind.prompt.template` and `overmind.prompt.kwargs` on the `llm_call` span, and the eval envelope hands the template and rendered prompt to the judges.

```python theme={"dark"}
from overmind import PromptString

system_prompt = PromptString(
    id="support_greeter_v1",
    template="You are a helpful support agent. Your name is {agent_name}.",
    kwargs={"agent_name": "Astra"},
)
```

Use one `PromptString` per LLM call — the instrumentor raises `ValueError` when it finds more.

## Full example

```python theme={"dark"}
import overmind
from openai import OpenAI

overmind.init(
    service_name="customer-support",
    environment="production",
    providers="auto",
    capability_id="support-triage",
)

client = OpenAI()

@overmind.tool()
def lookup_order(order_id: str) -> dict:
    return {"id": order_id, "status": "shipped"}

@overmind.run(
    intent=lambda user_id, question: question,
    conversation_id=lambda user_id, question: user_id,
)
def handle_support_query(user_id: str, question: str) -> str:
    overmind.set_user(user_id=user_id)
    order = lookup_order("A-1001")
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful customer support agent."},
            {"role": "user", "content": f"{question}\n\nOrder: {order}"},
        ],
    )
    answer = response.choices[0].message.content
    overmind.deliver(answer)
    return answer
```

One trace: the `handle_support_query` run → `lookup_order` (tool, environment evidence) → the OpenAI `llm_call` → the `deliver` span, attributed to the `support-triage` capability, grouped into the user's session, with the question as its intent. Trace scoring binds it to the capability's behaviour and judges the delivered answer against the eval set.
