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

# OTEL Guard

The Mima runtime guard detects unattested AI calls and reports them via
OpenTelemetry, a local daemon socket, or a JSONL report file.

It answers the question: *"Are there AI calls in my codebase that are
not wrapped with `@mima.attest()`?"*

---

## Install

```bash
pip install "mima-governance[otel]"
```

The `otel` extra adds `opentelemetry-api` and `opentelemetry-sdk`.

---

## Enable at startup

Call `enable_guard()` once at your application entry point, before any AI
clients are instantiated.

```python
from mima_governance.guard import enable_guard

enable_guard(mode="warn")   # "warn" | "block" | "report"
```

### Modes

| Mode       | Behaviour                                                                               |
| ---------- | --------------------------------------------------------------------------------------- |
| `"warn"`   | `UserWarning` on every unattested call. Non-disruptive in production.                   |
| `"block"`  | Raises `MimaAttestationError`. Use in tests to catch gaps before they reach production. |
| `"report"` | Silent logging to `~/.mima/guard_log.jsonl`. Use for audit-only runs.                   |

---

## What the guard detects

The guard patches the `__init__` method of the following AI client classes:

| Library     | Classes patched                 |
| ----------- | ------------------------------- |
| `openai`    | `OpenAI`, `AsyncOpenAI`         |
| `anthropic` | `Anthropic`, `AsyncAnthropic`   |
| `litellm`   | `completion()`, `acompletion()` |

When one of these is called outside a function decorated with `@mima.attest()`,
the guard fires.

---

## How it works with `@mima.attest()`

The `@mima.attest()` decorator sets an "attested" flag before the decorated
function runs and clears it afterwards. The guard checks this flag on every
patched AI client call.

```python
enable_guard(mode="block")

mima = MimaGovernance(api_key="...", system_name="my-system")

# This is fine — the guard sees the attested flag:
@mima.attest(tool_name="classify")
def classify(text):
    return openai_client.chat.completions.create(...)  # OK

# This raises MimaAttestationError in block mode:
def unguarded():
    return openai_client.chat.completions.create(...)  # BLOCKED
```

Thread safety: the attested flag uses `threading.local`, so each thread has
its own value. Concurrent threads do not interfere with each other.

Async safety: async calls use a `contextvars.ContextVar`. Each asyncio task
inherits a copy of the context, so concurrent tasks are isolated.

---

## OpenTelemetry integration

When a real `TracerProvider` is configured (not the default no-op), the guard
emits `mima.works_call` spans for every unattested call.

```python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# Configure your OTEL SDK:
provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(provider)

# Now enable the guard:
from mima_governance.guard import enable_guard
enable_guard(mode="warn")
```

### Span attributes

| Attribute           | Value                                                    |
| ------------------- | -------------------------------------------------------- |
| `mima.call_site`    | Name of the patched method (e.g. `"openai.OpenAI.chat"`) |
| `mima.attested`     | `false` — span only emitted for unattested calls         |
| `mima.workspace_id` | Your workspace ID (if configured via `mima login`)       |

---

## Report mode — `~/.mima/guard_log.jsonl`

In `"report"` mode, every unattested call is written to
`~/.mima/guard_log.jsonl` as a JSONL record:

```json
{"ts": "2026-06-28T09:14:22Z", "call_site": "anthropic.Anthropic.messages", "attested": false}
```

The file rotates at 10 MB (3 backups kept).

Review the log directly:

```bash
cat ~/.mima/guard_log.jsonl
tail -f ~/.mima/guard_log.jsonl   # live tail
```

---

## Use in CI — catch gaps before production

Add `enable_guard(mode="block")` to your test configuration. This causes
the test suite to fail fast whenever an AI call is made outside
`@mima.attest()`, preventing unattested calls from reaching production.

```python
# conftest.py
from mima_governance.guard import enable_guard
enable_guard(mode="block")
```

Then run your tests normally. Any unattested AI call raises `MimaAttestationError`
and the test fails with a clear message.

---

## Detection fallback chain

1. If a real `TracerProvider` is configured → emit `mima.works_call` OTEL span.
2. Else if the Mima daemon socket is available → send to local daemon.
3. Else → in-process queue + background thread → JSONL report.

The fallback chain ensures the guard always works, even without an OTEL
collector or Mima daemon running.

---

## Supported AI libraries

The guard patches these libraries automatically at runtime when they are installed:

* `openai` >= 1.0
* `anthropic` >= 0.20
* `litellm` >= 1.0 — routes all other providers (Gemini, Mistral, Cohere, DeepSeek, Qwen, Kimi, and more)

For any other library, use `mima.wrap()` / `@mima.attest()` directly — the guard does not need to detect those calls because they are already attested.

For static detection across all libraries — including Gemini, DeepSeek, Kimi, Qwen, and any custom wrapper — use `mima scan`. It detects unattested call sites via AST analysis regardless of which SDK you use.

---

## Disabling the guard

```python
from mima_governance.guard import disable_guard
disable_guard()
```

Or use per-call:

```python
from mima_governance.guard import _set_attested
_set_attested(True)
response = openai_client.chat.completions.create(...)  # won't trigger guard
_set_attested(False)
```

Prefer `@mima.attest()` over manual flag manipulation.