Metadata-Version: 2.4
Name: spineforge
Version: 4.0.0
Summary: AI agent identity and observability SDK — Okta + Datadog for the AI agent era
Project-URL: Homepage, https://www.spineforge.ai
Project-URL: Documentation, https://www.spineforge.ai/docs
Author-email: Kushagra Chavel <kushagrachavel@gmail.com>
License: Copyright (c) 2026 Spineforge. All rights reserved.
        
        This software and associated documentation files (the "Software") are proprietary and confidential. 
        Unauthorized copying, distribution, reproduction, publication, or modification of this file, 
        via any medium, is strictly prohibited. 
        
        This software is for internal company use only, unless explicitly authorized in writing by Spineforge.
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Requires-Dist: cryptography>=43.0.0
Requires-Dist: opentelemetry-api>=1.20.0
Requires-Dist: opentelemetry-instrumentation-groq>=0.35.0
Requires-Dist: opentelemetry-instrumentation-langchain>=0.35.0
Requires-Dist: opentelemetry-sdk>=1.20.0
Requires-Dist: opentelemetry-semantic-conventions>=0.41b0
Requires-Dist: pyjwt>=2.9.0
Provides-Extra: examples
Requires-Dist: duckduckgo-search; extra == 'examples'
Requires-Dist: groq; extra == 'examples'
Requires-Dist: langchain; extra == 'examples'
Requires-Dist: langchain-community; extra == 'examples'
Requires-Dist: langchain-core; extra == 'examples'
Requires-Dist: langchain-groq; extra == 'examples'
Requires-Dist: pydantic; extra == 'examples'
Requires-Dist: python-dotenv; extra == 'examples'
Requires-Dist: wikipedia; extra == 'examples'
Description-Content-Type: text/markdown

# Spineforge SDK v4

> AI agent identity, credentials, and observability — **Okta + Datadog for the AI agent era.**

[<u>_Homepage_</u>](https://www.spineforge.ai) | [<u>_Documentation_</u>](https://www.spineforge.ai/docs) | [<u>_Dashboard_</u>](https://dashboard.spineforge.ai/login)

Spineforge assigns every AI agent a stable identity (Spine ID), manages credential leasing securely, and instruments LLM and tool calls via [OpenLLMetry](https://github.com/traceloop/openllmetry) (OpenTelemetry-based auto-instrumentation).

---

## Quick Start

### 1. Setup in Dashboard
1. Go to the [<u>_Spineforge Dashboard_</u>](https://dashboard.spineforge.ai/login).
2. Add your LLM provider keys (e.g., OpenAI, Groq) in the **Settings > LLM Keys** section. These are securely stored in a zero-trust vault and bound specifically to your user account.
3. Create a new Agent in the dashboard and generate a **Spineforge API Key** (starts with `sf-`).

### 2. Install

```bash
pip install spineforge
```

### 3. Usage (3 lines to integrate)

```python
import spineforge
from groq import Groq

# 1. Init — maps directly to your dashboard agent via the API key
spine = spineforge.init(
    api_key="sf-xxxx-xxxx",
    registry_url="https://spineforge-backend.onrender.com"
)

# 2. Lease an API key dynamically (Zero client-side secrets!)
groq_key = spine.lease_credential("groq-api-key")

# 3. Instantiate your LLM client with the leased key
client = Groq(api_key=groq_key)

# 4. Wrap your agent's top-level invocation in a run
with spine.run(input=user_query) as run:
    result = client.chat.completions.create(
        model="llama3-8b-8192",
        messages=[{"role": "user", "content": user_query}]
    )
    run.set_output(result.choices[0].message.content)
```

That's it. Spineforge auto-instruments LLM calls (Groq, LangChain) in the background via OpenTelemetry. No code changes to your agent logic.

---

## Gateway Agents (No SDK Required)

If you don't want to install the Python SDK or rewrite your code, you can still get observability, cost tracking, and secure key management through our **Gateway Agents**. Just route your standard OpenAI/OpenAI-compatible requests through our proxy URL, attaching your Gateway Key (`sfgw-xxxx`):

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://spineforge-backend.onrender.com/gateway/v1",
    api_key="sfgw-xxxx-xxxx"
)
# We will automatically resolve your actual LLM keys from the vault and log the request!
```

---

## Credential Leasing

For SDK agents, Spineforge allows you to inject keys dynamically without storing `.env` files locally. 

```python
spine = spineforge.init(
    api_key="sf-xxxx",
    registry_url="https://spineforge-backend.onrender.com"
)

# Lease credentials mapped to your user account
openai_key = spine.lease_credential("openai-api-key")
anthropic_key = spine.lease_credential("anthropic-api-key")
```

The agent must have the appropriate `lease:<provider-key>` scope to perform this action.

---

## Security Scopes

Spineforge enforces strict security boundaries via **Scopes**.
By default, standard scopes like `telemetry:write` are automatically granted.

You can declare additional scopes from code at registration time:

```python
spine = spineforge.init(
    api_key="sf-xxxx",
    allowed_scopes=["lease:openai-api-key", "lease:groq-api-key", "telemetry:write"],
    registry_url="https://spineforge-backend.onrender.com"
)
```

> **Note**: While you can request scopes via code, you can also seamlessly manage and enforce scope policies globally across your entire fleet straight from the **Spineforge Dashboard**.

---

## How It Works

### `init()` → `Spine`

1. **Resolves identity** — Uses your `sf-` API key to authenticate and fetch the exact agent identity generated in the dashboard.
2. **Wires instrumentation** — creates an OpenTelemetry `TracerProvider`, registers a custom `SpineforgeSpanProcessor`, and activates OpenLLMetry instrumentors for installed libraries (Groq, LangChain).
3. **Returns a `Spine` handle** — use `spine.run()` to group actions into runs.

### `spine.run(input=...)` → context manager

The `with spine.run(...)` block:
- Generates a `run_id` and sets it in a `ContextVar` so all spans created during the block are associated with this run.
- Emits a `RunEvent(status="running")` at entry.
- Emits a `RunEvent(status="success")` or `RunEvent(status="error")` at exit.
- Force-flushes the OTel pipeline to ensure all action spans are written before the run-end event.

---

## Sink Abstraction

All events flow through a `Sink` interface:

```python
class Sink(ABC):
    def emit(self, event: dict) -> None: ...
    def flush(self) -> None: ...
    def shutdown(self) -> None: ...
```

**Built-in sinks:**
- `ConsoleSink` — compact, coloured one-liners to stdout
- `FileSink` — non-blocking JSONL append via background thread + queue
- `APISink` — batched, non-blocking POSTs to the Spineforge backend with automatic retry and local file fallback

| Variable | Default | Description |
| --- | --- | --- |
| `SPINEFORGE_REGISTRY_URL` | `https://spineforge-backend.onrender.com` | URL of the Spineforge backend. Set to empty string (`""`) for offline mode. |

---

## Adding a New Framework Instrumentor

To add support for a new framework (e.g. CrewAI):

### 1. Install the instrumentor package

```bash
pip install opentelemetry-instrumentation-crewai
```

### 2. Add activation in `instrumentation.py`

```python
# In _instrument_libraries():
try:
    from opentelemetry.instrumentation.crewai import CrewAIInstrumentor
    CrewAIInstrumentor().instrument(tracer_provider=provider)
    _log_instrumentor_status("CrewAI", True)
except ImportError:
    _log_instrumentor_status("CrewAI", False, "not installed")
```

---

## License

This software is proprietary and confidential. Unauthorized copying, distribution, reproduction, publication, or modification of this software, via any medium, is strictly prohibited. For internal use only.
