--reject --reason "Amount too large"
+```
+
+### Auto-approve low-risk actions
+
+Route only high-value operations to a human reviewer, and approve the rest automatically:
+
+```python
+def reviewer_approve_or_escalate(execution_id: str, runtime: AgentRuntime, args: dict):
+ if args and args.get("amount_usd", 999) <= 25:
+ reviewer_approve(execution_id, runtime)
+ else:
+ notify_human(execution_id, args)
+```
+
+### Wire up a webhook approver
+
+Store the `execution_id` from `handle_ticket` in your database, then approve or reject from a webhook when a reviewer clicks a button in your UI:
+
+```python
+@app.post("/approvals/{execution_id}/approve")
+def approve(execution_id: str):
+ reviewer_approve(execution_id, runtime)
+ return {"status": "approved"}
+
+@app.post("/approvals/{execution_id}/reject")
+def reject(execution_id: str, reason: str):
+ reviewer_reject(execution_id, runtime, reason)
+ return {"status": "rejected"}
+```
diff --git a/docs/developer-guides/agentspan/overview.mdx b/docs/developer-guides/agentspan/overview.mdx
new file mode 100644
index 00000000..a03d4541
--- /dev/null
+++ b/docs/developer-guides/agentspan/overview.mdx
@@ -0,0 +1,371 @@
+---
+slug: "/developer-guides/agentspan"
+title: "Agentspan"
+description: "Agentspan documentation for building production AI agents."
+---
+
+# Agentspan
+
+**AI agents that don't die when your process does.**
+
+Most agent frameworks run the loop in your process. A crash, deploy, or OOM kill loses everything. Agentspan separates your code from execution state — the server holds state, your workers execute tools. Agents survive restarts, pause for human approval indefinitely, and resume at the last completed step.
+
+
+
+---
+
+## Why production agents break
+
+When an agent loop runs inside your process, six things can go wrong — and they will:
+
+- **Process crash mid-run.** A long agent run takes minutes. If your process dies, the run is gone. No resume.
+- **Human approval loses state.** Pausing for human input means holding state in memory. A restart kills the pending approval.
+- **No history.** In-process execution leaves no record. You can't query what any agent did, replay a run, or compare models.
+- **Scaling duplicates state.** Multiple machines mean distributed state management — or isolated, uncoordinated agents.
+- **Scheduling requires external infra.** A cron means a separate scheduler, missed-fire handling, and overlap detection — all failure-prone.
+- **Background jobs vanish.** An async agent fired via threading or asyncio dies when your process does.
+
+Agentspan eliminates all six by keeping execution state on the server.
+
+```
+Your process Agentspan server
+└── worker └── agent execution
+ ├── registers tools ├── tracks current step
+ └── executes tool calls ←────── delegates tool work
+ ├── retries on failure
+ ├── holds HITL state
+ └── stores full history
+```
+
+Your process can crash, restart, or be replaced. **The agent keeps running.**
+
+---
+
+## Get started in 30 seconds
+
+### 1. Install
+
+=== "Python"
+
+ ```bash
+ pip install conductor-agent-sdk
+ ```
+
+=== "TypeScript"
+
+ ```bash
+ npm install @conductor-oss/conductor-agent-sdk
+ ```
+
+=== "Java"
+
+ ```xml
+
+
+ org.conductoross.conductor
+ conductor-agent-sdk
+ 0.1.0
+
+ ```
+
+ ```gradle
+ // Gradle
+ implementation 'org.conductoross.conductor:conductor-agent-sdk:0.1.0'
+ ```
+
+=== "C#"
+
+ ```bash
+ dotnet add package conductor-agent-sdk
+ ```
+
+=== "Rust *(coming soon)*"
+
+ ```toml
+ # Cargo.toml — not yet published
+ # [dependencies]
+ # conductor-agent-sdk = "0.1"
+ ```
+
+ Star the [repo](https://github.com/agentspan-ai/agentspan) to be notified when Rust support ships.
+
+=== "Ruby *(coming soon)*"
+
+ ```ruby
+ # Gemfile — not yet published
+ # gem 'conductor-agent-sdk'
+ ```
+
+ Star the [repo](https://github.com/agentspan-ai/agentspan) to be notified when Ruby support ships.
+
+### 2. Set your LLM key
+
+```bash
+export OPENAI_API_KEY=sk-... # OpenAI
+# or
+export ANTHROPIC_API_KEY=sk-ant-... # Anthropic
+```
+
+### 3. Start the server
+
+```bash
+agentspan server start
+```
+
+Downloads and starts the Agentspan runtime on `http://localhost:6767`. First run fetches the JAR (~50 MB); subsequent starts use the cache.
+
+### 4. Run your first agent
+
+=== "Python"
+
+ ```python
+ from conductor.ai.agents import Agent, AgentRuntime, tool
+
+ @tool
+ def get_weather(city: str) -> str:
+ """Get current weather for a city."""
+ return f"72°F and sunny in {city}"
+
+ agent = Agent(
+ name="weatherbot",
+ model="openai/gpt-4o",
+ instructions="You are an outdoor activity assistant. Look up the weather, then recommend activities.",
+ tools=[get_weather],
+ )
+
+ with AgentRuntime() as runtime:
+ result = runtime.run(agent, "What should I do today in NYC?")
+ result.print_result()
+ ```
+
+=== "TypeScript"
+
+ ```typescript
+ import { Agent, AgentRuntime, tool } from '@conductor-oss/conductor-agent-sdk';
+
+ const getWeather = tool(
+ async ({ city }: { city: string }) => `72°F and sunny in ${city}`,
+ { name: 'get_weather', description: 'Get current weather for a city',
+ inputSchema: { type: 'object', properties: { city: { type: 'string' } }, required: ['city'] } }
+ );
+
+ const agent = new Agent({
+ name: 'weatherbot',
+ model: 'openai/gpt-4o',
+ instructions: 'You are an outdoor activity assistant. Look up the weather, then recommend activities.',
+ tools: [getWeather],
+ });
+
+ const runtime = new AgentRuntime();
+ const result = await runtime.run(agent, 'What should I do today in NYC?');
+ result.printResult();
+ await runtime.shutdown();
+ ```
+
+=== "Java"
+
+ ```java
+ import org.conductoross.conductor.ai.Agent;
+ import org.conductoross.conductor.ai.AgentRuntime;
+ import org.conductoross.conductor.ai.tool.Tool;
+
+ public class Weatherbot {
+
+ @Tool(description = "Get current weather for a city")
+ public String getWeather(String city) {
+ return "72°F and sunny in " + city;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Weatherbot wb = new Weatherbot();
+
+ Agent agent = Agent.builder()
+ .name("weatherbot")
+ .model("openai/gpt-4o")
+ .instructions("You are an outdoor activity assistant. Look up the weather, then recommend activities.")
+ .tools(wb)
+ .build();
+
+ try (AgentRuntime runtime = new AgentRuntime()) {
+ var result = runtime.run(agent, "What should I do today in NYC?");
+ System.out.println(result.getOutput());
+ }
+ }
+ }
+ ```
+
+=== "C#"
+
+ ```csharp
+ using Conductor.AI;
+
+ var agent = new Agent(new AgentConfig {
+ Name = "weatherbot",
+ Model = "openai/gpt-4o",
+ Instructions = "You are an outdoor activity assistant. Look up the weather, then recommend activities.",
+ Tools = [
+ Tool.From((string city) => $"72°F and sunny in {city}",
+ name: "get_weather",
+ description: "Get current weather for a city")
+ ]
+ });
+
+ await using var runtime = new AgentRuntime();
+ var result = await runtime.RunAsync(agent, "What should I do today in NYC?");
+ Console.WriteLine(result.Output);
+ ```
+
+Open **http://localhost:6767** to see the execution in the visual UI.
+
+---
+
+## The four production patterns
+
+### Long-running agents
+
+Execution state lives on the server, not in your process. Workers connect, run tool calls, and disconnect — the server tracks every step. A crash mid-run resumes at the last completed step when a worker reconnects. Human approval pauses indefinitely with no in-memory state at risk.
+
+```python
+agent = Agent(
+ name="researcher",
+ model="anthropic/claude-sonnet-4-6",
+ instructions="Research the topic thoroughly. Use all available tools.",
+ tools=[web_search, read_page, write_report],
+)
+
+# Even if this process crashes, the agent resumes on reconnect
+with AgentRuntime() as runtime:
+ result = runtime.run(agent, "Write a report on LLM inference optimization")
+```
+
+### Dynamic plan-execute
+
+The LLM plans once; Conductor executes deterministically. A planner agent emits a JSON task graph. The server compiles it into an immutable sub-workflow — parallelism is `FORK_JOIN`, branching is `SWITCH`, retries cost zero tokens. See [Plan-Execute](concepts/plan-execute.md).
+
+```python
+from conductor.ai.agents import plan_execute
+
+harness = plan_execute(
+ name="report_generator",
+ tools=[create_dir, write_section, assemble, check_length],
+ planner_instructions="Plan a 3-section report on the topic.",
+ fallback_instructions="Fix what the deterministic plan couldn't.",
+)
+
+result = runtime.run(harness, "AI agents in 2025")
+```
+
+### Event-driven agents
+
+Attach cron schedules at deploy time. Connect to Kafka, SQS, AMQP, webhooks, or any Conductor event source — every execution fully recorded with inputs, outputs, and per-step timing. See [Scheduling](scheduling.md).
+
+```python
+from conductor.ai.agents import Schedule
+
+agent = Agent(
+ name="daily_digest",
+ instructions="Summarize the top news for today.",
+ tools=[fetch_news, send_email],
+ schedules=[Schedule(name="morning", cron="0 9 * * *")],
+)
+
+runtime.deploy(agent) # registers the schedule; server fires it every day at 9 AM
+```
+
+### Adaptive loops
+
+Any framework can loop. Only Agentspan makes each iteration a **durable, observable workflow** — crash mid-loop and resume at the current iteration, not from scratch. Combine Plan-Execute for deterministic inner execution with an adaptive outer loop that converges based on verified results. See [Adaptive Loops](concepts/adaptive-loops.md).
+
+```python
+from conductor.ai.agents import Agent, AgentRuntime
+
+agent = Agent(name="travel_planner", instructions="Output itineraries as JSON.", ...)
+
+failures = []
+with AgentRuntime() as runtime:
+ for iteration in range(max_iterations):
+ prompt = build_prompt(destination, daily_budget, failures)
+ result = runtime.run(agent, prompt) # durable workflow — survives crashes
+
+ itinerary = extract_json(result)
+ failures = verify_constraints(itinerary) # deterministic — no LLM
+ if not failures:
+ print(f"✓ All constraints passed in {iteration + 1} iteration(s)")
+ break
+ # Exact failure messages feed into the next prompt
+```
+
+Each `runtime.run()` is a durable Conductor workflow — every iteration observable in the UI, resumable on crash, and fully logged.
+
+See `examples/118_adaptive_loop_showcase.py` — a runnable travel planner that loops until budget and structural constraints pass (`python 118_adaptive_loop_showcase.py "Tokyo"`).
+
+---
+
+## Works with your existing framework
+
+Pass your existing agent directly to `runtime.run()`. Your code is unchanged.
+
+```python
+# LangGraph
+from langgraph.prebuilt import create_react_agent
+graph = create_react_agent(model, tools)
+result = runtime.run(graph, prompt)
+
+# OpenAI Agents SDK
+from agents import Agent as OAIAgent
+agent = OAIAgent(name="helper", instructions="...", tools=[...])
+result = runtime.run(agent, prompt)
+
+# Google ADK
+from google.adk.agents import LlmAgent
+agent = LlmAgent(name="helper", instruction="...", tools=[...])
+result = runtime.run(agent, prompt)
+```
+
+---
+
+## Go deeper
+
+
+
+- :material-help-circle-outline: **Why Agentspan**
+
+ ---
+
+ Why conventional frameworks fail in production, and how Agentspan's server-side execution model solves it.
+
+ [Read more →](why-agentspan.md)
+
+- :material-graph-outline: **Plan-Execute**
+
+ ---
+
+ The LLM plans once; Conductor executes deterministically. No tokens on retries, parallelism, or branching.
+
+ [Read more →](concepts/plan-execute.md)
+
+- :material-book-open-outline: **SDK Reference**
+
+ ---
+
+ Python, TypeScript, Java, and C# — full API reference, examples, and framework integration guides.
+
+ [Read more →](sdk.md)
+
+- :material-rocket-launch-outline: **Examples**
+
+ ---
+
+ Production-shape examples: support triage, research pipelines, HITL workflows, LangGraph bots.
+
+ [Read more →](examples/support-triage.md)
+
+- :material-refresh: **Adaptive loops**
+
+ ---
+
+ Durable iterative agents — each iteration a Conductor workflow. Replan based on verified results, converge on goals, and observe every iteration in the UI.
+
+ [Read more →](concepts/adaptive-loops.md)
+
+
diff --git a/docs/developer-guides/agentspan/quickstart.mdx b/docs/developer-guides/agentspan/quickstart.mdx
new file mode 100644
index 00000000..9b39d9e0
--- /dev/null
+++ b/docs/developer-guides/agentspan/quickstart.mdx
@@ -0,0 +1,124 @@
+---
+slug: "/developer-guides/agentspan/quickstart"
+title: "Quickstart"
+description: "Install Agentspan and run your first durable AI agent in under 60 seconds."
+---
+
+# Quickstart
+
+Get Agentspan running locally in under 60 seconds.
+
+## Step 1 — Install
+
+```bash
+pip install conductor-agent-sdk
+```
+
+This installs the Python SDK and the `agentspan` CLI — everything you need as a Python developer.
+
+Verify your setup:
+
+```bash
+agentspan doctor
+```
+
+> **uv:** `uv pip install conductor-agent-sdk` also works.
+>
+> **CLI only (no Python SDK):** `npm install -g @agentspan-ai/agentspan` — downloads the binary eagerly at install time, no Python required.
+
+## Step 2 — Set your LLM API key
+
+```bash
+# OpenAI
+export OPENAI_API_KEY=sk-...
+
+# Anthropic
+export ANTHROPIC_API_KEY=sk-ant-...
+```
+
+See [Providers](/developer-guides/agentspan/reference/providers) for all supported models and environment variables.
+
+## Step 3 — Start the server
+
+```bash
+agentspan server start
+```
+
+On first run, this downloads the Agentspan server JAR (~50 MB) and starts it on `http://localhost:6767`. Subsequent starts use the cached JAR. Open `http://localhost:6767` in your browser to see the visual execution UI.
+
+> **Local default:** The server uses SQLite with WAL mode — no external database needed for local development. Data is stored in `agent-runtime.db` in the working directory.
+
+## Step 4 — Run your first agent
+
+Save this as `hello.py` and run `python hello.py`:
+
+```python
+from conductor.ai.agents import Agent, AgentRuntime, tool
+
+@tool
+def get_weather(city: str) -> str:
+ """Get current weather for a city."""
+ return f"72°F and sunny in {city}"
+
+agent = Agent(
+ name="weatherbot",
+ model="openai/gpt-4o", # if you set OPENAI_API_KEY
+ # model="anthropic/claude-sonnet-4-6", # if you set ANTHROPIC_API_KEY
+ instructions="You are an outdoor activity assistant. When asked about a city, look up the weather there, then recommend 2-3 specific outdoor activities suited to those conditions. Be direct: good weather for hiking is different from good weather for a beach day.",
+ tools=[get_weather],
+)
+
+with AgentRuntime() as runtime:
+ result = runtime.run(agent, "What should I do today in NYC?")
+ result.print_result()
+```
+
+You should see the answer printed, and the execution visible in the UI at `http://localhost:6767`.
+
+## What just happened?
+
+When you called `runtime.run()`, the SDK:
+
+1. Compiled your `Agent` into a durable execution on the Agentspan server
+2. Started a worker process to handle `@tool` function calls
+3. Executed the workflow on the server — not in-process
+4. Returned the result when complete
+
+**The key difference from other SDKs:** if your process crashes mid-execution, the workflow keeps running on the server. You can reconnect to it by execution ID from any machine.
+
+**Tool locality — what runs where:**
+- `@tool` functions run in **your worker process** — full access to your code, libraries, and local state
+- `http_tool()`, `api_tool()`, `mcp_tool()` run **server-side** — no code to write, just configure a URL
+
+See [Tools](/developer-guides/agentspan/concepts/tools) for all tool types.
+
+## Alternative: Using module-level functions
+
+If you prefer not to use the context manager, module-level functions are available. They use a shared singleton runtime under the hood:
+
+```python
+from conductor.ai.agents import Agent, tool, run
+
+@tool
+def get_weather(city: str) -> str:
+ """Get current weather for a city."""
+ return f"72°F and sunny in {city}"
+
+agent = Agent(
+ name="weatherbot",
+ model="openai/gpt-4o", # if you set OPENAI_API_KEY
+ # model="anthropic/claude-sonnet-4-6", # if you set ANTHROPIC_API_KEY
+ instructions="You are an outdoor activity assistant. When asked about a city, look up the weather there, then recommend 2-3 specific outdoor activities suited to those conditions. Be direct: good weather for hiking is different from good weather for a beach day.",
+ tools=[get_weather],
+)
+result = run(agent, "What should I do today in NYC?")
+result.print_result()
+```
+
+## Next steps
+
+- [Concepts: Agents](/developer-guides/agentspan/concepts/agents) — all `Agent` constructor parameters
+- [Concepts: Tools](/developer-guides/agentspan/concepts/tools) — `@tool`, `http_tool`, `mcp_tool`, `api_tool`
+- [Providers](/developer-guides/agentspan/reference/providers) — all supported LLM providers and model strings
+- [Deployment](/developer-guides/agentspan/reference/deployment) — local, Docker, and Kubernetes setups
+- [Examples](/developer-guides/agentspan/examples) — 180+ runnable examples
diff --git a/docs/developer-guides/agentspan/reference/ai-models.mdx b/docs/developer-guides/agentspan/reference/ai-models.mdx
new file mode 100644
index 00000000..36e32e11
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/ai-models.mdx
@@ -0,0 +1,222 @@
+---
+slug: "/developer-guides/agentspan/reference/ai-models"
+title: "AI Model Configuration"
+---
+
+# AI Model Configuration
+
+Agentspan supports 12+ AI providers out of the box. Configure them by setting environment variables before starting the server.
+
+## Quick Setup
+
+Set the API key for the provider(s) you want to use:
+
+```bash
+# OpenAI (most common)
+export OPENAI_API_KEY=sk-...
+
+# Anthropic (Claude)
+export ANTHROPIC_API_KEY=sk-ant-...
+
+# Google Gemini
+export GEMINI_API_KEY=AI...
+export GOOGLE_CLOUD_PROJECT=your-gcp-project-id
+
+# Then start the server
+agentspan server start
+```
+
+## All Providers
+
+### OpenAI
+
+| Variable | Description |
+|---|---|
+| `OPENAI_API_KEY` | API key from [platform.openai.com](https://platform.openai.com/api-keys) |
+| `OPENAI_ORG_ID` | Organization ID (optional) |
+
+**Models:** `openai/gpt-4o`, `anthropic/claude-sonnet-4-6`, `openai/gpt-4-turbo`, `openai/o1`, `openai/o1-mini`, `openai/o3-mini`
+
+**Embeddings:** `openai/text-embedding-3-small`, `openai/text-embedding-3-large`
+
+**Image generation:** `openai/dall-e-3`
+
+---
+
+### Anthropic (Claude)
+
+| Variable | Description |
+|---|---|
+| `ANTHROPIC_API_KEY` | API key from [console.anthropic.com](https://console.anthropic.com/) |
+
+**Models:** `anthropic/claude-opus-4-20250514`, `anthropic/claude-sonnet-4-20250514`, `anthropic/claude-3-5-sonnet-20241022`, `anthropic/claude-3-haiku-20240307`
+
+---
+
+### Google Gemini
+
+| Variable | Description |
+|---|---|
+| `GEMINI_API_KEY` | API key from [aistudio.google.com](https://aistudio.google.com/apikey) |
+| `GOOGLE_CLOUD_PROJECT` | **Required.** GCP project ID |
+
+**Models:** `google_gemini/gemini-2.0-flash`, `google_gemini/gemini-1.5-pro`, `google_gemini/gemini-1.5-flash`
+
+**Embeddings:** `google_gemini/text-embedding-004`
+
+**Image generation:** `google_gemini/imagen-3.0-generate-002`
+
+---
+
+### Azure OpenAI
+
+| Variable | Description |
+|---|---|
+| `AZURE_OPENAI_API_KEY` | API key from Azure portal |
+| `AZURE_OPENAI_ENDPOINT` | **Required.** Endpoint URL (e.g. `https://your-resource.openai.azure.com`) |
+| `AZURE_OPENAI_DEPLOYMENT` | **Required.** Deployment name |
+
+**Models:** `azure_openai/gpt-4o`, `azure_openai/gpt-4`, `azure_openai/gpt-3.5-turbo`
+
+---
+
+### AWS Bedrock
+
+| Variable | Description |
+|---|---|
+| `AWS_ACCESS_KEY_ID` | AWS access key |
+| `AWS_SECRET_ACCESS_KEY` | AWS secret key |
+
+**Server properties (optional):**
+- `conductor.ai.bedrock.region` — defaults to `us-east-1`
+
+**Models:** `aws_bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0`, `aws_bedrock/anthropic.claude-3-haiku-20240307-v1:0`, `aws_bedrock/meta.llama3-70b-instruct-v1:0`, `aws_bedrock/amazon.titan-text-express-v1`
+
+**Embeddings:** `aws_bedrock/amazon.titan-embed-text-v2:0`
+
+---
+
+### Mistral AI
+
+| Variable | Description |
+|---|---|
+| `MISTRAL_API_KEY` | API key from [console.mistral.ai](https://console.mistral.ai/) |
+
+**Models:** `mistral/mistral-large-latest`, `mistral/mistral-medium-latest`, `mistral/mistral-small-latest`, `mistral/open-mixtral-8x7b`
+
+**Embeddings:** `mistral/mistral-embed`
+
+---
+
+### Cohere
+
+| Variable | Description |
+|---|---|
+| `COHERE_API_KEY` | API key from [dashboard.cohere.com](https://dashboard.cohere.com/) |
+
+**Models:** `cohere/command-r-plus`, `cohere/command-r`, `cohere/command`
+
+**Embeddings:** `cohere/embed-english-v3.0`, `cohere/embed-multilingual-v3.0`
+
+---
+
+### Grok (xAI)
+
+| Variable | Description |
+|---|---|
+| `XAI_API_KEY` | API key from xAI |
+
+**Models:** `grok/grok-3`, `grok/grok-3-mini`
+
+---
+
+### Perplexity AI
+
+| Variable | Description |
+|---|---|
+| `PERPLEXITY_API_KEY` | API key from [perplexity.ai](https://www.perplexity.ai/) |
+
+**Models:** `perplexity/sonar-pro`, `perplexity/sonar`
+
+---
+
+### Hugging Face
+
+| Variable | Description |
+|---|---|
+| `HUGGINGFACE_API_KEY` | API token from [huggingface.co](https://huggingface.co/settings/tokens) |
+
+**Models:** `hugging_face/meta-llama/Llama-3-70b-chat-hf`, `hugging_face/mistralai/Mistral-7B-Instruct-v0.2`
+
+---
+
+### Stability AI
+
+| Variable | Description |
+|---|---|
+| `STABILITY_API_KEY` | API key from [platform.stability.ai](https://platform.stability.ai/) |
+
+**Image generation:** `stabilityai/sd3.5-large`, `stabilityai/sd3.5-medium`, `stabilityai/stable-image-core`
+
+---
+
+### Ollama (Local / Remote)
+
+No API key required. Ollama must be running and reachable.
+
+| Variable | Description |
+|---|---|
+| `OLLAMA_BASE_URL` | Ollama server URL (default: `http://localhost:11434`) |
+
+```bash
+# Local (default)
+# No configuration needed if Ollama is running on localhost
+
+# Remote or custom port
+export OLLAMA_BASE_URL=http://your-gpu-server:11434
+```
+
+Install Ollama: [ollama.com/download](https://ollama.com/download)
+
+**Models:** `ollama/llama3`, `ollama/mistral`, `ollama/phi3`, `ollama/codellama`
+
+**Embeddings:** `ollama/nomic-embed-text`
+
+---
+
+## Model Format
+
+When specifying models in your agents, use the format `provider/model-name`:
+
+```python
+agent = Agent(name="my_agent", model="openai/gpt-4o")
+agent = Agent(name="my_agent", model="anthropic/claude-sonnet-4-20250514")
+agent = Agent(name="my_agent", model="google_gemini/gemini-2.0-flash")
+```
+
+## Server Properties
+
+These can be set as environment variables using the Spring Boot convention (dots become underscores, uppercase):
+
+| Property | Env Variable | Default | Description |
+|---|---|---|---|
+| `conductor.integrations.ai.enabled` | `CONDUCTOR_INTEGRATIONS_AI_ENABLED` | `true` | Enable/disable AI integration |
+| `conductor.ai.openai.api-key` | `OPENAI_API_KEY` | — | OpenAI API key |
+| `conductor.ai.openai.organization-id` | `OPENAI_ORG_ID` | — | OpenAI organization |
+| `conductor.ai.anthropic.api-key` | `ANTHROPIC_API_KEY` | — | Anthropic API key |
+| `conductor.ai.gemini.api-key` | `GEMINI_API_KEY` | — | Google Gemini API key |
+| `conductor.ai.gemini.project-id` | `GOOGLE_CLOUD_PROJECT` | — | GCP project ID |
+| `conductor.ai.gemini.location` | — | `us-central1` | GCP region |
+| `conductor.ai.azureopenai.api-key` | `AZURE_OPENAI_API_KEY` | — | Azure OpenAI API key |
+| `conductor.ai.azureopenai.base-url` | `AZURE_OPENAI_ENDPOINT` | — | Azure OpenAI endpoint |
+| `conductor.ai.azureopenai.deployment-name` | `AZURE_OPENAI_DEPLOYMENT` | — | Azure deployment name |
+| `conductor.ai.bedrock.access-key` | `AWS_ACCESS_KEY_ID` | — | AWS access key |
+| `conductor.ai.bedrock.secret-key` | `AWS_SECRET_ACCESS_KEY` | — | AWS secret key |
+| `conductor.ai.bedrock.region` | — | `us-east-1` | AWS region |
+| `conductor.ai.mistral.api-key` | `MISTRAL_API_KEY` | — | Mistral API key |
+| `conductor.ai.cohere.api-key` | `COHERE_API_KEY` | — | Cohere API key |
+| `conductor.ai.grok.api-key` | `XAI_API_KEY` | — | Grok/xAI API key |
+| `conductor.ai.perplexity.api-key` | `PERPLEXITY_API_KEY` | — | Perplexity API key |
+| `conductor.ai.huggingface.api-key` | `HUGGINGFACE_API_KEY` | — | Hugging Face token |
+| `conductor.ai.stabilityai.api-key` | `STABILITY_API_KEY` | — | Stability AI API key |
+| `conductor.ai.ollama.base-url` | `OLLAMA_BASE_URL` | `http://localhost:11434` | Ollama server URL |
diff --git a/docs/developer-guides/agentspan/reference/cli.mdx b/docs/developer-guides/agentspan/reference/cli.mdx
new file mode 100644
index 00000000..25989d96
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/cli.mdx
@@ -0,0 +1,168 @@
+---
+slug: "/developer-guides/agentspan/reference/cli"
+title: "CLI Reference"
+description: "Agentspan CLI commands for server, credentials, agents, skills, status, and execution history"
+---
+
+# CLI Reference
+
+**Python developers:** `pip install conductor-agent-sdk` gives you the SDK and the CLI. The pip package registers the `agentspan` command as a console script; on first invocation it downloads the Go binary from S3 and caches it.
+
+**CLI only (no Python SDK):** `npm install -g @agentspan-ai/agentspan` — downloads the Go binary eagerly at install time. Useful if you don't have Python or want the binary pre-fetched.
+
+```bash
+agentspan version # Print the CLI version
+agentspan --help # List all commands
+```
+
+## Server Commands
+
+```bash
+agentspan server start # Download (if needed) and start the server
+agentspan server stop # Stop the server
+agentspan server logs # View server logs
+```
+
+`agentspan server start` downloads the Agentspan server JAR on first run (~50 MB) and starts it as a local process. The JAR is cached — subsequent starts are instant. The server runs on port `6767`. The UI and API are both served from the same port — open `http://localhost:6767` in your browser to see the visual execution UI.
+
+## Diagnostics
+
+```bash
+agentspan doctor # Check system dependencies and AI provider configuration
+```
+
+`agentspan doctor` verifies:
+- CLI is installed and working
+- Java runtime is available (required to run the server)
+- Python SDK is installed
+- API keys are configured
+- Server is reachable
+
+## Credential Management
+
+Store secrets on the server once. Tools resolve them automatically at runtime — no `.env` files, no hardcoded keys, no secrets in git.
+
+```bash
+agentspan credentials set KEY value # Store a credential (encrypted at rest)
+agentspan credentials list # List stored credential keys
+agentspan credentials delete KEY # Delete a credential
+```
+
+Credentials are encrypted with AES-256-GCM. Only the key names are shown in `list` — values are never exposed.
+
+Example:
+
+```bash
+agentspan credentials set GITHUB_TOKEN ghp_xxxxxxxxxxxx
+agentspan credentials set SEARCH_API_KEY xxx-your-key
+```
+
+Use them in tools with `@tool(credentials=["KEY"])`. See [Tools](/developer-guides/agentspan/concepts/tools) for details.
+
+## Agent Commands
+
+### Status
+
+```bash
+agentspan agent status # Get detailed status of a running execution
+```
+
+### Respond to HITL
+
+```bash
+agentspan agent respond --approve
+agentspan agent respond --deny --reason "Amount too large, escalate to finance"
+agentspan agent respond --message "Please use a different approach"
+```
+
+### Execution History
+
+```bash
+agentspan agent execution --since 1h
+agentspan agent execution --name my_agent --since 1d
+agentspan agent execution --status COMPLETED --since 7d
+agentspan agent execution --name my_agent --status FAILED --since 1mo
+```
+
+Time formats: `30s`, `5m`, `1h`, `6h`, `1d`, `7d`, `1mo`, `1y`
+
+### Run and Stream
+
+```bash
+agentspan agent run --name my_agent "What is quantum computing?" # Run deployed agent and stream output
+agentspan agent run --config agent.yaml "What is quantum computing?" # Run from config file
+agentspan agent stream # Stream events from a running execution
+```
+
+### List and Get
+
+```bash
+agentspan agent list # List all registered agents
+agentspan agent get my_agent # Get agent configuration JSON
+agentspan agent compile my_agent # Compile and inspect execution plan (dry run)
+```
+
+### Skills
+
+```bash
+agentspan skill run ./my-skill "Do the task" --model openai/gpt-4o
+agentspan skill run my-skill "Do the task" --model openai/gpt-4o --version 2026.05.21
+agentspan skill run code-review "Review current changes" --model openai/gpt-4o --workspace .
+agentspan skill run code-review "Review docs too" --model openai/gpt-4o --filesystem docs=./docs
+agentspan skill load ./my-skill --model openai/gpt-4o
+agentspan skill register ./my-skill --model openai/gpt-4o --version 2026.05.21
+agentspan skill list --all-versions
+agentspan skill get my-skill --version 2026.05.21
+agentspan skill pull my-skill ./my-skill-copy --version 2026.05.21
+agentspan skill delete my-skill --version 2026.05.21 --yes
+agentspan skill serve my-skill --version 2026.05.21 --script-timeout 300
+```
+
+When `skill run` or `skill serve` is given a registered skill name instead of
+a local directory, the CLI downloads the package into
+`~/.agentspan/skills///files` and reuses that cached copy until
+the server checksum changes. Downloaded packages are checksum-verified before
+the cache is installed or any script worker is started. If a registered skill
+references another registered skill, the server resolves that reference at
+compile time and the CLI downloads the referenced package too, so script tools
+and `read_skill_file` work for both the parent and referenced skills. Referenced
+skill versions are pinned when the parent is registered; running `parent@v1`
+continues to use the child version that was latest at registration time.
+
+`skill register` excludes generated directories, common secret files such as
+`.env` and private keys, and paths matched by `.agentspanignore`.
+
+`skill run` exposes the current directory as the `workspace` filesystem root by
+default. Skills can list, read, search, and inspect git status/diff through
+workspace tools served by the CLI. Use `--workspace ` to point at a
+different checkout, `--filesystem =` to expose additional read-only
+roots, or `--no-workspace` to run without local filesystem context.
+
+## Configuration
+
+Configure the server URL and auth credentials:
+
+```bash
+agentspan configure --url https://your-server.example.com
+agentspan configure --url https://your-server.example.com --auth-key my-key --auth-secret my-secret
+```
+
+Or set environment variables:
+
+```bash
+export AGENTSPAN_SERVER_URL=https://your-server.example.com
+export AGENTSPAN_AUTH_KEY=your-key
+export AGENTSPAN_AUTH_SECRET=your-secret
+```
+
+Or configure in Python code:
+
+```python
+from conductor.ai.agents import configure
+
+configure(
+ server_url="https://your-server.example.com",
+ auth_key="your-key",
+ auth_secret="your-secret",
+)
+```
diff --git a/docs/developer-guides/agentspan/reference/deployment.mdx b/docs/developer-guides/agentspan/reference/deployment.mdx
new file mode 100644
index 00000000..d48b6eae
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/deployment.mdx
@@ -0,0 +1,184 @@
+---
+slug: "/developer-guides/agentspan/reference/deployment"
+title: "Deployment"
+description: "Deploy Agentspan locally with SQLite, with Docker Compose, or on Kubernetes"
+---
+
+# Deployment
+
+Agentspan runs on a persistent server that manages durable execution. Your Python workers connect to the server and execute tools as distributed tasks.
+
+## Local Development (SQLite — zero setup)
+
+The default setup uses SQLite with WAL mode. No external database needed.
+
+```bash
+agentspan server start
+```
+
+Data is stored in `agent-runtime.db` in the working directory. The UI and API are both at `http://localhost:6767`.
+
+## Production (PostgreSQL + Docker Compose)
+
+For production workloads, use PostgreSQL for durability and concurrent access.
+
+**1. Clone the repo and start the compose stack:**
+
+```bash
+cd deployment/docker-compose
+cp .env.example .env
+# Set at least one LLM provider key in .env (e.g. OPENAI_API_KEY)
+docker compose up -d
+```
+
+The compose stack starts two services:
+- `agentspan` — the Agentspan server (port 6767)
+- `postgres` — PostgreSQL 16
+
+Open `http://localhost:6767` for the UI. Health check: `http://localhost:6767/actuator/health`.
+
+**2. Point your Python workers at the running server:**
+
+```bash
+export AGENTSPAN_SERVER_URL=http://localhost:6767
+python my_agent.py
+```
+
+Workers are stateless Python processes that poll the server for tasks. Scale them independently.
+
+## PostgreSQL (without Docker)
+
+Start PostgreSQL separately and configure the server:
+
+```bash
+export SPRING_DATASOURCE_URL=jdbc:postgresql://your-host:5432/conductor
+export SPRING_DATASOURCE_USERNAME=your_user
+export SPRING_DATASOURCE_PASSWORD=your_password
+export SPRING_PROFILES_ACTIVE=postgres
+agentspan server start
+```
+
+## Kubernetes
+
+Kubernetes manifests and a Helm chart are included in the repo under `deployment/k8s/` and `deployment/helm/`.
+
+For a minimal single-node deployment:
+
+```yaml
+# agentspan-server Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: agentspan-server
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: agentspan-server
+ template:
+ metadata:
+ labels:
+ app: agentspan-server
+ spec:
+ containers:
+ - name: agentspan-server
+ image: ghcr.io/agentspan-ai/agentspan-server:latest
+ ports:
+ - containerPort: 6767
+ env:
+ - name: SPRING_PROFILES_ACTIVE
+ value: postgres
+ - name: SPRING_DATASOURCE_URL
+ valueFrom:
+ secretKeyRef:
+ name: agentspan-secrets
+ key: db-url
+ - name: SPRING_DATASOURCE_USERNAME
+ valueFrom:
+ secretKeyRef:
+ name: agentspan-secrets
+ key: db-username
+ - name: SPRING_DATASOURCE_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: agentspan-secrets
+ key: db-password
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: agentspan-server
+spec:
+ selector:
+ app: agentspan-server
+ ports:
+ - port: 6767
+ targetPort: 6767
+```
+
+Worker pods connect via `AGENTSPAN_SERVER_URL`:
+
+```python
+import os
+os.environ["AGENTSPAN_SERVER_URL"] = "http://agentspan-server:6767"
+
+from conductor.ai.agents import Agent, run
+agent = Agent(name="my_agent", model="openai/gpt-4o")
+result = run(agent, "Hello")
+```
+
+Workers are stateless — run as many replicas as you need. The server queues tasks; workers poll and execute them.
+
+## Authentication
+
+For remote servers (non-localhost), set auth credentials:
+
+```bash
+export AGENTSPAN_SERVER_URL=https://my-server.example.com
+export AGENTSPAN_AUTH_KEY=my-key
+export AGENTSPAN_AUTH_SECRET=my-secret
+```
+
+Or via code:
+
+```python
+from conductor.ai.agents import configure
+
+configure(
+ server_url="https://my-server.example.com",
+ auth_key="my-key",
+ auth_secret="my-secret",
+)
+```
+
+No other code changes needed. Your agents run exactly the same — the only difference is where the server runs.
+
+## Configuration Reference
+
+| Variable | Default | Description |
+|---|---|---|
+| `SERVER_PORT` | `6767` | Server port |
+| `SPRING_PROFILES_ACTIVE` | `default` (SQLite) | Set to `postgres` for PostgreSQL |
+| `SPRING_DATASOURCE_URL` | `jdbc:sqlite:agent-runtime.db` | Database URL |
+| `SPRING_DATASOURCE_USERNAME` | `postgres` | Database user |
+| `SPRING_DATASOURCE_PASSWORD` | `postgres` | Database password |
+| `AGENTSPAN_SERVER_URL` | `http://localhost:6767` | Server URL (used by SDK/workers) |
+| `AGENTSPAN_AUTH_KEY` | — | Auth key (required for non-localhost) |
+| `AGENTSPAN_AUTH_SECRET` | — | Auth secret (required for non-localhost) |
+| `OPENAI_API_KEY` | — | OpenAI API key |
+| `ANTHROPIC_API_KEY` | — | Anthropic API key |
+| `GEMINI_API_KEY` | — | Google Gemini API key |
+| `MISTRAL_API_KEY` | — | Mistral API key |
+| `GROQ_API_KEY` | — | Groq API key |
+
+## Production Checklist
+
+Before going to production:
+
+- [ ] Switch from SQLite to a managed PostgreSQL (RDS, Cloud SQL, etc.)
+- [ ] Set `AGENTSPAN_AUTH_KEY` and `AGENTSPAN_AUTH_SECRET` for all workers
+- [ ] Configure `max_turns` and timeouts for long-running agents
+- [ ] Add guardrails for all user-facing agents
+- [ ] Test agents with `mock_run` before deploying
+- [ ] Use `AgentHandle.get_status()` to monitor long-running executions
+- [ ] Set up alerting via the Agentspan UI or Prometheus metrics
diff --git a/docs/developer-guides/agentspan/reference/integrations.mdx b/docs/developer-guides/agentspan/reference/integrations.mdx
new file mode 100644
index 00000000..6b87629b
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/integrations.mdx
@@ -0,0 +1,144 @@
+---
+slug: "/developer-guides/agentspan/reference/integrations"
+title: "Framework Integrations"
+description: "Use Agentspan with LangGraph, the OpenAI Agents SDK, Google ADK, or any framework. Pass your existing agent to runtime.run() — one line, no rewrites."
+---
+
+# Framework Integrations
+
+Agentspan works with the frameworks you already use. Pass your existing agent directly to `runtime.run()` — definitions, tools, and routing logic stay exactly as written. You get crash recovery, durable human-in-the-loop, and full execution history without changing a single node or handoff.
+
+```python
+from conductor.ai.agents import AgentRuntime
+
+with AgentRuntime() as runtime:
+ result = runtime.run(your_existing_agent, "your prompt")
+```
+
+`your_existing_agent` can be a LangGraph compiled graph, an OpenAI Agents SDK `Agent`, a Google ADK pipeline, or a native Agentspan `Agent`. The API is the same.
+
+---
+
+## Supported frameworks
+
+### LangGraph
+
+Pass a compiled `StateGraph` or any graph produced by `create_react_agent`:
+
+```python
+from langgraph.prebuilt import create_react_agent
+from conductor.ai.agents import AgentRuntime
+
+graph = create_react_agent(model="openai/gpt-4o", tools=[search, calculator])
+
+with AgentRuntime() as runtime:
+ result = runtime.run(graph, "Research the history of the Eiffel Tower")
+ print(result.workflow_id)
+```
+
+**Note:** Do not pass a `checkpointer` when wrapping with AgentRuntime — Agentspan manages execution state server-side and the two checkpointing models conflict. LangSmith observability is fully compatible and unaffected.
+
+→ [Full LangGraph example — code review bot](/developer-guides/agentspan/examples/langgraph)
+
+---
+
+### OpenAI Agents SDK
+
+Pass an `Agent` from the `agents` package directly:
+
+```python
+from agents import Agent as OAIAgent, WebSearchTool
+from conductor.ai.agents import AgentRuntime
+
+oai_agent = OAIAgent(
+ name="support_agent",
+ instructions="You are a helpful customer support agent.",
+ tools=[WebSearchTool()],
+)
+
+with AgentRuntime() as runtime:
+ result = runtime.run(oai_agent, "How do I reset my password?")
+ print(result.output["result"])
+```
+
+Agent definitions, handoffs, and tool registrations stay exactly as written.
+
+→ [Full OpenAI Agents SDK example — support agent](/developer-guides/agentspan/examples/openai-agents-sdk)
+
+---
+
+### Google ADK
+
+Pass any ADK pipeline (`SequentialAgent`, `ParallelAgent`, `LoopAgent`, or a custom `BaseAgent`):
+
+```python
+from google.adk.agents import SequentialAgent, LlmAgent
+from conductor.ai.agents import AgentRuntime
+
+researcher = LlmAgent(name="researcher", model="gemini-2.0-flash", ...)
+writer = LlmAgent(name="writer", model="gemini-2.0-flash", ...)
+pipeline = SequentialAgent(name="pipeline", sub_agents=[researcher, writer])
+
+with AgentRuntime() as runtime:
+ result = runtime.run(pipeline, "Research and summarize quantum computing trends")
+ print(result.output["result"])
+```
+
+→ [Full Google ADK example — research assistant](/developer-guides/agentspan/examples/google-adk)
+
+---
+
+## What Agentspan adds to any framework
+
+| Capability | Without Agentspan | With Agentspan |
+|---|---|---|
+| Process crash mid-run | Entire run lost | Resumes from last completed step |
+| Human approval pause | State held in memory | Paused server-side, survives restarts |
+| Execution history | None | Every run stored with inputs, outputs, token usage |
+| Long-running agents | Risk of timeout or OOM | Runs detached from your process |
+| Observability | Framework-specific | Unified across all frameworks |
+
+---
+
+## Tool locality
+
+Regardless of which framework you use, tools in Agentspan run in one of two places:
+
+| Tool type | Where it runs | What you provide |
+|---|---|---|
+| `@tool` (Python function) | **Your worker process** | The function code |
+| `http_tool()` | **Agentspan server** | A URL and optional headers |
+| `api_tool()` | **Agentspan server** | An OpenAPI/Swagger spec URL |
+| `mcp_tool()` | **Agentspan server** | An MCP server URL |
+
+When you wrap a LangGraph graph or OpenAI SDK agent with `AgentRuntime`, its tool functions become worker-executed tasks. Server-side tools (`http_tool`, `api_tool`, `mcp_tool`) run on the server regardless of framework.
+
+See [Tools](/developer-guides/agentspan/concepts/tools) for details.
+
+---
+
+## Native Agentspan
+
+If you're not using an existing framework, define agents natively:
+
+```python
+from conductor.ai.agents import Agent, tool, AgentRuntime
+
+@tool
+def search_web(query: str) -> str:
+ """Search the web for information."""
+ return f"Results for: {query}"
+
+agent = Agent(
+ name="researcher",
+ model="openai/gpt-4o",
+ tools=[search_web],
+ instructions="Research topics thoroughly.",
+)
+
+with AgentRuntime() as runtime:
+ result = runtime.run(agent, "What is quantum entanglement?")
+ result.print_result()
+```
+
+→ [Quickstart](/developer-guides/agentspan/quickstart) · [Agents concept](/developer-guides/agentspan/concepts/agents) · [Tools concept](/developer-guides/agentspan/concepts/tools)
diff --git a/docs/developer-guides/agentspan/reference/providers.mdx b/docs/developer-guides/agentspan/reference/providers.mdx
new file mode 100644
index 00000000..20fa993d
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/providers.mdx
@@ -0,0 +1,207 @@
+---
+slug: "/developer-guides/agentspan/reference/providers"
+title: "LLM Providers"
+description: "All supported LLM providers, model strings, and API key configuration"
+---
+
+# LLM Providers
+
+Agentspan supports 15+ AI providers. Set the environment variables for the providers you want to use before starting the server. The server auto-enables each provider when its key is present — no manual integration setup needed.
+
+## Quick Setup
+
+```bash
+# OpenAI
+export OPENAI_API_KEY=sk-...
+
+# Anthropic
+export ANTHROPIC_API_KEY=sk-ant-...
+
+# Google Gemini
+export GEMINI_API_KEY=AI...
+export GOOGLE_CLOUD_PROJECT=your-gcp-project-id
+
+# Then start the server
+agentspan server start
+```
+
+## Model Format
+
+Specify models in your agents using `provider/model-name`:
+
+```python
+agent = Agent(name="bot", model="openai/gpt-4o")
+agent = Agent(name="bot", model="anthropic/claude-sonnet-4-6")
+agent = Agent(name="bot", model="google_gemini/gemini-2.0-flash")
+```
+
+## All Providers
+
+### OpenAI
+
+| Variable | Description |
+|---|---|
+| `OPENAI_API_KEY` | API key from [platform.openai.com](https://platform.openai.com/api-keys) |
+| `OPENAI_ORG_ID` | Organization ID (optional) |
+
+**Models:** `openai/gpt-4o`, `anthropic/claude-sonnet-4-6`, `openai/gpt-4-turbo`, `openai/o1`, `openai/o1-mini`, `openai/o3-mini`
+
+**Embeddings:** `openai/text-embedding-3-small`, `openai/text-embedding-3-large`
+
+---
+
+### Anthropic (Claude)
+
+| Variable | Description |
+|---|---|
+| `ANTHROPIC_API_KEY` | API key from [console.anthropic.com](https://console.anthropic.com/) |
+
+**Models:** `anthropic/claude-opus-4-20250514`, `anthropic/claude-sonnet-4-6`, `anthropic/claude-3-5-sonnet-20241022`, `anthropic/claude-3-haiku-20240307`
+
+---
+
+### Google Gemini
+
+| Variable | Description |
+|---|---|
+| `GEMINI_API_KEY` | API key from [aistudio.google.com](https://aistudio.google.com/apikey) |
+| `GOOGLE_CLOUD_PROJECT` | **Required.** Your GCP project ID |
+
+**Models:** `google_gemini/gemini-2.0-flash`, `google_gemini/gemini-1.5-pro`, `google_gemini/gemini-1.5-flash`
+
+**Embeddings:** `google_gemini/text-embedding-004`
+
+---
+
+### Azure OpenAI
+
+| Variable | Description |
+|---|---|
+| `AZURE_OPENAI_API_KEY` | API key from Azure portal |
+| `AZURE_OPENAI_ENDPOINT` | **Required.** Endpoint URL, e.g. `https://your-resource.openai.azure.com` |
+| `AZURE_OPENAI_DEPLOYMENT` | **Required.** Deployment name |
+
+**Models:** `azure_openai/gpt-4o`, `azure_openai/gpt-4`, `azure_openai/gpt-3.5-turbo`
+
+---
+
+### AWS Bedrock
+
+| Variable | Description |
+|---|---|
+| `AWS_ACCESS_KEY_ID` | AWS access key |
+| `AWS_SECRET_ACCESS_KEY` | AWS secret key |
+
+**Models:** `aws_bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0`, `aws_bedrock/anthropic.claude-3-haiku-20240307-v1:0`, `aws_bedrock/meta.llama3-70b-instruct-v1:0`, `aws_bedrock/amazon.titan-text-express-v1`
+
+**Embeddings:** `aws_bedrock/amazon.titan-embed-text-v2:0`
+
+---
+
+### Mistral AI
+
+| Variable | Description |
+|---|---|
+| `MISTRAL_API_KEY` | API key from [console.mistral.ai](https://console.mistral.ai/) |
+
+**Models:** `mistral/mistral-large-latest`, `mistral/mistral-medium-latest`, `mistral/mistral-small-latest`, `mistral/open-mixtral-8x7b`
+
+**Embeddings:** `mistral/mistral-embed`
+
+---
+
+### Cohere
+
+| Variable | Description |
+|---|---|
+| `COHERE_API_KEY` | API key from [dashboard.cohere.com](https://dashboard.cohere.com/) |
+
+**Models:** `cohere/command-r-plus`, `cohere/command-r`, `cohere/command`
+
+**Embeddings:** `cohere/embed-english-v3.0`, `cohere/embed-multilingual-v3.0`
+
+---
+
+### Grok (xAI)
+
+| Variable | Description |
+|---|---|
+| `XAI_API_KEY` | API key from xAI |
+
+**Models:** `grok/grok-3`, `grok/grok-3-mini`
+
+---
+
+### Perplexity AI
+
+| Variable | Description |
+|---|---|
+| `PERPLEXITY_API_KEY` | API key from [perplexity.ai](https://www.perplexity.ai/) |
+
+**Models:** `perplexity/sonar-pro`, `perplexity/sonar`
+
+---
+
+### Hugging Face
+
+| Variable | Description |
+|---|---|
+| `HUGGINGFACE_API_KEY` | API token from [huggingface.co](https://huggingface.co/settings/tokens) |
+
+**Models:** `hugging_face/meta-llama/Llama-3-70b-chat-hf`, `hugging_face/mistralai/Mistral-7B-Instruct-v0.2`
+
+---
+
+### Stability AI
+
+| Variable | Description |
+|---|---|
+| `STABILITY_API_KEY` | API key from [platform.stability.ai](https://platform.stability.ai/) |
+
+**Image generation:** `stabilityai/sd3.5-large`, `stabilityai/sd3.5-medium`, `stabilityai/stable-image-core`
+
+---
+
+### DeepSeek
+
+| Variable | Description |
+|---|---|
+| `DEEPSEEK_API_KEY` | API key from DeepSeek |
+
+**Models:** `deepseek/deepseek-chat`
+
+---
+
+### Ollama (local)
+
+No API key required. Ollama must be running and reachable.
+
+| Variable | Description |
+|---|---|
+| `OLLAMA_BASE_URL` | Ollama server URL (default: `http://localhost:11434`) |
+
+**Models:** `ollama/llama3`, `ollama/mistral`, `ollama/phi3`, `ollama/codellama`
+
+**Embeddings:** `ollama/nomic-embed-text`
+
+Install Ollama: [ollama.com/download](https://ollama.com/download)
+
+---
+
+## Summary
+
+| Provider | Env Var | Model Prefix |
+|---|---|---|
+| OpenAI | `OPENAI_API_KEY` | `openai/` |
+| Anthropic | `ANTHROPIC_API_KEY` | `anthropic/` |
+| Google Gemini | `GEMINI_API_KEY` + `GOOGLE_CLOUD_PROJECT` | `google_gemini/` |
+| Azure OpenAI | `AZURE_OPENAI_API_KEY` + endpoint + deployment | `azure_openai/` |
+| AWS Bedrock | `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` | `aws_bedrock/` |
+| Mistral | `MISTRAL_API_KEY` | `mistral/` |
+| Cohere | `COHERE_API_KEY` | `cohere/` |
+| Grok / xAI | `XAI_API_KEY` | `grok/` |
+| Perplexity | `PERPLEXITY_API_KEY` | `perplexity/` |
+| Hugging Face | `HUGGINGFACE_API_KEY` | `hugging_face/` |
+| Stability AI | `STABILITY_API_KEY` | `stabilityai/` |
+| DeepSeek | `DEEPSEEK_API_KEY` | `deepseek/` |
+| Ollama | `OLLAMA_BASE_URL` | `ollama/` |
diff --git a/docs/developer-guides/agentspan/reference/sdk.mdx b/docs/developer-guides/agentspan/reference/sdk.mdx
new file mode 100644
index 00000000..77edb7dc
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/sdk.mdx
@@ -0,0 +1,509 @@
+---
+slug: "/developer-guides/agentspan/reference/sdk"
+title: "SDK Overview"
+description: "Conductor Agent SDK — coordinates, Agent 101, and framework integrations for Python, TypeScript, Java, and C#."
+---
+
+# SDK Overview
+
+The Conductor Agent SDK lets you build and run Agentspan agents in four languages. Install the package, point it at an Agentspan server, and you're running agents in under 30 seconds.
+
+## Quick reference
+
+| Language | Install | Import | Full docs |
+|---|---|---|---|
+| **Python** | `pip install conductor-agent-sdk` | `from conductor.ai.agents import Agent, AgentRuntime` | [Python SDK](python-sdk/README.md) |
+| **TypeScript** | `npm install @conductor-oss/conductor-agent-sdk` | `import { Agent, AgentRuntime } from '@conductor-oss/conductor-agent-sdk'` | [TypeScript SDK](typescript-sdk/README.md) |
+| **Java** | `org.conductoross.conductor:conductor-agent-sdk:0.1.0` | `import org.conductoross.conductor.ai.*` | [Java SDK](java-sdk/index.md) |
+| **C#** | `dotnet add package conductor-agent-sdk` | `using Conductor.AI;` | [C# SDK](csharp-sdk/README.md) |
+
+## Environment setup
+
+All SDKs read the same environment variables:
+
+```bash
+export AGENTSPAN_SERVER_URL=http://localhost:6767/api
+export OPENAI_API_KEY=
+export AGENTSPAN_LLM_MODEL=openai/gpt-4o-mini
+```
+
+Start a local server:
+
+```bash
+agentspan server start # downloads the runtime jar on first run, starts on :6767
+```
+
+---
+
+## Agent 101
+
+The minimal loop: define an `Agent`, open a runtime, call `run`.
+
+---
+#### Python
+
+ ```python
+ from conductor.ai.agents import Agent, AgentRuntime, tool
+
+ @tool
+ def get_weather(city: str) -> str:
+ """Return current weather for a city."""
+ return f"72°F and sunny in {city}"
+
+ agent = Agent(
+ name="weather_agent",
+ model="anthropic/claude-sonnet-4-6",
+ instructions="You are a helpful assistant. Use available tools.",
+ tools=[get_weather],
+ )
+
+ with AgentRuntime() as runtime:
+ result = runtime.run(agent, "What's the weather in San Francisco?")
+ result.print_result()
+ ```
+---
+#### TypeScript
+
+ ```ts
+ import { Agent, AgentRuntime, tool } from '@conductor-oss/conductor-agent-sdk';
+ import { z } from 'zod';
+
+ const getWeather = tool({
+ name: 'get_weather',
+ description: 'Return current weather for a city.',
+ parameters: z.object({ city: z.string() }),
+ execute: async ({ city }) => `72°F and sunny in ${city}`,
+ });
+
+ const agent = new Agent({
+ name: 'weather_agent',
+ model: 'anthropic/claude-sonnet-4-6',
+ instructions: 'You are a helpful assistant. Use available tools.',
+ tools: [getWeather],
+ });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(agent, "What's the weather in San Francisco?");
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+---
+#### Java
+
+ ```java
+ import org.conductoross.conductor.ai.Agent;
+ import org.conductoross.conductor.ai.AgentRuntime;
+ import org.conductoross.conductor.ai.tool.Tool;
+
+ public class WeatherExample {
+ @Tool(description = "Return current weather for a city.")
+ public static String getWeather(String city) {
+ return "72°F and sunny in " + city;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Agent agent = Agent.builder()
+ .name("weather_agent")
+ .model("anthropic/claude-sonnet-4-6")
+ .instructions("You are a helpful assistant. Use available tools.")
+ .tools(WeatherExample.class)
+ .build();
+
+ try (AgentRuntime runtime = new AgentRuntime()) {
+ var result = runtime.run(agent, "What's the weather in San Francisco?");
+ result.printResult();
+ }
+ }
+ }
+ ```
+
+---
+#### C#
+
+ ```csharp
+ using Conductor.AI;
+ using Conductor.AI.Tools;
+
+ [AgentTools]
+ public static class WeatherTools
+ {
+ [AgentTool(Description = "Return current weather for a city.")]
+ public static string GetWeather(string city) =>
+ $"72°F and sunny in {city}";
+ }
+
+ var agent = new Agent("weather_agent")
+ {
+ Model = "anthropic/claude-sonnet-4-6",
+ Instructions = "You are a helpful assistant. Use available tools.",
+ Tools = ToolRegistry.FromType(),
+ };
+
+ await using var runtime = new AgentRuntime();
+ var result = await runtime.RunAsync(agent, "What's the weather in San Francisco?");
+ result.PrintResult();
+ ```
+
+---
+
+## What `run()` returns
+
+All four SDKs return an `AgentResult` with the same fields:
+
+| Field | Description |
+|---|---|
+| `output` / `Output` | Final text response from the agent |
+| `execution_id` / `ExecutionId` | Server-side workflow execution ID — use to poll, stream, or inspect |
+| `status` | `COMPLETED`, `FAILED`, `TIMED_OUT` |
+| `usage` | Token counts (input, output, total) |
+| `print_result()` / `PrintResult()` | Pretty-print to stdout |
+
+---
+
+## Framework agents
+
+You don't have to rewrite agents authored in another framework. Pass the framework object directly to `runtime.run()` — the runtime auto-detects the framework and runs it on Agentspan.
+
+### LangGraph
+
+---
+#### Python
+
+ ```python
+ import math
+ from langchain_core.tools import tool
+ from langchain_openai import ChatOpenAI
+ from langgraph.prebuilt import create_react_agent
+ from conductor.ai.agents import AgentRuntime
+
+ @tool
+ def calculate(expression: str) -> str:
+ """Evaluate a safe math expression."""
+ return str(eval(expression, {"__builtins__": {}}, {"sqrt": math.sqrt, "pi": math.pi}))
+
+ llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
+ graph = create_react_agent(llm, tools=[calculate], name="math_agent")
+
+ with AgentRuntime() as runtime:
+ result = runtime.run(graph, "What is sqrt(256) + 2**10?")
+ result.print_result()
+ ```
+
+---
+#### TypeScript
+
+ ```ts
+ import { createReactAgent } from '@langchain/langgraph/prebuilt';
+ import { ChatOpenAI } from '@langchain/openai';
+ import { tool } from '@langchain/core/tools';
+ import { z } from 'zod';
+ import { AgentRuntime } from '@conductor-oss/conductor-agent-sdk';
+
+ const calculate = tool(
+ async ({ expression }) => String(eval(expression)),
+ { name: 'calculate', description: 'Evaluate a math expression.',
+ schema: z.object({ expression: z.string() }) }
+ );
+
+ const llm = new ChatOpenAI({ model: 'gpt-4o-mini', temperature: 0 });
+ const graph = createReactAgent({ llm, tools: [calculate], name: 'math_agent' });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(graph, 'What is sqrt(256) + 2**10?');
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+---
+#### Java (LangGraph4j)
+
+ ```java
+ import dev.langchain4j.model.openai.OpenAiChatModel;
+ import org.bsc.langgraph4j.agentexecutor.AgentExecutor;
+ import org.conductoross.conductor.ai.AgentRuntime;
+
+ var model = OpenAiChatModel.builder()
+ .apiKey("agentspan-server-handles-credentials")
+ .modelName("anthropic/claude-sonnet-4-6")
+ .build();
+
+ AgentExecutor.Builder agent = AgentExecutor.builder().chatModel(model);
+
+ try (AgentRuntime runtime = new AgentRuntime()) {
+ var result = runtime.run(agent, "What is sqrt(256) + 2**10?");
+ result.printResult();
+ }
+ ```
+
+---
+
+### LangChain
+
+---
+##### Python
+
+ ```python
+ from conductor.ai.agents import AgentRuntime
+ from langchain.agents import create_tool_calling_agent, AgentExecutor
+ from langchain_core.prompts import ChatPromptTemplate
+ from langchain_core.tools import tool
+ from langchain_openai import ChatOpenAI
+
+ @tool
+ def lookup_order(order_id: str) -> str:
+ """Look up an order by ID."""
+ return f"Order {order_id}: shipped, arriving tomorrow."
+
+ llm = ChatOpenAI(model="gpt-4o-mini")
+ prompt = ChatPromptTemplate.from_messages([
+ ("system", "You are an order support assistant."),
+ ("human", "{input}"),
+ ("placeholder", "{agent_scratchpad}"),
+ ])
+ lc_agent = create_tool_calling_agent(llm, [lookup_order], prompt)
+ executor = AgentExecutor(agent=lc_agent, tools=[lookup_order])
+
+ with AgentRuntime() as runtime:
+ result = runtime.run(executor, "Where is order #12345?")
+ result.print_result()
+ ```
+
+---
+#### TypeScript
+
+ ```ts
+ import { createAgentExecutor } from '@conductor-oss/conductor-agent-sdk/langchain';
+ import { AgentRuntime } from '@conductor-oss/conductor-agent-sdk';
+ import { ChatOpenAI } from '@langchain/openai';
+ import { tool } from '@langchain/core/tools';
+ import { z } from 'zod';
+
+ const lookupOrder = tool(
+ async ({ orderId }) => `Order ${orderId}: shipped, arriving tomorrow.`,
+ { name: 'lookup_order', description: 'Look up an order.',
+ schema: z.object({ orderId: z.string() }) }
+ );
+
+ const llm = new ChatOpenAI({ model: 'gpt-4o-mini' });
+ const executor = createAgentExecutor({ llm, tools: [lookupOrder] });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(executor, 'Where is order #12345?');
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+---
+
+### OpenAI Agents SDK
+
+---
+#### Python
+
+ ```python
+ from conductor.ai import Runner # drop-in: replaces `from agents import Runner`
+ from agents import Agent, function_tool
+
+ @function_tool
+ def get_weather(city: str) -> str:
+ return f"72°F and sunny in {city}"
+
+ agent = Agent(
+ name="weather_assistant",
+ model="gpt-4o",
+ tools=[get_weather],
+ instructions="You are a helpful assistant.",
+ )
+
+ result = Runner.run_sync(agent, "What's the weather in NYC?")
+ print(result.final_output)
+ ```
+
+ One import change — everything else stays as written.
+
+---
+#### TypeScript
+
+ ```ts
+ import { Agent, setTracingDisabled } from '@openai/agents';
+ import { AgentRuntime } from '@conductor-oss/conductor-agent-sdk';
+
+ setTracingDisabled(true);
+
+ const agent = new Agent({
+ name: 'support_agent',
+ instructions: 'You are a helpful support assistant.',
+ model: 'gpt-4o',
+ });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(agent, 'How do I reset my password?');
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+---
+#### Java
+
+ ```java
+ import org.conductoross.conductor.ai.Agent;
+ import org.conductoross.conductor.ai.AgentRuntime;
+ import org.conductoross.conductor.ai.Strategy;
+
+ // OpenAI Agents SDK agents are expressed as native Agentspan agents
+ // with Strategy.HANDOFF for multi-agent handoffs
+ Agent agent = Agent.builder()
+ .name("support_agent")
+ .model("gpt-4o")
+ .instructions("You are a helpful support assistant.")
+ .strategy(Strategy.HANDOFF)
+ .build();
+
+ try (AgentRuntime runtime = new AgentRuntime()) {
+ var result = runtime.run(agent, "How do I reset my password?");
+ result.printResult();
+ }
+ ```
+
+---
+
+### Google ADK
+
+---
+#### Python
+
+ ```python
+ from google.adk.agents import LlmAgent
+ from google.adk.tools import FunctionTool
+ from conductor.ai.agents import AgentRuntime
+
+ def get_weather(city: str) -> dict:
+ """Get current weather for a city."""
+ return {"city": city, "condition": "Sunny", "temp_c": 22}
+
+ adk_agent = LlmAgent(
+ name="weather_agent",
+ model="gemini-2.0-flash",
+ instruction="Answer weather questions using tools.",
+ tools=[FunctionTool(func=get_weather)],
+ )
+
+ with AgentRuntime() as runtime:
+ result = runtime.run(adk_agent, "What's the weather in Tokyo?")
+ result.print_result()
+ ```
+
+---
+#### TypeScript
+
+ ```ts
+ import { LlmAgent } from '@google/adk';
+ import { AgentRuntime } from '@conductor-oss/conductor-agent-sdk';
+
+ const agent = new LlmAgent({
+ name: 'weather_agent',
+ model: 'gemini-2.0-flash',
+ instruction: 'Answer weather questions using available tools.',
+ });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(agent, "What's the weather in Tokyo?");
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+---
+#### Java
+
+ ```java
+ import com.google.adk.agents.LlmAgent;
+ import org.conductoross.conductor.ai.AgentRuntime;
+ import org.conductoross.conductor.ai.frameworks.AdkBridge;
+
+ LlmAgent adkAgent = LlmAgent.builder()
+ .name("weather_agent")
+ .model("gemini-2.0-flash")
+ .instruction("Answer weather questions.")
+ .build();
+
+ try (AgentRuntime runtime = new AgentRuntime()) {
+ var result = runtime.run(AdkBridge.toAgentspan(adkAgent), "What's the weather in Tokyo?");
+ result.printResult();
+ }
+ ```
+
+---
+
+### Vercel AI SDK
+
+---
+#### TypeScript
+
+ **Option 1 — Use AI SDK tools on a native Agent (recommended):**
+
+ The Conductor Agent SDK auto-detects Vercel AI SDK `tool()` objects — no wrapper needed.
+
+ ```ts
+ import { tool as aiTool } from 'ai';
+ import { z } from 'zod';
+ import { Agent, AgentRuntime } from '@conductor-oss/conductor-agent-sdk';
+
+ const getWeather = aiTool({
+ description: 'Get current weather for a city.',
+ parameters: z.object({ city: z.string() }),
+ execute: async ({ city }) => ({ city, tempF: 72, condition: 'Sunny' }),
+ });
+
+ const agent = new Agent({
+ name: 'weather_agent',
+ model: 'anthropic/claude-sonnet-4-6',
+ instructions: 'Use tools to answer weather questions.',
+ tools: [getWeather],
+ });
+
+ const runtime = new AgentRuntime();
+ try {
+ const result = await runtime.run(agent, "What's the weather in SF?");
+ result.printResult();
+ } finally {
+ await runtime.shutdown();
+ }
+ ```
+
+ **Option 2 — Drop-in `generateText`:**
+
+ ```ts
+ import { generateText } from '@conductor-oss/conductor-agent-sdk/vercel-ai';
+
+ const { text } = await generateText({
+ model: 'anthropic/claude-sonnet-4-6',
+ prompt: 'Write a haiku about durable execution.',
+ });
+ console.log(text);
+ ```
+
+---
+
+## Next steps
+
+- [Why Agentspan](why-agentspan.md) — the case for server-side execution
+- [Quickstart](quickstart.md) — full local setup in 60 seconds
+- [Plan-Execute](concepts/plan-execute.md) — dynamic agents with deterministic execution
+- [Scheduling](scheduling.md) — cron-triggered agents
+- Per-SDK deep dives: [Python](python-sdk/README.md) · [TypeScript](typescript-sdk/README.md) · [Java](java-sdk/index.md) · [C#](csharp-sdk/README.md)
diff --git a/docs/developer-guides/agentspan/reference/self-hosting.mdx b/docs/developer-guides/agentspan/reference/self-hosting.mdx
new file mode 100644
index 00000000..b3c9f3c4
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/self-hosting.mdx
@@ -0,0 +1,168 @@
+---
+slug: "/developer-guides/agentspan/reference/self-hosting"
+title: "Self-Hosting"
+description: "Run the Agentspan server on your own infrastructure — single VM, multi-node, or managed cloud"
+---
+
+# Self-Hosting
+
+Self-hosting Agentspan means running the Agentspan server on your own infrastructure. The server is a Spring Boot application backed by PostgreSQL. Workers are stateless Python processes that connect to it.
+
+## Architecture
+
+```mermaid
+sequenceDiagram
+ participant W1 as Python Worker 1 (your code)
+ participant W2 as Python Worker 2 (your code)
+ participant S as Agentspan Server :6767
+ participant DB as PostgreSQL
+ Note over S: UI (React dashboard) + REST API + Conductor engine
+ W1->>S: poll for tasks
+ S->>DB: read task queue
+ DB-->>S: pending tasks
+ S-->>W1: task assignment
+ W1->>W1: execute tool
+ W1->>S: report result
+ S->>DB: persist result
+ W2->>S: poll for tasks
+ S->>DB: read task queue
+ DB-->>S: pending tasks
+ S-->>W2: task assignment
+ W2->>W2: execute tool
+ W2->>S: report result
+ S->>DB: persist result
+```
+
+Workers poll the server for tasks to execute. Add more workers to scale throughput. Workers are completely stateless.
+
+## Single VM — Docker Compose
+
+The fastest way to self-host. Uses the compose stack from the repo:
+
+```bash
+git clone https://github.com/agentspan-ai/agentspan.git
+cd agentspan/deployment/docker-compose
+cp .env.example .env
+```
+
+Edit `.env` to set your LLM provider API keys (e.g. `OPENAI_API_KEY=sk-...`), then:
+
+```bash
+docker compose up -d
+```
+
+This starts:
+- **agentspan** — the server, accessible at `http://localhost:6767`
+- **postgres** — PostgreSQL 16
+
+Verify:
+
+```bash
+curl http://localhost:6767/actuator/health
+docker compose logs --tail=50 agentspan
+```
+
+Stop and clean up:
+
+```bash
+docker compose down # stops containers, keeps data
+docker compose down -v # stops containers, removes postgres volume
+```
+
+## Running Workers
+
+Workers are Python processes that connect to the server. Run them on the same host or on separate machines:
+
+```bash
+export AGENTSPAN_SERVER_URL=http://your-server:6767
+export OPENAI_API_KEY=sk-...
+python my_agent.py
+```
+
+Your agent code uses `AgentRuntime` as usual:
+
+```python
+from conductor.ai.agents import Agent, AgentRuntime, tool
+
+@tool
+def process_data(input: str) -> str:
+ """Process some data."""
+ return f"Processed: {input}"
+
+agent = Agent(name="processor", model="openai/gpt-4o", tools=[process_data])
+
+with AgentRuntime() as runtime:
+ result = runtime.run(agent, "Process this dataset")
+ result.print_result()
+```
+
+Run multiple worker processes in parallel to increase tool execution throughput.
+
+## Authentication
+
+For any server that isn't running on localhost, enable auth:
+
+```bash
+# In server .env file:
+AGENTSPAN_AUTH_KEY=your-app-key
+AGENTSPAN_AUTH_SECRET=your-app-secret
+
+# In worker environment:
+export AGENTSPAN_SERVER_URL=https://your-server.example.com
+export AGENTSPAN_AUTH_KEY=your-app-key
+export AGENTSPAN_AUTH_SECRET=your-app-secret
+```
+
+Or configure in code:
+
+```python
+from conductor.ai.agents import configure
+
+configure(
+ server_url="https://your-server.example.com",
+ auth_key="your-app-key",
+ auth_secret="your-app-secret",
+)
+```
+
+## Multi-Node / Kubernetes
+
+For multi-node deployments, use the Kubernetes manifests or Helm chart from `deployment/k8s/` and `deployment/helm/` in the repo.
+
+Key points:
+- Run multiple server replicas for high availability
+- Use a managed PostgreSQL (RDS, Cloud SQL, etc.) not a containerized one
+- Workers scale independently from the server — add as many as needed
+- All server replicas share the same database
+
+See [Deployment](/developer-guides/agentspan/reference/deployment) for Kubernetes YAML examples.
+
+## Configuration Reference
+
+The server is configured via environment variables:
+
+| Variable | Default | Description |
+|---|---|---|
+| `SERVER_PORT` | `6767` | Port the server listens on |
+| `SPRING_PROFILES_ACTIVE` | `default` (SQLite) | Set to `postgres` for PostgreSQL |
+| `SPRING_DATASOURCE_URL` | `jdbc:sqlite:agent-runtime.db` | JDBC database URL |
+| `SPRING_DATASOURCE_USERNAME` | `postgres` | Database user |
+| `SPRING_DATASOURCE_PASSWORD` | `postgres` | Database password |
+| `SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE` | `8` | Connection pool size |
+| `AGENTSPAN_AUTH_KEY` | — | Application auth key |
+| `AGENTSPAN_AUTH_SECRET` | — | Application auth secret |
+| `OPENAI_API_KEY` | — | OpenAI API key |
+| `ANTHROPIC_API_KEY` | — | Anthropic API key |
+| `GEMINI_API_KEY` | — | Google Gemini API key |
+
+All LLM provider keys follow the same pattern — set the key, the server auto-enables that provider.
+
+## Backup and Recovery
+
+Agentspan stores all execution state in PostgreSQL. Back up regularly using standard PostgreSQL tools:
+
+```bash
+pg_dump agentspan > backup.sql
+```
+
+Execution state is durable — in-progress executions resume after a server restart as long as the database is intact.
diff --git a/docs/developer-guides/agentspan/reference/worker-types.mdx b/docs/developer-guides/agentspan/reference/worker-types.mdx
new file mode 100644
index 00000000..7d685948
--- /dev/null
+++ b/docs/developer-guides/agentspan/reference/worker-types.mdx
@@ -0,0 +1,89 @@
+---
+slug: "/developer-guides/agentspan/reference/worker-types"
+title: "Agentspan Worker Types"
+---
+
+# Agentspan Worker Types
+
+Workers are functions registered as Conductor task pollers. They execute locally (SDK-side)
+while execution orchestration happens server-side. Both Python and TypeScript SDKs implement
+all worker types with identical behavior.
+
+## Quick Reference
+
+| # | Worker Type | Task Name Pattern | Trigger |
+|---|-------------|-------------------|---------|
+| 1 | Tool | `{tool_name}` | `agent.tools` with `tool_type == "worker"` |
+| 2 | CLI Command | `{agent_name}_run_command` | `agent.cli_commands == True` |
+| 3 | Code Execution | `{agent_name}_execute_code` | `agent.local_code_execution == True` |
+| 4 | Output Guardrail (combined) | `{agent_name}_output_guardrail` | Custom guardrails (local compile path) |
+| 5 | Individual Guardrail | `{guardrail.name}` | Custom guardrails (server compile path) |
+| 6 | Stop When | `{agent_name}_stop_when` | `agent.stop_when` is callable |
+| 7 | Gate | `{agent_name}_gate` | `agent.gate` is callable |
+| 8 | Callback | `{agent_name}_{position}` | `agent.callbacks` |
+| 9 | Termination | `{agent_name}_termination` | `agent.termination` is set |
+| 10 | Check Transfer | `{agent_name}_check_transfer` | Hybrid or swarm agent |
+| 11 | Router Function | `{agent_name}_router_fn` | `strategy == "router"` with callable router |
+| 12 | Handoff Check | `{agent_name}_handoff_check` | `agent.handoffs` is non-empty |
+| 13 | Swarm Transfer | `{source_agent}_transfer_to_{peer}` | `strategy == "swarm"` with sub-agents |
+| 14 | Manual Selection | `{agent_name}_process_selection` | `strategy == "manual"` with sub-agents |
+| 15 | Framework | `{worker.name}` | Foreign framework with extractable tools |
+| 16 | Framework Passthrough | `{worker_name}` | Foreign framework (passthrough) |
+| 17 | Claude Code Passthrough | `{agent_name}` | `model="claude-code/..."` |
+
+## Task Definition Registration
+
+**Task definitions are registered by the server during agent compilation.** SDKs do NOT register
+task definitions — they only poll for tasks. The server returns `requiredWorkers` in the
+start/deploy response so SDKs know exactly which workers to register.
+
+| Setting | Value | Source |
+|----------------------|----------------|--------|
+| `timeoutSeconds` | 0 (no timeout) | `AgentService.registerTaskDef()` |
+| `responseTimeoutSeconds` | 3600 (1 hour) | Conductor requires minimum 1s |
+| Retry count | 2 | Server-side |
+| Retry logic | LINEAR_BACKOFF | Server-side |
+| Retry delay | 2 s | Server-side |
+
+## Task Name Prefixing Rules
+
+All auto-generated task names MUST be prefixed with the agent name to prevent collisions
+when multiple agents share the same Conductor namespace.
+
+| Category | Pattern | Example |
+|---|---|---|
+| System workers | `{agentName}_{type}` | `my_agent_termination` |
+| CLI tools | `{agentName}_run_command` | `git_fetch_run_command` |
+| Code execution | `{agentName}_execute_code` | `coder_execute_code` |
+| Swarm transfers | `{sourceAgent}_transfer_to_{peer}` | `coder_transfer_to_qa_tester` |
+| User-defined tools | `{tool_name}` (user-controlled) | `get_weather` |
+
+## Credentials
+
+Credentials are always resolved from the server. There is no environment variable fallback.
+
+- **Execution token present** → `POST /api/workers/secrets` → injected into `process.env`/`os.environ`
+- **No execution token** → `FAILED_WITH_TERMINAL_ERROR` (non-retryable)
+- **Credentials not found on server** → `FAILED_WITH_TERMINAL_ERROR` (non-retryable)
+- **Cleanup** → credentials removed from environment after tool execution
+
+Store credentials with: `agentspan credentials set --name `
+
+## TypeScript Parity
+
+Both Python and TypeScript SDKs implement all 17 worker types. The TypeScript SDK includes:
+- All SWARM workers (transfer_to, check_transfer, handoff_check, process_selection)
+- Claude Code agent support (`ClaudeCode` class, `PermissionMode` enum)
+- CLI command execution (`CliConfig`, `makeCliTool()`)
+- Code execution validators (`CommandValidator`)
+- LLM guardrails (`LLMGuardrail` class)
+- Credential resolution and injection (`resolveCredentials`, `injectCredentials`)
+
+## Worker Lifecycle
+
+1. **Server compilation** — Server compiles agent → registers all task definitions → returns `requiredWorkers` list
+2. **SDK registration** — SDK registers workers (poll functions) for task names in `requiredWorkers`
+3. **Polling** — Workers poll Conductor for tasks, execute functions, report results
+4. **Credentials** — Before tool execution, credentials are resolved from server and injected
+5. **Monitoring** — TaskHandler checks process health every 5s and restarts dead workers
+6. **Shutdown** — Workers stopped during `AgentRuntime.shutdown()`
diff --git a/docs/developer-guides/agentspan/why-agentspan.mdx b/docs/developer-guides/agentspan/why-agentspan.mdx
new file mode 100644
index 00000000..91537b66
--- /dev/null
+++ b/docs/developer-guides/agentspan/why-agentspan.mdx
@@ -0,0 +1,118 @@
+---
+slug: "/developer-guides/agentspan/why-agentspan"
+title: "Why Agentspan"
+description: "Why agents fail in production, and how Agentspan's server-side execution model solves it."
+---
+
+# Why Agentspan
+
+**Agentspan is a durable runtime for AI agents, built for Conductor. Your code runs in your process. Execution state lives on the server — so crashes, restarts, and deployments don't lose work.**
+
+
+
+---
+
+## How most agent frameworks work (_and what could go wrong?_)
+
+Most agent frameworks — LangGraph, the OpenAI Agents SDK, Google ADK, and others — run the agent loop inside your process. Your code calls the LLM, receives a tool call, executes the tool, and loops. All of that happens in memory, in your process.
+
+```
+Your process
+└── agent loop
+ ├── call LLM
+ ├── execute tool
+ ├── call LLM again
+ └── ...until done
+```
+This works fine on your laptop. In production, it breaks in predictable ways.
+
+### What can go wrong
+
+**Process crash mid-run.** A long-running agent — one that searches the web, reads files, calls APIs across dozens of steps — can take minutes. If your process dies (OOM kill, deploy, network drop), the entire run is gone. There is no way to resume from where it stopped.
+
+**Human-in-the-loop doesn't survive restarts.** Pausing an agent to wait for a human approval means holding state in memory. If anything interrupts that wait — a timeout, a restart, a deploy — the approval request is lost and the agent can't resume.
+
+**No history, no replay.** In-process execution leaves no record. You can't see what an agent did on a past run, replay a run with a different model, or query execution history across agents.
+
+**Scaling means duplicating state.** Running agents across multiple machines means solving distributed state management yourself — or accepting that each agent instance is isolated with no shared execution context.
+
+**No scheduling without external infrastructure.** Running an agent on a cron means maintaining a separate scheduler, handling missed fires, and managing overlap. Any of those can fail silently — and there's no execution history tied to your agent when it does.
+
+**Background jobs block or disappear.** Firing an agent asynchronously in-process — via threading or asyncio — means the job dies when your process does. There's no durable handle, no execution record, and no way to push new events into it from another process.
+
+---
+
+## How Agentspan separates orchestration from execution
+
+Agentspan separates where your code runs from where execution state lives.
+
+```
+Your process Agentspan server
+└── worker └── agent execution
+ ├── registers tools ├── tracks current step
+ └── executes tool calls ←──────── delegates tool work
+ ├── retries on failure
+ ├── holds HITL state
+ └── stores full history
+```
+
+Your agent definition compiles into a durable workflow on the Agentspan server. The server orchestrates execution — calling your worker to run tools, tracking state at every step, and resuming from the last completed step if anything goes wrong.
+
+Your process can crash, restart, or be replaced. The agent keeps running.
+
+---
+
+## What this enables
+
+### Long-running agents
+
+**Crash recovery.** If your worker process dies mid-run, the server resumes execution when a new worker connects. No work is re-run from scratch — it picks up at the current step.
+
+**Durable human-in-the-loop.** Mark any tool with `approval_required=True`. The agent pauses server-side and waits indefinitely — no timeouts, no in-memory state at risk. Approve or deny via CLI, API, or the UI.
+
+**Full execution history.** Every run is stored with inputs, outputs, token usage, and per-step timing. Query via CLI, browse in the UI at `http://localhost:6767`, or replay any past run.
+
+### Dynamic agents (Plan-Execute)
+
+**LLM plans, Conductor executes.** Define a planner agent that emits a JSON DAG of operations at runtime — adapting the plan to the specific task and inputs. The server compiles it into an immutable Conductor sub-workflow: no LLM involved in orchestration, retries, parallelism, or validation. The plan is fixed once compiled — replay-safe and branch-stable. See [Plan-Execute](concepts/plan-execute.md).
+
+**Call existing Conductor workflows.** Plan steps can invoke any deployed Conductor workflow as a sub-workflow. This bridges dynamic AI planning with your existing deterministic business automation — the LLM decides when to call it; Conductor handles the execution.
+
+### Event-driven agents
+
+**Scheduled agents.** Attach one or more crons to any agent at deploy time. The server fires the agent on cadence, tracks every execution, and lets you pause, resume, or trigger ad-hoc — without touching application code. See [Scheduling](scheduling.md).
+
+**Conductor event handlers.** Agentspan runs on Conductor, which has native integrations for Kafka, SQS, AMQP, webhooks, and database events. Any event source that can trigger a Conductor workflow can trigger an agent — with a full durable execution record for every event.
+
+### Adaptive loops
+
+**Durable iterations.** Any framework can write a `while` loop. In Agentspan, each iteration is a Conductor workflow execution — crash mid-loop and the current iteration resumes when a worker reconnects. The loop itself survives process failures.
+
+**Single execution ID across all iterations.** Using DO_WHILE inside a Conductor workflow, every iteration appears as a suffixed task (`planner_llm__1`, `planner_llm__2`, ...) under one workflow ID. The entire loop is observable, queryable, and replayable as a unit in the UI.
+
+**Deterministic inner × adaptive outer.** Combine Plan-Execute (deterministic per-iteration execution) with an outer loop that adapts based on verified results. The LLM decides *what* to try next; Conductor handles *how* each attempt runs — with full parallelism, retry, and validation built in.
+
+See [Adaptive Loops](concepts/adaptive-loops.md).
+
+### Framework compatibility
+
+**Works with frameworks you already use.** Pass a LangGraph `StateGraph`, an OpenAI Agents SDK `Agent`, or a Google ADK pipeline directly to `runtime.run()`. Your definitions stay unchanged.
+
+---
+
+## Frequently asked questions
+
+**What makes Agentspan different from LangGraph?**
+LangGraph is a graph framework for defining agent routing logic — nodes, edges, conditional branching. Agentspan is an execution runtime. You can pass a compiled LangGraph app directly to `runtime.run()` and it gains crash recovery, HITL, and execution history without changing a single node. They work together.
+
+**What makes Agentspan different from the OpenAI Agents SDK?**
+The OpenAI Agents SDK defines agents, handoffs, and tools. Its execution model is in-process. Agentspan wraps that execution so it runs server-side — your agent definitions, handoffs, and tools stay exactly as written.
+
+**When should I use Agentspan?**
+Whenever agents need to run reliably in production: long-running tasks, human approval steps, jobs that must survive process restarts, or situations where you need a queryable history of what every agent did.
+
+**Does Agentspan replace my existing framework?**
+No. If you use LangGraph, the OpenAI Agents SDK, or Google ADK, pass your existing agent directly to `runtime.run()`. If you write agents natively, use the `Agent` class — one Python object with tools, instructions, and strategy.
+
+**What model providers does Agentspan support?**
+Any provider with an OpenAI-compatible API. Set the model with one string: `"openai/gpt-4o"`, `"anthropic/claude-sonnet-4-6"`, `"google_gemini/gemini-2.0-flash"`. See [LLM Providers](/developer-guides/agentspan/reference/providers) for the full list.
diff --git a/sidebars.js b/sidebars.js
index e26fe4d7..02edb875 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -225,7 +225,83 @@ const sidebars = {
items: [
'developer-guides/using-llms-in-your-orkes-conductor-workflows',
'developer-guides/using-vector-databases-in-your-orkes-conductor-workflows',
- 'developer-guides/using-ai-prompts'
+ 'developer-guides/using-ai-prompts',
+ {
+ type: 'category',
+ label: 'Agentspan',
+ className: 'leftMenuHeader',
+ link: {
+ type: 'doc',
+ id: 'developer-guides/agentspan/overview',
+ },
+ items: [
+ 'developer-guides/agentspan/why-agentspan',
+ 'developer-guides/agentspan/quickstart',
+ {
+ type: 'category',
+ label: 'Concepts',
+ link: {
+ type: 'generated-index',
+ title: 'Agentspan Concepts',
+ slug: '/developer-guides/agentspan/concepts',
+ description: 'Learn the core Agentspan concepts for durable AI agents, including tools, memory, streaming, guardrails, scheduling, and multi-agent coordination.',
+ },
+ items: [
+ 'developer-guides/agentspan/concepts/agents',
+ 'developer-guides/agentspan/concepts/tools',
+ 'developer-guides/agentspan/concepts/skills',
+ 'developer-guides/agentspan/concepts/multi-agent',
+ 'developer-guides/agentspan/concepts/plan-execute',
+ 'developer-guides/agentspan/concepts/adaptive-loops',
+ 'developer-guides/agentspan/concepts/guardrails',
+ 'developer-guides/agentspan/concepts/memory',
+ 'developer-guides/agentspan/concepts/streaming',
+ 'developer-guides/agentspan/concepts/scheduling',
+ 'developer-guides/agentspan/concepts/testing',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Examples',
+ link: {
+ type: 'generated-index',
+ title: 'Agentspan Examples',
+ slug: '/developer-guides/agentspan/examples',
+ description: 'Build durable AI agents with examples for support triage, research pipelines, document processing, crash recovery, human review, LangGraph, OpenAI Agents SDK, and Google ADK.',
+ },
+ items: [
+ 'developer-guides/agentspan/examples/support-triage',
+ 'developer-guides/agentspan/examples/research-pipeline',
+ 'developer-guides/agentspan/examples/document-processor',
+ 'developer-guides/agentspan/examples/crash-resume',
+ 'developer-guides/agentspan/examples/human-in-the-loop',
+ 'developer-guides/agentspan/examples/langgraph',
+ 'developer-guides/agentspan/examples/openai-agents-sdk',
+ 'developer-guides/agentspan/examples/google-adk',
+ ],
+ },
+ {
+ type: 'category',
+ label: 'Reference',
+ link: {
+ type: 'generated-index',
+ title: 'Agentspan Reference',
+ slug: '/developer-guides/agentspan/reference',
+ description: 'Reference pages for Agentspan providers, model configuration, CLI commands, deployment, self-hosting, integrations, and worker types.',
+ },
+ items: [
+ 'developer-guides/agentspan/reference/sdk',
+ 'developer-guides/agentspan/reference/providers',
+ 'developer-guides/agentspan/reference/ai-models',
+ 'developer-guides/agentspan/reference/cli',
+ 'developer-guides/agentspan/reference/deployment',
+ 'developer-guides/agentspan/reference/self-hosting',
+ 'developer-guides/agentspan/reference/integrations',
+ 'developer-guides/agentspan/reference/worker-types',
+ ],
+ },
+ ],
+ },
],
},
{