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

# Setup

> Get started with ZeroEval tracing in Python applications

The [ZeroEval Python SDK](https://pypi.org/project/zeroeval/) provides seamless integration with your Python applications through automatic instrumentation and a simple decorator-based API.

## Installation

<CodeGroup>
  ```bash pip theme={null}
  pip install zeroeval
  ```

  ```bash poetry theme={null}
  poetry add zeroeval
  ```
</CodeGroup>

## Basic Setup

```python theme={null}
import zeroeval as ze

# Option 1: ZEROEVAL_API_KEY in your environment variable file
ze.init()

# Option 2: Provide API key directly from
#           https://app.zeroeval.com/settings?tab=api-keys
ze.init(api_key="YOUR_API_KEY")
```

<Note>
  Run `zeroeval setup` once to save your API key securely to
  `~/.config/zeroeval/config.json`
</Note>

<Tip>
  Need source-side PII redaction? Pass `redaction={"enabled": True}` to
  `ze.init(...)` or set `ZEROEVAL_REDACT_PII=true`. See [PII
  redaction](/tracing/pii-redaction).
</Tip>

## Patterns

### Decorators

The `@span` decorator is the easiest way to add tracing:

```python theme={null}
import zeroeval as ze

@ze.span(name="fetch_data")
def fetch_data(user_id: str):
    # Function arguments are automatically captured as inputs
    # Return values are automatically captured as outputs
    return {"user_id": user_id, "name": "John Doe"}

@ze.span(name="process_data", attributes={"version": "1.0"})
def process_data(data: dict):
    # Add custom attributes for better filtering
    return f"Welcome, {data['name']}!"
```

### Context Manager

For more control over span lifecycles:

```python theme={null}
import zeroeval as ze

def complex_workflow():
    with ze.span(name="data_pipeline") as pipeline_span:
        # Fetch stage
        with ze.span(name="fetch_stage") as fetch_span:
            data = fetch_external_data()
            fetch_span.set_io(output_data=str(data))

        # Process stage
        with ze.span(name="process_stage") as process_span:
            processed = transform_data(data)
            process_span.set_io(
                input_data=str(data),
                output_data=str(processed)
            )

        # Save stage
        with ze.span(name="save_stage") as save_span:
            result = save_to_database(processed)
            save_span.set_io(output_data=f"Saved {result} records")
```

### Artifact Spans

When a single prompt run produces multiple judged outputs (e.g. a final decision and a customer card), use `ze.artifact_span` to mark each output as a named artifact. The prompt completions page surfaces the primary artifact as the row preview and lets you switch between artifacts in the detail view.

```python theme={null}
import zeroeval as ze

def resolve_ticket(ticket):
    with ze.span(name="resolve-ticket"):
        system_prompt = ze.prompt(name="support-copilot", content="...")
        decision = run_agent(system_prompt, ticket)

        with ze.artifact_span(
            name="final-decision",
            artifact_type="final_decision",
            role="primary",
            label="Final Decision",
            tags={"judge_target": "support_ops_final_decision"},
        ) as s:
            s.set_io(input_data=ticket.body, output_data=decision.json())

        with ze.artifact_span(
            name="customer-card",
            artifact_type="customer_card",
            role="secondary",
            label="Customer Card",
            tags={"has_customer_card": "true"},
        ) as card:
            card.set_io(input_data=ticket.summary, output_data=decision.json())
            card.add_image(base64_data=render_card(decision))
```

`artifact_span` defaults to `kind="llm"` and writes the `completion_artifact_*` attributes automatically. All other `ze.span` features (tags, sessions, prompt metadata inheritance) work the same way.

<Note>
  `ze.artifact_span` is available in the **Python SDK only** for now.
</Note>

## Advanced Configuration

Fine-tune the tracer behavior:

```python theme={null}
from zeroeval.observability.tracer import tracer

# Configure tracer settings
tracer.configure(
    flush_interval=5.0,        # Flush every 5 seconds
    max_spans=200,             # Buffer up to 200 spans
    collect_code_details=True  # Capture source code context
)
```

## Context

Access current context information:

```python theme={null}
# Get the current span
current_span = ze.get_current_span()

# Get the current trace ID
trace_id = ze.get_current_trace()

# Get the current session ID
session_id = ze.get_current_session()
```

## Sessions

Sessions group related spans together, making it easier to track complex workflows, user interactions, or multi-step processes.

### Basic Session

Provide a session ID to associate spans with a session:

```python theme={null}
import uuid
import zeroeval as ze

session_id = str(uuid.uuid4())

@ze.span(name="process_request", session=session_id)
def process_request(data):
    return transform_data(data)
```

### Named Sessions

For better organization in the dashboard, provide both an ID and a name:

```python theme={null}
@ze.span(
    name="user_interaction",
    session={
        "id": session_id,
        "name": "Customer Support Chat - User #12345"
    }
)
def handle_support_chat(user_id, message):
    return generate_response(message)
```

### Session Inheritance

Child spans automatically inherit the session from their parent:

```python theme={null}
session_info = {
    "id": str(uuid.uuid4()),
    "name": "Order Processing Pipeline"
}

@ze.span(name="process_order", session=session_info)
def process_order(order_id):
    validate_order(order_id)
    charge_payment(order_id)
    fulfill_order(order_id)

@ze.span(name="validate_order")
def validate_order(order_id):
    return check_inventory(order_id)

@ze.span(name="charge_payment")
def charge_payment(order_id):
    return process_payment(order_id)
```

### Context Manager Sessions

```python theme={null}
session_info = {
    "id": str(uuid.uuid4()),
    "name": "Data Pipeline Run"
}

with ze.span(name="etl_pipeline", session=session_info) as pipeline_span:
    with ze.span(name="extract_data") as extract_span:
        raw_data = fetch_from_source()
        extract_span.set_io(output_data=f"Extracted {len(raw_data)} records")

    with ze.span(name="transform_data") as transform_span:
        clean_data = transform_records(raw_data)
        transform_span.set_io(
            input_data=f"{len(raw_data)} raw records",
            output_data=f"{len(clean_data)} clean records"
        )
```

## Tags

Tags are key-value pairs attached to spans, traces, or sessions. They power the facet filters in the console so you can slice your telemetry by user, plan, model, tenant, or anything else.

### Tag Once, Inherit Everywhere

Tags on the first span automatically flow down to all child spans:

```python theme={null}
@ze.span(
    name="handle_request",
    tags={
        "user_id": "42",
        "tenant": "acme-corp",
        "plan": "enterprise"
    }
)
def handle_request():
    with ze.span(name="fetch_data"):
        ...

    with ze.span(name="process", tags={"stage": "post"}):
        ...
```

### Tag a Single Span

Tags provided on a specific span stay only on that span -- they are not copied to siblings or parents:

```python theme={null}
@ze.span(name="top_level")
def top_level():
    with ze.span(name="db_call", tags={"table": "customers", "operation": "SELECT"}):
        query_database()

    with ze.span(name="render"):
        render_template()
```

### Granular Tagging

Add tags at the span, trace, or session level after creation:

```python theme={null}
with ze.span(name="root_invoke", session=session_info, tags={"run": "invoke"}):
    current_span = ze.get_current_span()
    ze.set_tag(current_span, {"phase": "pre-run"})

    current_trace = ze.get_current_trace()
    ze.set_tag(current_trace, {"run_mode": "invoke"})

    current_session = ze.get_current_session()
    ze.set_tag(current_session, {"env": "local"})
```

## Feedback

To attach human or programmatic feedback to completions, see [Human Feedback](/feedback/human-feedback) and the [Feedback SDK docs](/feedback/python). For automated quality evaluations, see [Judges](/judges/introduction).

## CLI Tooling

The Python SDK includes helpful CLI commands:

```bash theme={null}
# Save your API key securely
zeroeval setup

# Run scripts with automatic tracing
zeroeval run my_script.py
```
