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

# Python SDK

> Wire the Sector8 Guard Module into your LLM application in minutes

## Installation

```bash theme={null}
pip install sector8-sdk
```

Requires Python 3.10+.

## Authentication

```bash theme={null}
export SECTOR8_API_KEY=your_api_key_here
export SECTOR8_CLIENT_ID=your_client_id
```

Or pass directly:

```python theme={null}
from sector8 import GuardClient

client = GuardClient(
    api_key="your_api_key_here",
    client_id="your_client_id",
)
```

## Evaluate a tool call

```python theme={null}
from sector8 import GuardClient, ToolCallRequest

client = GuardClient()

result = client.evaluate(
    ToolCallRequest(
        tool_name="bash",
        arguments={"command": "ls -la /home"},
        session_id="session-abc123",
        user_id="engineer-42",
    )
)

if result.decision == "ALLOW":
    output = execute_bash(result.request.arguments["command"])
else:
    print(f"Blocked: {result.reason_code}")
    print(f"Evidence hash: {result.evidence_hash}")
    print(f"Trace ID: {result.decision_trace_id}")
```

## Drop-in wrapper for existing agents

Replace your existing tool dispatch with this single function:

```python theme={null}
from sector8 import GuardClient, ToolCallRequest
from sector8.exceptions import AdmissionDeniedError

client = GuardClient()

def guarded_tool_call(tool_name: str, arguments: dict, session_id: str):
    result = client.evaluate(
        ToolCallRequest(
            tool_name=tool_name,
            arguments=arguments,
            session_id=session_id,
        )
    )

    if result.decision == "DENY":
        raise AdmissionDeniedError(
            reason=result.reason_code,
            evidence_hash=result.evidence_hash,
            trace_id=result.decision_trace_id,
        )

    return dispatch_tool(tool_name, arguments)
```

## Multi-turn session protection

Pass a consistent `session_id` across turns to enable escalation scoring. After repeated denied turns in a session, subsequent calls are blocked even if per-turn content looks benign.

```python theme={null}
SESSION_ID = "session-abc123"

for turn in conversation:
    result = client.evaluate(
        ToolCallRequest(
            tool_name=turn.tool,
            arguments=turn.args,
            session_id=SESSION_ID,  # same ID every turn
        )
    )
```

## Admission decision object

```python theme={null}
@dataclass
class AdmissionDecision:
    decision:             str          # "ALLOW" | "DENY"
    reason_code:          str | None   # e.g. "SHELL_INJECTION_BLOCKED"
    evidence_hash:        str | None   # SHA-256 of blocked payload
    has_forensic_payload: bool         # True on all DENY records
    policy_version_id:    str          # HMAC-SHA256 signed bundle hash
    decision_trace_id:    str          # Full trace linkage UUID
    semantic_score:       float | None # 0.0–1.0 if semantic engine ran
    pre_filter_decision:  str | None   # "BLOCK" | "PASS" | "REVIEW"
```

## Error handling

```python theme={null}
from sector8.exceptions import (
    AdmissionDeniedError,
    PolicyVersionMismatchError,
    GuardClientError,
)

try:
    result = client.evaluate(request)
except AdmissionDeniedError as e:
    # Blocked — safe to log and continue
    logger.warning(f"Blocked: {e.reason} | trace: {e.trace_id}")
except PolicyVersionMismatchError:
    # Policy bundle changed — re-fetch before retrying
    client.refresh_policy()
except GuardClientError as e:
    # Network or config error — fail closed
    raise
```

## Claude Code — MCP integration

For teams using Claude Code, install the Guard MCP Server instead. Every tool call is governed automatically with no code changes.

```bash theme={null}
sector8-guard install
```

See the [Guard MCP Server guide](/guides/mcp-server) for full setup instructions.
