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

# Python SDK

> Instrument your Python agents with ProvenLog

## Installation

```bash theme={null}
pip install provenlog
```

**Requirements:** Python 3.8+

## Basic usage

```python theme={null}
from provenlog import ProvenLogClient

client = ProvenLogClient(agent_id="my-agent")

client.log_event(
    action_type="TOOL_CALL",
    action_name="search_database",
    action_input={"query": "revenue Q4"},
    action_status="success",
    action_output={"results": 42}
)

client.close()
```

## Client configuration

```python theme={null}
client = ProvenLogClient(
    base_url=None,              # Server URL; None for embedded mode
    agent_id="my-agent",        # Default agent ID for all events
    session_id="session-123",   # Default session ID
    batch_size=100,             # Events per batch
    flush_interval=1.0,         # Seconds between flushes
    timeout=30.0,               # HTTP timeout
    metadata={"env": "prod"},   # Default metadata merged into every event
    labels={"dept": "finance"}, # Default labels merged into every event
    context=None,               # Initial label context for dashboard enrichment
    db_path=None,               # SQLite path (embedded mode)
    api_key=None,               # Bearer token (server mode)
    on_error=None,              # Error callback
)
```

### Environment variables

| Variable               | Description                                                 |
| ---------------------- | ----------------------------------------------------------- |
| `PROVENLOG_SERVER_URL` | Server URL (enables server mode, used by `ProvenLogClient`) |
| `PROVENLOG_URL`        | Server URL (used by `provenlog.auto` / `plog run`)          |
| `PROVENLOG_DB_PATH`    | SQLite path for embedded mode                               |
| `PROVENLOG_API_KEY`    | Bearer token for server auth                                |

## Embedded vs Server mode

```python theme={null}
# Embedded mode (default) — writes to local SQLite
client = ProvenLogClient(agent_id="my-agent")
client = ProvenLogClient(agent_id="my-agent", db_path="/tmp/audit.db")

# Server mode — sends to plog serve
client = ProvenLogClient("http://localhost:7600", agent_id="my-agent")
client = ProvenLogClient("http://localhost:7600", agent_id="my-agent", api_key="your-key")
```

## Logging events

```python theme={null}
# Using keyword arguments
client.log_event(
    action_type="TOOL_CALL",
    action_name="search_database",
    action_input={"query": "revenue Q4"},
    action_output={"results": 42},
    action_status="success",
    duration_ms=150,
    metadata={"model": "claude-sonnet-4-5-20250929"},
    labels={"env": "prod"},
)

# Using a ProvenLogEvent object
from provenlog.event import ProvenLogEvent

event = ProvenLogEvent(
    action_type="LLM_CALL",
    action_name="chat_completion",
    action_input={"prompt": "Hello"},
    action_status="success",
)
client.log_event(event)
```

## Labels and context

### Default labels

Labels passed to the constructor are merged into every event. Event-level labels override defaults for matching keys.

```python theme={null}
client = ProvenLogClient(
    agent_id="loan-processor",
    labels={"env": "prod", "dept": "lending"},
)

# This event will have labels {"env": "prod", "dept": "lending", "loan_id": "LN-2024-4821"}
client.log_event(
    action_type="TOOL_CALL",
    action_name="pull_credit_report",
    action_status="success",
    labels={"loan_id": "LN-2024-4821"},
)
```

### Querying by labels

Events can be filtered by label values using `?label.<key>=<value>` query parameters. Multiple label filters are ANDed together.

```
GET /v1/events?label.env=prod
GET /v1/events?label.env=prod&label.dept=lending
GET /v1/events?agent_id=loan-processor&label.loan_id=LN-2024-4821&limit=50
```

### Label context

Labels are short identifiers, but dashboards often need richer information. `set_context()` attaches business data to a label value for dashboard enrichment — for example, attaching a borrower name and loan amount to a `loan_id`.

```python theme={null}
client = ProvenLogClient(
    agent_id="loan-processor",
    labels={"loan_id": "LN-2024-4821"},
)

client.set_context("loan_id", {
    "borrower": "Alice Rivera",
    "amount": 420000,
    "stage": "underwriting",
})
```

The label key must exist in the client's default labels — otherwise a `ValueError` is raised. The data is sent as a fire-and-forget `PUT /v1/context/{key}/{value}` request (or written to SQLite in embedded mode). Transport errors are logged as warnings and never raise.

Context is keyed by `(label_key, label_value)` and upserted — calling `set_context` again replaces the previous data.

You can also push context at construction time with the `context` parameter:

```python theme={null}
client = ProvenLogClient(
    agent_id="loan-processor",
    labels={"loan_id": "LN-2024-4821", "env": "prod"},
    context={
        "loan_id": {"borrower": "Alice Rivera", "amount": 420000},
        "env": {"display_name": "Production", "region": "us-east-1"},
    },
)
```

## Querying events

```python theme={null}
# List events with filters
events = client.get_events(
    agent_id="my-agent",
    action_type="TOOL_CALL",
    limit=50,
    offset=0,
)

# Get a single event by ID
event = client.get_event("550e8400-e29b-41d4-a716-446655440000")
```

## Verifying integrity

```python theme={null}
result = client.verify("my-agent")
# {"valid": True}
# or {"valid": False, "error": "hash mismatch at sequence 42"}
```

## Batching and async

Events are ingested **non-blocking** via a background thread:

* Batched every **100 events** or **1 second** (whichever comes first)
* Never blocks your agent's execution path
* Flush explicitly with `client.flush()`
* Clean shutdown with `client.close()`

## Context manager

```python theme={null}
with ProvenLogClient(agent_id="my-agent") as client:
    client.log_event(
        action_type="TOOL_CALL",
        action_name="search",
        action_status="success",
    )
# Automatically flushed and closed
```

## PII redaction

In **embedded mode**, redaction is automatic — the client loads redaction rules from your config file on startup. In **server mode**, the server handles redaction.

To add custom redaction rules, create a `provenlog.yaml` config file:

```yaml theme={null}
redaction:
  rules:
    - name: mrn
      pattern: "MRN-\\d{10}"
      replace: "[REDACTED:mrn]"
```

Config file discovery order:

1. `PROVENLOG_CONFIG` environment variable
2. `./provenlog.yaml`
3. `~/.provenlog/config.yaml`

You can also use the `Redactor` class directly for standalone redaction:

```python theme={null}
from provenlog import Redactor

redactor = Redactor.default()
clean, count = redactor.redact_string("Contact john@example.com")
# clean = "Contact [REDACTED:email]", count = 1
```

See [PII Redaction](/features/pii-redaction) for the full list of built-in patterns.
