diff --git a/content/develop/ai/_index.md b/content/develop/ai/_index.md
index 17021e2bbf..d488360269 100644
--- a/content/develop/ai/_index.md
+++ b/content/develop/ai/_index.md
@@ -68,7 +68,7 @@ AI agents are autonomous systems that combine LLMs with memory, tools, and plann
The [Context Engine]({{< relref "/develop/ai/context-engine" >}}) (Redis Iris) includes four services, available fully managed on Redis Cloud or self-managed on your own infrastructure:
-- [LangCache]({{< relref "/develop/ai/context-engine/langcache" >}}): Semantic caching that reduces LLM API costs and improves response times by reusing cached responses for similar queries.
+- [LangCache]({{< relref "/develop/ai/langcache" >}}): Semantic caching that reduces LLM API costs and improves response times by reusing cached responses for similar queries.
- [Redis Agent Memory]({{< relref "/develop/ai/context-engine/agent-memory" >}}): Two-tier persistent memory (session and long-term) for agents, available through Python and TypeScript SDKs and a REST API.
- [Context Gateway]({{< relref "/develop/ai/context-engine/context-gateway" >}}): Gives agents one Model Context Protocol (MCP) endpoint for the tools of any MCP server, and serves your Redis data as tools with Context Surfaces.
- [Data Integration]({{< relref "/develop/ai/context-engine/data-integration" >}}): Keeps your Redis Cloud database in sync with relational databases in near real time using Change Data Capture.
@@ -80,7 +80,7 @@ The [Context Engine]({{< relref "/develop/ai/context-engine" >}}) (Redis Iris) i
1. [**Search with vectors**]({{< relref "develop/ai/search-and-query/vectors#search-with-vectors" >}}): Redis supports several advanced querying strategies with vector fields including k-nearest neighbor ([KNN]({{< relref "develop/ai/search-and-query/vectors#knn-vector-search" >}})), [vector range queries]({{< relref "develop/ai/search-and-query/vectors#vector-range-queries" >}}), and [metadata filters]({{< relref "develop/ai/search-and-query/vectors#filters" >}}).
1. [**Configure vector queries at runtime**]({{< relref "develop/ai/search-and-query/vectors#runtime-query-parameters" >}}): Select the best filter mode to optimize query execution.
1. [**Build an AI agent**]({{< relref "/develop/ai/agent-builder" >}}): Use the interactive agent builder to generate complete working code for conversational assistants and recommendation engines.
-1. [**Add semantic caching**]({{< relref "/develop/ai/context-engine/langcache" >}}): Reduce LLM API calls by caching and reusing responses for semantically similar queries.
+1. [**Add semantic caching**]({{< relref "/develop/ai/langcache" >}}): Reduce LLM API calls by caching and reusing responses for semantically similar queries.
1. [**Add agent memory**]({{< relref "/develop/ai/context-engine/agent-memory" >}}): Give your agent persistent session and long-term memory using the Agent Memory REST API.
1. [**Connect tools and business data**]({{< relref "/develop/ai/context-engine/context-gateway" >}}): Use Context Gateway to give any agent one endpoint for your MCP servers and your Redis data.
1. [**Sync live data to Redis**]({{< relref "/develop/ai/context-engine/data-integration" >}}): Use Data Integration to keep your Redis Cloud database in sync with your primary relational database using Change Data Capture.
@@ -137,7 +137,7 @@ AI agents can act autonomously to plan and execute tasks for the user.
#### Context Engine
The Context Engine provides managed services for agent memory and data access.
-* [Get started with LangCache]({{< relref "/develop/ai/context-engine/langcache" >}}): Add semantic caching to reduce LLM costs in minutes.
+* [Get started with LangCache]({{< relref "/develop/ai/langcache" >}}): Add semantic caching to reduce LLM costs in minutes.
* [Get started with Agent Memory]({{< relref "/develop/ai/context-engine/agent-memory" >}}): Add persistent two-tier memory to any agent using the REST API.
* [Get started with Context Gateway]({{< relref "/develop/ai/context-engine/context-gateway" >}}): Give agents one MCP endpoint for the tools of your MCP servers and your Redis data.
* [Get started with Data Integration]({{< relref "/develop/ai/context-engine/data-integration" >}}): Keep Redis in sync with your primary database so agents always have fresh data.
diff --git a/content/develop/ai/agent-builder/agent-concepts.md b/content/develop/ai/agent-builder/agent-concepts.md
index d44b50f92d..cb1fd512be 100644
--- a/content/develop/ai/agent-builder/agent-concepts.md
+++ b/content/develop/ai/agent-builder/agent-concepts.md
@@ -89,7 +89,7 @@ You can build each part of an agent's context layer yourself from Redis data str
| Agent need | Build it yourself with Redis | Redis Iris service |
|:--|:--|:--|
| Remember the user across sessions | Streams, Hashes, and vector search for session and long-term memory | [Agent Memory](/content/develop/ai/context-engine/agent-memory/_index.md) stores session events, summarizes long sessions, and extracts long-term memories in the background. |
-| Avoid repeat LLM calls | Vector search plus your own cache logic | [LangCache](/content/develop/ai/context-engine/langcache/_index.md) returns a cached response when a new prompt is semantically similar to a cached one. |
+| Avoid repeat LLM calls | Vector search plus your own cache logic | [LangCache](/content/develop/ai/langcache/_index.md) returns a cached response when a new prompt is semantically similar to a cached one. |
| Query business data safely | Hand-written tools or generated queries per agent | [Context Gateway](/content/develop/ai/context-engine/context-gateway/_index.md) generates tools from a data model you define once. Agents call them over MCP (Model Context Protocol), and agent keys limit what each agent can reach. |
| Keep that data current | Your own sync jobs from the source database | [Data Integration](/content/develop/ai/context-engine/data-integration/_index.md) streams changes from relational databases into Redis within seconds. |
@@ -310,7 +310,7 @@ Production-ready agents include built-in reliability features:
### Performance optimization
- Cache frequently accessed information
-- Cache LLM responses semantically, so paraphrased questions skip the model call. [LangCache](/content/develop/ai/context-engine/langcache/_index.md) does this as a managed service
+- Cache LLM responses semantically, so paraphrased questions skip the model call. [LangCache](/content/develop/ai/langcache/_index.md) does this as a managed service
- Use efficient data structures for fast retrieval
- Scale resources based on demand
@@ -343,7 +343,7 @@ Production-ready agents include built-in reliability features:
### Cost Optimization
-- LLM cost management: Use appropriate models for different tasks, and serve repeat questions from a semantic cache such as [LangCache](/content/develop/ai/context-engine/langcache/_index.md)
+- LLM cost management: Use appropriate models for different tasks, and serve repeat questions from a semantic cache such as [LangCache](/content/develop/ai/langcache/_index.md)
- Redis memory optimization: Efficient data structures and TTL policies
- API rate limiting: Prevent excessive external API calls
- Resource monitoring: Track and optimize compute and storage costs
@@ -377,7 +377,7 @@ Ready to build your AI agent with Redis?
**Learn more:**
- [Redis Iris Context Engine — Agent Memory](/content/develop/ai/context-engine/agent-memory/_index.md) for managed session and long-term agent memory
- [Redis Iris concepts](/content/develop/ai/context-engine/concepts/_index.md) for how memory, caching, and governed data access work together
-- Interactive demos for [Agent Memory](/content/develop/ai/context-engine/agent-memory/interactive-demo.md), [LangCache](/content/develop/ai/context-engine/langcache/interactive-demo.md) that run in your browser
+- Interactive demos for [Agent Memory](/content/develop/ai/context-engine/agent-memory/interactive-demo.md), [LangCache](/content/develop/ai/langcache/interactive-demo.md) that run in your browser
- [Redis Vector Search documentation](/content/develop/ai/search-and-query/vectors/_index.md)
- [RedisVL Python library](/content/develop/clients/redis-vl.md) for vector operations and AI workflows
- [Redis data structures guide](/content/develop/data-types/_index.md)
diff --git a/content/develop/ai/context-engine/_index.md b/content/develop/ai/context-engine/_index.md
index e67e3e4396..37617052e8 100644
--- a/content/develop/ai/context-engine/_index.md
+++ b/content/develop/ai/context-engine/_index.md
@@ -15,14 +15,16 @@ weight: 30
Redis Iris eliminates the infrastructure burden of building context-aware AI agents.
+## Explore Redis Iris
+
{{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Concepts" description="What happens when an agent asks Redis Iris for context" url="/develop/ai/context-engine/concepts" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="SDK and CLI setup" description="Install redis-iris and connect it to Redis Cloud or a self-managed deployment" url="/develop/ai/context-engine/sdk-and-cli" >}}
{{< tile-card icon="images/dev/icons/icon-redis-agent-memory-64-duotone.png" title="Agent Memory" description="Persistent short-term and long-term memory across agent interactions" url="/develop/ai/context-engine/agent-memory" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Context Gateway" description="One MCP endpoint for the tools of any MCP server and your Redis data" url="/develop/ai/context-engine/context-gateway" >}}
{{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Agent Playbooks" description="Publish reusable answers and procedures for agents" url="/develop/ai/context-engine/agent-playbooks" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Lens" description="Debug agent answers by tracing the context behind each turn" url="/develop/ai/context-engine/lens" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Context Gateway" description="One MCP endpoint for the tools of any MCP server and your Redis data" url="/develop/ai/context-engine/context-gateway" >}}
{{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Intent Router" description="Classify requests into intents and route them to the right tool or agent" url="/develop/ai/context-engine/intent-router" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="SDK and CLI setup" description="Install redis-iris and connect it to Redis Cloud or a self-managed deployment" url="/develop/ai/context-engine/sdk-and-cli" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Lens (beta)" description="Debug agent answers by tracing the context behind each turn" url="/develop/ai/context-engine/lens" >}}
{{< tile-card icon="images/dev/icons/icon-redis-code-64-duotone.png" title="Agent Mesh (beta)" description="Share agent-to-agent task state across Python replicas and resume event delivery" url="/develop/ai/context-engine/agent-mesh" >}}
@@ -30,13 +32,13 @@ Redis Iris eliminates the infrastructure burden of building context-aware AI age
Redis Iris is a production-ready context engine for AI agents that:
-- **Answers recurring questions without a model call**: Agent Playbooks return the answers and procedures your business published, matched to the agent's task by semantic similarity
- **Adds persistent memory**: Agents remember past interactions and user preferences across sessions
-- **Routes each message**: Intent Router matches a message to the intents you defined and returns the target that handles it
+- **Answers recurring questions without a model call**: Agent Playbooks return the answers and procedures your business published, matched to the agent's task by semantic similarity
- **Connects tools and business data**: Context Gateway gives agents one MCP endpoint for the tools of any MCP server and your Redis data
+- **Routes each message**: Intent Router matches a message to the intents you defined and returns the target that handles it
+- **Shows why an agent answered the way it did**: Lens (beta) traces each turn, from what each source returned to what entered the prompt
+- **Keeps long responses deliverable**: Agent Mesh (beta) keeps an agent's response stream resumable when the client disconnects
- **Keeps data fresh**: Data Integration streams live changes from relational databases into Redis within seconds
-- **Shows why an agent answered the way it did**: Lens traces each turn, from what each source returned to what entered the prompt
-- **Keeps long responses deliverable**: Agent Mesh keeps an agent's response stream resumable when the client disconnects
- **Deploys your way**: Check each service’s operator guide for its managed and self-managed deployment options.
## Why use Redis Iris?
diff --git a/content/develop/ai/context-engine/agent-memory/_index.md b/content/develop/ai/context-engine/agent-memory/_index.md
index fd33342d91..7d89e63cf9 100644
--- a/content/develop/ai/context-engine/agent-memory/_index.md
+++ b/content/develop/ai/context-engine/agent-memory/_index.md
@@ -41,9 +41,9 @@ Access Redis Agent Memory through the `redis-iris` Python SDK, the `iris` CLI, i
* **Multi-session recall:** Retrieve relevant memories across conversations and filter results by owner, session, namespace, topic, or memory type.
* **Custom memory types:** Define memory types for your business domain, with structured fields and instructions that control what Redis Agent Memory extracts.
-## Two-tier memory model
+## Concepts
-Redis Agent Memory provides two memory tiers:
+Redis Agent Memory provides two memory tiers. See the [overview](/content/develop/ai/context-engine/agent-memory/overview.md) for how they relate to sessions, owners, and namespaces.
@@ -97,26 +97,26 @@ Agent: Good to know! I'll help you find some vegetarian-friendly restaurants in
-## Get started with Redis Agent Memory {#get-started}
+## Quick example {#get-started}
-Get started with Redis Agent Memory on Redis Cloud or deploy it with Redis Software.
+1. Set up an Agent Memory store:
+ - **Redis Cloud:** [Create an Agent Memory service on Redis Cloud](/content/operate/iris/agent-memory/create-service.md).
+ - **Self-managed:** [Deploy Agent Memory on Kubernetes](/content/operate/iris/agent-memory/self-managed/_index.md).
+1. Install the Redis Iris Python package, which includes the `iris` CLI:
-
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
+
+1. With `IRIS_AGENT_MEMORY_URL`, `IRIS_AGENT_MEMORY_STORE_ID`, and `IRIS_AGENT_MEMORY_API_KEY` in your environment, record a conversation, then recall what Agent Memory extracted from it:
+
+{{< clients-example set="iris_agent_memory_quickstart" step="agent-memory-connect" description="" lang_filter="Python (Iris),cURL (Iris)" footer="hide" />}}
+
+{{< clients-example set="iris_agent_memory_quickstart" step="agent-memory-quickstart-save" description="" lang_filter="Python (Iris),cURL (Iris)" footer="hide" />}}
-### Follow the quickstart
+{{< clients-example set="iris_agent_memory_quickstart" step="agent-memory-quickstart-recall" description="" lang_filter="Python (Iris),CLI (Iris),cURL (Iris)" footer="hide" />}}
-After your service is ready, follow the [quickstart]({{< relref "/develop/ai/context-engine/agent-memory/quickstart" >}}). Choose Python, the Iris CLI, or cURL to explore the same travel planning scenario.
+Follow the [quickstart](/content/develop/ai/context-engine/agent-memory/quickstart.md) to explore the same travel planning scenario in Python, the Iris CLI, or cURL.
## Explore the documentation
diff --git a/content/develop/ai/context-engine/agent-mesh/_index.md b/content/develop/ai/context-engine/agent-mesh/_index.md
index 6613fbe33c..b8e480a679 100644
--- a/content/develop/ai/context-engine/agent-mesh/_index.md
+++ b/content/develop/ai/context-engine/agent-mesh/_index.md
@@ -8,7 +8,7 @@ description: Create resumable event streams with Agent Mesh through A2A or FastA
hideListLinks: true
linktitle: Agent Mesh
title: Redis Agent Mesh
-weight: 40
+weight: 28
bannerText: Redis Agent Mesh is currently in beta. Features and behavior are subject to change.
bannerChildren: true
---
diff --git a/content/develop/ai/context-engine/agent-mesh/a2a-sdk.md b/content/develop/ai/context-engine/agent-mesh/a2a-sdk.md
index 26fdf7eb36..fe75205511 100644
--- a/content/develop/ai/context-engine/agent-mesh/a2a-sdk.md
+++ b/content/develop/ai/context-engine/agent-mesh/a2a-sdk.md
@@ -249,4 +249,4 @@ Storage and internal reader calls can raise `A2AStorageError`, `A2ACapacityExcee
Task listing scans an owner's Task index and suits modest inventories per owner. It is not a search index or a consistent snapshot during concurrent writes.
-See the [SDK API reference](https://github.com/redis/redis-iris/blob/main/docs/core/agent-mesh-a2a.md) for signatures and the [beta limits](/content/develop/ai/context-engine/agent-mesh/_index.md#requirements-and-limits) for deployment qualification. Redis durability remains application-owned; replay does not guarantee exactly-once external effects.
+See the [beta limits](/content/develop/ai/context-engine/agent-mesh/_index.md#requirements-and-limits) for deployment qualification. Redis durability remains application-owned; replay does not guarantee exactly-once external effects.
diff --git a/content/develop/ai/context-engine/agent-mesh/fastapi-sse-sdk.md b/content/develop/ai/context-engine/agent-mesh/fastapi-sse-sdk.md
index 4eb7693cbe..d5a45f2859 100644
--- a/content/develop/ai/context-engine/agent-mesh/fastapi-sse-sdk.md
+++ b/content/develop/ai/context-engine/agent-mesh/fastapi-sse-sdk.md
@@ -543,7 +543,6 @@ The SDK retains all events until the run expires. A writer that exceeds
The demo sets `REDIS_STREAM_DONE_TTL=3600`; replay still ends at the run's
original lifetime. Application state in your own database has separate retention.
-See the [SDK reference](https://github.com/redis/redis-iris/blob/main/docs/core/agent-mesh-sse.md)
-for facade exports and upstream signatures, and the
+See the
[beta limits](/content/develop/ai/context-engine/agent-mesh/_index.md#requirements-and-limits)
for deployment qualification.
diff --git a/content/develop/ai/context-engine/agent-playbooks/_index.md b/content/develop/ai/context-engine/agent-playbooks/_index.md
index 8e60f48940..e55dbc00b2 100644
--- a/content/develop/ai/context-engine/agent-playbooks/_index.md
+++ b/content/develop/ai/context-engine/agent-playbooks/_index.md
@@ -8,7 +8,7 @@ categories:
description: Create playbooks of reusable skills and answers that agents can discover and load for a task.
linkTitle: Agent Playbooks
hideListLinks: true
-weight: 25
+weight: 15
cascade:
exampleClientOrder:
- Python (Iris)
@@ -39,7 +39,9 @@ A FAQ gives an agent a validated answer, such as where a customer can find their
- **Governed collaboration:** Separate reading, writing, publishing, and proposing with playbook access grants.
- **Flexible integration:** Retrieve entries through Python, HTTP, or Model Context Protocol (MCP).
-## Choose what to publish
+## Concepts
+
+A playbook holds two kinds of entries:
| Entry | Use it for | What the agent receives |
| ----- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
@@ -50,10 +52,24 @@ A publisher selects the version of each **entry** agents receive. Your applicati
See [Redis Agent Playbooks concepts]({{< relref "/develop/ai/context-engine/agent-playbooks/concepts" >}}) for versions, publication, and review.
-## Get started
+## Quick example
+
+1. Set up a playbook:
+ - **Redis Cloud:** [Create a playbook](/content/operate/iris/agent-playbook/create-playbook.md).
+ - **Self-managed:** [Deploy Agent Playbooks on Kubernetes](/content/operate/iris/agent-playbook/self-managed/_index.md).
+1. Install the Redis Iris Python package, which includes the `iris` CLI:
+
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
+
+1. With `IRIS_AGENT_PLAYBOOKS_URL`, `IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID`, and `IRIS_AGENT_PLAYBOOKS_API_KEY` in your environment, find the published entries that match an agent's task:
+
+{{< clients-example set="iris_playbook_quickstart" step="playbook-connect" description="" lang_filter="Python (Iris),CLI (Iris),cURL (Iris)" footer="hide" />}}
+
+{{< clients-example set="iris_playbook_quickstart" step="playbook-quickstart-discover" description="" lang_filter="Python (Iris),CLI (Iris),cURL (Iris)" footer="hide" />}}
-1. [Create a playbook]({{< relref "/operate/iris/agent-playbook/create-playbook" >}}) on Redis Cloud.
-2. [Publish and retrieve your first FAQ]({{< relref "/develop/ai/context-engine/agent-playbooks/quickstart" >}}).
+Follow the [quickstart](/content/develop/ai/context-engine/agent-playbooks/quickstart.md) to publish your first FAQ and retrieve it.
## Manage playbook entries
diff --git a/content/develop/ai/context-engine/context-gateway/_index.md b/content/develop/ai/context-engine/context-gateway/_index.md
index adbb67506c..eb99ef1c55 100644
--- a/content/develop/ai/context-engine/context-gateway/_index.md
+++ b/content/develop/ai/context-engine/context-gateway/_index.md
@@ -55,34 +55,37 @@ Redis Context Gateway is a Model Context Protocol (MCP) gateway for AI agents th
-## Quick example
+## Concepts
+
+A **Gateway** is one MCP endpoint for an agent. Each **Upstream** behind it is an MCP server or a **Context Surface**, which generates tools from a data model of records in Redis. In full mode the agent lists every tool; in search mode it searches for the tools it needs. See [Context Gateway concepts](/content/develop/ai/context-engine/context-gateway/concepts.md) for tool policies, caching, and compression.
-Install the Redis Iris Python package, which includes the `iris` CLI:
+## Quick example
-```bash
-pip install redis-iris
-```
+1. Set up a Gateway:
+ - **Redis Cloud:** [Create a Context Gateway](/content/operate/iris/context-gateway/create-gateway.md).
+ - **Self-managed:** Follow the [deployment guide](/content/operate/iris/context-gateway/self-managed/_index.md), then [create a Gateway and an agent key](/content/operate/iris/context-gateway/self-managed/api-examples.md). A license key is required for self-managed deployment. [Contact Redis](https://redis.io/contact/) to request access.
+1. Install the Redis Iris Python package, which includes the `iris` CLI:
-With a Gateway's MCP endpoint and an agent key in your environment, list its tools:
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
-```bash
-export IRIS_CONTEXT_GATEWAY_URL=''
-export IRIS_CONTEXT_GATEWAY_API_KEY=''
-iris --json context-gateway tools list
-```
+1. With `IRIS_CONTEXT_GATEWAY_URL` and `IRIS_CONTEXT_GATEWAY_API_KEY` in your environment, find a tool and call it:
-Use the tool names and input schemas returned by discovery. The [quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md) shows calls in full and search mode.
+ ```python
+ from redis_iris import ContextGateway
-The [redis-iris package](https://pypi.org/project/redis-iris/) covers MCP calls and Gateway administration in Python and the CLI. For JavaScript and TypeScript, install the separate [@redis-iris/context-gateway SDK](https://www.npmjs.com/package/@redis-iris/context-gateway) for MCP calls and the Control Plane API. See the [client guide](/content/develop/ai/context-engine/context-gateway/mcp.md#choose-a-client) to choose a client.
+ gateway = ContextGateway.from_env()
-Follow the [quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md) to list, search, and call tools, or see [Manage Gateways and Upstreams](/content/develop/ai/context-engine/context-gateway/manage-gateways.md) to register your own MCP servers and Context Surfaces.
+ for tool in gateway.search("filter providers by specialty"):
+ print(tool.name, tool.description)
-## Get started with Context Gateway
+ result = gateway.call("", {"": ""})
+ ```
-Context Gateway is available on Redis Cloud or as a self-managed deployment on Kubernetes.
+ From the CLI, `iris --json context-gateway tools list` lists the same tools.
-- **Redis Cloud:** [Create a Context Gateway](/content/operate/iris/context-gateway/create-gateway.md).
-- **Self-managed:** Follow the [deployment guide](/content/operate/iris/context-gateway/self-managed/_index.md), then [create a Gateway and an agent key](/content/operate/iris/context-gateway/self-managed/api-examples.md). A license key is required for self-managed deployment. [Contact Redis](https://redis.io/contact/) to request access.
+Use the tool names and input schemas returned by discovery. The [redis-iris package](https://pypi.org/project/redis-iris/) covers MCP calls and Gateway administration in Python and the CLI. For JavaScript and TypeScript, install the [@redis-iris/context-gateway SDK](https://www.npmjs.com/package/@redis-iris/context-gateway); see the [client guide](/content/develop/ai/context-engine/context-gateway/mcp.md#choose-a-client) to choose a client. The [quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md) shows calls in full and search mode.
## Manage Gateways and Upstreams
diff --git a/content/develop/ai/context-engine/intent-router/_index.md b/content/develop/ai/context-engine/intent-router/_index.md
index bb0e214c05..b60c32db18 100644
--- a/content/develop/ai/context-engine/intent-router/_index.md
+++ b/content/develop/ai/context-engine/intent-router/_index.md
@@ -8,7 +8,7 @@ categories:
description: Classify a user's message into a named intent and get back the target your application should dispatch to.
linkTitle: Intent Router
hideListLinks: true
-weight: 27
+weight: 24
---
## What is Redis Intent Router?
@@ -36,38 +36,39 @@ For example, a support application can route "where is my package?" to a `track_
- **Governed access:** Each Router is its own authorization boundary, with separate `read`, `write`, and `full` grants.
- **Flexible integration:** Use Python, TypeScript, the `iris` command-line interface (CLI), or the Hypertext Transfer Protocol (HTTP) API.
-## Choose how to use it
-
-| Use case | How an intent helps |
-| -------- | ------------------- |
-| Agent routing | Send each request to the specialist agent or tool that handles it. |
-| Model selection | Send simple requests to a small model and complex ones to a larger model. |
-| Guardrails | Detect off-topic or disallowed requests before they reach the agent. |
-| Workflow dispatch | Start a pipeline or handler from a natural-language request. |
+## Concepts
-The Router doesn't run the target. It returns the target, and your application decides how and whether to act on it.
+A **Router** holds your intents and is its own access boundary. Each **intent** has example phrasings and an optional **target**, and each match returns intents with a **score** that a threshold on the Router, the intent, or the request can filter. See [Intent Router concepts](/content/develop/ai/context-engine/intent-router/concepts.md).
## Quick example
-Install the Redis Iris Python package, which includes the `iris` CLI:
+1. Set up a Router:
+
+ - **Self-managed:** Deploy with [Self-managed Intent Router](/content/operate/iris/intent-router/self-managed/_index.md), then [create a Router and an agent key](/content/operate/iris/intent-router/self-managed/api-examples.md). You need a license key to deploy: [contact Redis](https://redis.io/contact/) to request access.
+1. Install the Redis Iris Python package, which includes the `iris` CLI:
-```bash
-pip install 'redis-iris>=1.0.0'
-```
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
-Set `IRIS_INTENT_ROUTER_URL`, `IRIS_INTENT_ROUTER_ID`, and `IRIS_INTENT_ROUTER_API_KEY` as shown in the [quickstart](/content/develop/ai/context-engine/intent-router/quickstart.md#save-connection-values), connect, and define intents:
+1. Set `IRIS_INTENT_ROUTER_URL`, `IRIS_INTENT_ROUTER_ID`, and `IRIS_INTENT_ROUTER_API_KEY` as shown in the [quickstart](/content/develop/ai/context-engine/intent-router/quickstart.md#save-connection-values), connect, and define intents:
-{{< clients-example set="iris_intent_router_quickstart" step="intents-create" description="" lang_filter="Python (Iris),TypeScript (Iris),cURL (Iris),CLI (Iris)" footer="hide" />}}
+{{< clients-example set="iris_intent_router_quickstart" step="router-connect" description="" lang_filter="Python (Iris),TypeScript (Iris),cURL (Iris),CLI (Iris)" footer="hide" />}}
-The [redis-iris package](https://pypi.org/project/redis-iris/) covers matching, intent authoring, and Router administration in Python and the CLI. For TypeScript, the generated client [@redis-iris/intent-router](https://www.npmjs.com/package/@redis-iris/intent-router) covers the data plane and the control plane. Install it with `npm install @redis-iris/intent-router`. See the [developer guide](/content/develop/ai/context-engine/intent-router/developer-guide.md) to choose a client.
+{{< clients-example set="iris_intent_router_quickstart" step="intents-create" description="" lang_filter="Python (Iris),TypeScript (Iris),cURL (Iris),CLI (Iris)" footer="hide" />}}
-## Get started
+The [redis-iris package](https://pypi.org/project/redis-iris/) covers matching, intent authoring, and Router administration in Python and the CLI. For TypeScript, the generated client [@redis-iris/intent-router](https://www.npmjs.com/package/@redis-iris/intent-router) covers the data plane and the control plane. See the [developer guide](/content/develop/ai/context-engine/intent-router/developer-guide.md) to choose a client, and [define intents and match your first queries](/content/develop/ai/context-engine/intent-router/quickstart.md).
-Redis Intent Router is available for self-managed deployment on Kubernetes. See [Self-managed Intent Router](/content/operate/iris/intent-router/self-managed/_index.md), then [create a Router and an agent key](/content/operate/iris/intent-router/self-managed/api-examples.md).
+## Choose how to use it
-You need a license key to deploy: [contact Redis](https://redis.io/contact/) to request access.
+| Use case | How an intent helps |
+| -------- | ------------------- |
+| Agent routing | Send each request to the specialist agent or tool that handles it. |
+| Model selection | Send simple requests to a small model and complex ones to a larger model. |
+| Guardrails | Detect off-topic or disallowed requests before they reach the agent. |
+| Workflow dispatch | Start a pipeline or handler from a natural-language request. |
-Then [define intents and match your first queries](/content/develop/ai/context-engine/intent-router/quickstart.md).
+The Router doesn't run the target. It returns the target, and your application decides how and whether to act on it.
## Manage Routers and intents
diff --git a/content/develop/ai/context-engine/lens/AGENTS.md b/content/develop/ai/context-engine/lens/AGENTS.md
index d68fd57125..ec238bcf95 100644
--- a/content/develop/ai/context-engine/lens/AGENTS.md
+++ b/content/develop/ai/context-engine/lens/AGENTS.md
@@ -41,8 +41,8 @@ beta notice; don't add lists of gaps or "coming soon" notes.
Lens runs on Redis Cloud and self-managed. Pages are deployment-neutral: the same steps
work on both. Name a deployment only where behavior differs.
-Readers get endpoints and keys from their administrator. Until the operator pages exist,
-say so without linking to them, and mark each handoff with a TODO comment.
+Readers get endpoints and keys from their administrator. Link the handoff to the Cloud
+pages or the self-managed guide under `content/operate/iris/lens/self-managed/`.
## Terms
diff --git a/content/develop/ai/context-engine/lens/_index.md b/content/develop/ai/context-engine/lens/_index.md
index c4fc7795fb..e377653cd8 100644
--- a/content/develop/ai/context-engine/lens/_index.md
+++ b/content/develop/ai/context-engine/lens/_index.md
@@ -34,7 +34,9 @@ When your agent gives a wrong answer, Lens shows where it went wrong. For exampl
- **You control content capture:** Capture prompts and retrieved text for debugging, or keep only IDs, hashes, and counts.
- **Background export:** Lens exports in the background, so your agent never waits for it. If an export fails, the error stays out of your agent's code.
-## How it works
+## Concepts
+
+Lens groups turns into sessions by agent, and records each turn's steps. See [Lens concepts](/content/develop/ai/context-engine/lens/concepts.md) for fetched and used context.
1. Your agent opens a turn for each message with the Redis Iris software development kit (SDK).
1. The SDK records each step in the turn: retrievals, memory recalls, prompt assembly, model calls, tool calls, and Iris service calls.
@@ -44,11 +46,22 @@ When your agent gives a wrong answer, Lens shows where it went wrong. For exampl

{width="700"}
-## Get started
+## Quick example
+
+1. Set up a Lens instance and get its endpoints and keys:
+ - **Redis Cloud:** [Create Lens](/content/operate/iris/lens/create-lens.md).
+ - **Self-managed:** [Deploy Lens on Kubernetes](/content/operate/iris/lens/self-managed/_index.md).
+1. Install the Redis Iris Python package:
+
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
+
+1. With `IRIS_LENS_ENDPOINT`, `IRIS_LENS_API_KEY`, and `IRIS_LENS_AGENT_ID` in your environment, trace a turn:
+
+{{< clients-example set="iris_lens_quickstart" step="trace_turn" description="" lang_filter="Python (Iris)" footer="hide" />}}
-1. Get your Lens endpoints and keys from your administrator.
-
-1. [Trace your first turn](/content/develop/ai/context-engine/lens/quickstart.md).
+Follow the [quickstart](/content/develop/ai/context-engine/lens/quickstart.md) to read the turn back.
## Use Lens
diff --git a/content/develop/ai/context-engine/lens/concepts.md b/content/develop/ai/context-engine/lens/concepts.md
index 8920bf1cec..f5b9550fdb 100644
--- a/content/develop/ai/context-engine/lens/concepts.md
+++ b/content/develop/ai/context-engine/lens/concepts.md
@@ -77,5 +77,4 @@ You can turn content capture off. Lens then keeps each step's IDs, content hashe
## Retention
-Lens keeps turn structure, timing, scores, and outcomes for the full retention window. Captured text has a shorter window. Your administrator sets both windows.
-
+Lens keeps turn structure, timing, scores, and outcomes for the full retention window. Captured text has a shorter window. Your administrator sets both windows. See [self-managed retention](/content/operate/iris/lens/self-managed/configuration.md#retention).
diff --git a/content/develop/ai/context-engine/lens/configure.md b/content/develop/ai/context-engine/lens/configure.md
index b29959e877..b949f3ad35 100644
--- a/content/develop/ai/context-engine/lens/configure.md
+++ b/content/develop/ai/context-engine/lens/configure.md
@@ -65,8 +65,7 @@ Lens keys have one of three scopes:
| `read` | People and tools that read turns, in the Lens user interface (UI) or with the read application programming interface (API). |
| `full` | Both. |
-Agents send their key as `IRIS_LENS_API_KEY`. The read client reads its key from `LENS_API_KEY`. Give each agent an ingest key and each reader a read key, so an agent's key can't read other agents' turns. On Redis Cloud, [create keys in the console](/content/operate/iris/lens/create-lens.md#create-api-keys). Self-managed, your administrator creates them.
-
+Agents send their key as `IRIS_LENS_API_KEY`. The read client reads its key from `LENS_API_KEY`. Give each agent an ingest key and each reader a read key, so an agent's key can't read other agents' turns. On Redis Cloud, [create keys in the console](/content/operate/iris/lens/create-lens.md#create-api-keys). Self-managed, your administrator [creates them](/content/operate/iris/lens/self-managed/authentication.md#create-api-keys).
## Control content capture
diff --git a/content/develop/ai/context-engine/lens/inspect-sessions.md b/content/develop/ai/context-engine/lens/inspect-sessions.md
index 0cb15b0a34..93ffeb10ba 100644
--- a/content/develop/ai/context-engine/lens/inspect-sessions.md
+++ b/content/develop/ai/context-engine/lens/inspect-sessions.md
@@ -15,8 +15,7 @@ Use the Lens user interface (UI) to find a session, open a turn, and see what ha
## Connect to Lens
-Open Lens. On Redis Cloud, select **Lens** under **Iris** in the console menu; Lens uses your console sign-in. Self-managed, Lens asks for a credential: paste your read key and select **Connect**.
-
+Open Lens. On Redis Cloud, select **Lens** under **Iris** in the console menu; Lens uses your console sign-in. Self-managed, Lens asks for a credential: paste your read key and select **Connect**. Your administrator [connects Lens to the console](/content/operate/iris/lens/self-managed/operations.md#connect-the-console).
## Find a session
diff --git a/content/develop/ai/context-engine/lens/limits.md b/content/develop/ai/context-engine/lens/limits.md
index 70a8484426..0a5e889b24 100644
--- a/content/develop/ai/context-engine/lens/limits.md
+++ b/content/develop/ai/context-engine/lens/limits.md
@@ -24,8 +24,7 @@ Check these limits when you design IDs and read large sessions, and use the erro
| Sessions per listed range | Up to 10,000. Narrow the range or add filters to list more. |
| Turns per session read | Up to 10,000. |
-Your administrator can change the ingest request size and sets the retention windows.
-
+Your administrator can change the ingest request size and sets the retention windows. See [self-managed retention](/content/operate/iris/lens/self-managed/configuration.md#retention).
## How Lens exports
diff --git a/content/develop/ai/context-engine/lens/quickstart.md b/content/develop/ai/context-engine/lens/quickstart.md
index 5e2508955f..1c5ff6d9b0 100644
--- a/content/develop/ai/context-engine/lens/quickstart.md
+++ b/content/develop/ai/context-engine/lens/quickstart.md
@@ -15,12 +15,11 @@ Trace one agent turn with the Redis Iris software development kit (SDK), then fi
## Before you begin
-Get these values. On Redis Cloud, [create Lens and its keys](/content/operate/iris/lens/create-lens.md). Self-managed, get them from your administrator.
+Get these values. On Redis Cloud, [create Lens and its keys](/content/operate/iris/lens/create-lens.md). Self-managed, get them from your administrator, who [hands them off](/content/operate/iris/lens/self-managed/deploy.md#hand-off-to-developers) after deploying Lens.
- The Iris host, such as `https://iris.example.com`. The SDK sends turns there, and the read client reads them back from there.
- An ingest key, for sending turns.
- Your instance ID and a read key, for reading turns back.
-
You also need Python 3.11 or later. The cURL example uses Bash and jq. This walkthrough needs no agent framework or model provider key. For the configuration `redis-iris` reads across services, see [SDK and CLI setup](/content/develop/ai/context-engine/sdk-and-cli.md).
@@ -31,9 +30,10 @@ Install the Redis Iris SDK, which includes Lens instrumentation, and the Lens re
```bash
python -m venv .venv
source .venv/bin/activate
-python -m pip install redis-iris 'redis-agent-lens>=0.1.0a4'
+python -m pip install 'redis-iris>=1.0.0' 'redis-agent-lens>=1.0.0'
```
-
+
+`redis-agent-lens` is the read client the last step uses. Add the `llm-tracing` extra, `'redis-iris[llm-tracing]>=1.0.0'`, to trace OpenAI, Anthropic, Amazon Bedrock, and LangChain model calls automatically.
## Configure the SDK
@@ -75,8 +75,7 @@ A turn is readable a few seconds after its export.
To view it in Lens:
-1. Open Lens. On Redis Cloud, select **Lens** under **Iris** in the console menu; Lens uses your console sign-in. Self-managed, Lens asks for a credential: paste your read key and select **Connect**.
-
+1. Open Lens. On Redis Cloud, select **Lens** under **Iris** in the console menu; Lens uses your console sign-in. Self-managed, Lens asks for a credential: paste your read key and select **Connect**. Your administrator [connects Lens to the console](/content/operate/iris/lens/self-managed/operations.md#connect-the-console).
1. Select the `lens-quickstart` agent.
1. Select the session that matches the printed session ID.
1. Expand the turn.
diff --git a/content/develop/ai/context-engine/sdk-and-cli.md b/content/develop/ai/context-engine/sdk-and-cli.md
index b850a05b53..3c441b322a 100644
--- a/content/develop/ai/context-engine/sdk-and-cli.md
+++ b/content/develop/ai/context-engine/sdk-and-cli.md
@@ -11,11 +11,11 @@ title: Set up Redis Iris with the SDK and CLI
weight: 7
---
-The `redis-iris` package is a Python software development kit (SDK) with one object per Redis Iris service, plus the `iris` command-line interface (CLI), which creates services, mints keys, and checks connections. Your agent reads only `IRIS_*` environment variables, so the same code runs on Redis Cloud and on a self-managed deployment.
+The [`redis-iris`](https://pypi.org/project/redis-iris/) package is the Python software development kit (SDK) for every Redis Iris service, plus the `iris` command-line interface (CLI), which creates services, mints keys, and checks connections. Your agent reads only `IRIS_*` environment variables, so the same code runs on Redis Cloud and on a self-managed deployment.
-Start with a service's quickstart: [Agent Memory](/content/develop/ai/context-engine/agent-memory/quickstart.md), [Agent Playbooks](/content/develop/ai/context-engine/agent-playbooks/quickstart.md), [Context Gateway](/content/develop/ai/context-engine/context-gateway/quickstart.md), or [Lens](/content/develop/ai/context-engine/lens/quickstart.md). This page covers the setup they share.
+Start with a service's quickstart: [Agent Memory](/content/develop/ai/context-engine/agent-memory/quickstart.md), [Agent Playbooks](/content/develop/ai/context-engine/agent-playbooks/quickstart.md), [Context Gateway](/content/develop/ai/context-engine/context-gateway/quickstart.md), [Intent Router](/content/develop/ai/context-engine/intent-router/quickstart.md), or [Lens](/content/develop/ai/context-engine/lens/quickstart.md). This page covers the setup they share.
-The unified `redis-iris` package is for Python and the CLI. JavaScript and TypeScript use separate product SDKs. For Context Gateway, install `@redis-iris/context-gateway` as shown in its [quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md#install-the-client).
+`redis-iris` covers Python and the CLI. For JavaScript and TypeScript, each service has its own `@redis-iris/*` npm package, shown in its quickstart.
## Install the SDK and CLI
@@ -59,12 +59,12 @@ iris --json --profile suite agent-playbooks faqs sync ./faqs --publish changed
`--json` prints one JSON value, `--no-input` never prompts, and `--profile` selects a configuration profile. Run `iris --help` for each command's options.
-For every command, see the [redis-iris CLI reference](https://github.com/redis/redis-iris#the-cli), or give your coding agent that link.
-
+`iris --help` lists every service group, and `--help` at any level lists its commands, so the CLI is its own reference.
+
## Set up on Redis Cloud
-On Redis Cloud, the [Redis Cloud console](https://cloud.redis.io/) creates services and keys, and the CLI checks the connection. These steps use Agent Playbooks. The other Redis Iris services follow the same steps with their own console pages and `IRIS__*` variables.
+On Redis Cloud, the [Redis Cloud console](https://cloud.redis.io/) creates services and keys, and the CLI checks the connection. These steps use Agent Playbooks. The other Redis Iris services follow the same steps with their own console pages and `IRIS__*` variables. To see how the pieces fit together first, read [Redis Iris concepts](/content/develop/ai/context-engine/concepts/_index.md).
1. [Create a playbook](/content/operate/iris/agent-playbook/create-playbook.md) and wait until it is **Ready**.
1. Select **Connect** on the playbook's page. Copy the **Endpoint** and **Playbook ID**.
@@ -77,7 +77,8 @@ On Redis Cloud, the [Redis Cloud console](https://cloud.redis.io/) creates servi
IRIS_AGENT_PLAYBOOKS_API_KEY=
```
-1. Optional, but recommended: create `iris.toml` with a cloud profile, and add `IRIS_PROFILE=cloud` and `IRIS_CONFIG=./iris.toml` to `.env`. One `iris.toml` holds the URLs for every Redis Iris service you use, so the CLI and SDK manage them together, and switching deployments means switching one profile. See the [Redis Cloud project setup example](https://github.com/redis/redis-iris/tree/main/examples/project_setup/cloud).
+1. Optional, but recommended: create `iris.toml` with a cloud profile, and add `IRIS_PROFILE=cloud` and `IRIS_CONFIG=./iris.toml` to `.env`. One `iris.toml` holds the URLs for every Redis Iris service you use, so the CLI and SDK manage them together, and switching deployments means switching one profile.
+
```toml
[profiles.cloud]
@@ -100,9 +101,18 @@ On Redis Cloud, the [Redis Cloud console](https://cloud.redis.io/) creates servi
On a self-managed deployment, the CLI creates services and keys with your operator tokens. Each token is the deployment's static admin token or an access token from your identity provider.
-The Playbooks commands in this section require an already deployed Playbooks control plane, data plane, and Identity Service. The [Playbooks Cloud setup guide](/content/operate/iris/agent-playbook/_index.md) covers managed provisioning; the CLI does not install a Playbooks deployment.
+The Playbooks commands in this section require an already deployed Playbooks control plane, data plane, and Identity Service. The CLI does not install a deployment.
-The services deploy on Kubernetes from the shared Redis Helm repository, `https://helm.redis.io/ai`. See [deploy self-managed Agent Memory](/content/operate/iris/agent-memory/self-managed/deploy.md) and [deploy self-managed Context Gateway](/content/operate/iris/context-gateway/self-managed/deploy.md). For a complete project, see the [self-managed project setup example](https://github.com/redis/redis-iris/tree/main/examples/project_setup/onprem).
+The services deploy on Kubernetes from the shared Redis Helm repository, [https://helm.redis.io/ai](https://helm.redis.io/ai). Each has its own self-managed guide:
+
+- [Self-managed Agent Memory](/content/operate/iris/agent-memory/self-managed/_index.md)
+- [Self-managed Agent Playbooks](/content/operate/iris/agent-playbook/self-managed/_index.md)
+- [Self-managed Context Gateway](/content/operate/iris/context-gateway/self-managed/_index.md)
+- [Self-managed Intent Router](/content/operate/iris/intent-router/self-managed/_index.md)
+- [Self-managed Lens](/content/operate/iris/lens/self-managed/_index.md) (beta)
+- [Identity Service](/content/operate/iris/identity-service/_index.md), which every self-managed service uses for agent keys
+
+
1. Create `iris.toml` with a profile for your deployment. It holds URLs only:
@@ -164,8 +174,5 @@ The CLI takes each setting from the first of these that sets it: a command optio
## More information
-- [The `iris` CLI in the redis-iris README](https://github.com/redis/redis-iris#the-cli)
-- [Configuration guide](https://github.com/redis/redis-iris/blob/main/docs/user_guides/configuration.md)
-- [Provision without the UI](https://github.com/redis/redis-iris/blob/main/docs/user_guides/provision-without-the-ui.md)
-- [Starter configuration for Redis Cloud and self-managed projects](https://github.com/redis/redis-iris/tree/main/examples/project_setup)
-- [redis-iris examples](https://github.com/redis/redis-iris/tree/main/examples), including adding Redis Iris to an agent you already have
+- [redis-iris on PyPI](https://pypi.org/project/redis-iris/)
+- [Redis Iris concepts](/content/develop/ai/context-engine/concepts/_index.md)
diff --git a/content/develop/ai/context-engine/langcache/_index.md b/content/develop/ai/langcache/_index.md
similarity index 91%
rename from content/develop/ai/context-engine/langcache/_index.md
rename to content/develop/ai/langcache/_index.md
index 7efd9d174f..2e45809a80 100644
--- a/content/develop/ai/context-engine/langcache/_index.md
+++ b/content/develop/ai/langcache/_index.md
@@ -8,11 +8,11 @@ categories:
description: Store LLM responses for AI apps in a semantic cache.
linkTitle: LangCache
hideListLinks: true
-weight: 30
+weight: 35
bannerText: LangCache is currently available in preview. Features and behavior are subject to change.
bannerChildren: true
aliases:
-- /develop/ai/langcache
+- /develop/ai/context-engine/langcache/
---
Cut LLM costs and improve response times with semantic caching.
@@ -20,10 +20,10 @@ Cut LLM costs and improve response times with semantic caching.
LangCache checks whether a semantically similar prompt has been answered before and returns the cached response instantly: no LLM call required. When there's no match, your app calls the LLM as usual and stores the result for future use.
- {{< tile-card icon="images/icon_logo/icon-data-structures-64-midnight.png" title="Concepts" description="Why a cache hit isn't binary anymore, and how to choose a similarity threshold" url="/develop/ai/context-engine/langcache/concepts" >}}
- {{< tile-card icon="images/icon_logo/icon-developers-64-midnight.png" title="Quick Start" description="Create a LangCache service on Redis Cloud and make your first API call" url="/operate/iris/langcache/create-service" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-code-64-duotone.png" title="API & SDK Examples" description="Search, store, and manage cache entries with REST, Python, or JS" url="/develop/ai/context-engine/langcache/api-examples" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-insight-64-duotone.png" title="Monitor Cache" description="Track hit rates, usage, and performance in Redis Cloud" url="/operate/iris/langcache/monitor-cache" >}}
+ {{< tile-card icon="images/icon_logo/icon-data-structures-64-midnight.png" title="Concepts" description="Why a cache hit isn't binary anymore, and how to choose a similarity threshold" url="/develop/ai/langcache/concepts" >}}
+ {{< tile-card icon="images/icon_logo/icon-developers-64-midnight.png" title="Quick Start" description="Create a LangCache service on Redis Cloud and make your first API call" url="/operate/rc/langcache/create-service" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-code-64-duotone.png" title="API & SDK Examples" description="Search, store, and manage cache entries with REST, Python, or JS" url="/develop/ai/langcache/api-examples" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-insight-64-duotone.png" title="Monitor Cache" description="Track hit rates, usage, and performance in Redis Cloud" url="/operate/rc/langcache/monitor-cache" >}}
## What is LangCache?
@@ -80,7 +80,7 @@ POST /v1/caches/{cacheId}/entries
}
```
-See the full [LangCache API and SDK examples](/content/develop/ai/context-engine/langcache/api-examples.md) for more.
+See the full [LangCache API and SDK examples](/content/develop/ai/langcache/api-examples.md) for more.
## LangCache overview
@@ -94,7 +94,7 @@ Imagine you’re using an LLM to build an agent to answer questions about your c
These prompts may have slight variations, but they essentially ask the same question. LangCache can help you avoid calling the LLM for each of these prompts by caching the response to the first prompt and returning it for any similar prompts.
-To watch a cache answer paraphrased questions, try the [interactive demo](/content/develop/ai/context-engine/langcache/interactive-demo.md).
+To watch a cache answer paraphrased questions, try the [interactive demo](/content/develop/ai/langcache/interactive-demo.md).
Using LangCache as a semantic caching service has the following benefits:
@@ -129,13 +129,13 @@ The following diagram displays how you can integrate LangCache into your GenAI a
1. Your app sends the prompt and the new response to LangCache through the `POST /v1/caches/{cacheId}/entries` endpoint.
1. LangCache stores the embedding with the new response in the cache for future use.
-See the [LangCache API and SDK examples](/content/develop/ai/context-engine/langcache/api-examples.md) for more information on how to use the LangCache API.
+See the [LangCache API and SDK examples](/content/develop/ai/langcache/api-examples.md) for more information on how to use the LangCache API.
## Get started
LangCache is currently in preview:
-- Public preview on [Redis Cloud](/content/operate/iris/langcache/_index.md)
+- Public preview on [Redis Cloud](/content/operate/rc/langcache/_index.md)
- Self-managed deployment on Kubernetes, as a private preview
- Fully-managed [private preview](https://redis.io/langcache/)
@@ -148,7 +148,7 @@ LangCache is currently in preview:
-tab-sep-
-Self-managed LangCache is available for deployment on Kubernetes as a private preview. See [Self-managed LangCache](/content/operate/iris/langcache/self-managed/_index.md) for deployment, configuration, security, and operations.
+Self-managed LangCache is available for deployment on Kubernetes as a private preview. See [Self-managed LangCache](/content/operate/rc/langcache/self-managed/_index.md) for deployment, configuration, security, and operations.
You need a license key to deploy: [contact Redis](https://redis.io/contact/) to request access.
diff --git a/content/develop/ai/context-engine/langcache/api-examples.md b/content/develop/ai/langcache/api-examples.md
similarity index 86%
rename from content/develop/ai/context-engine/langcache/api-examples.md
rename to content/develop/ai/langcache/api-examples.md
index 99b04030d8..5345a7fdab 100644
--- a/content/develop/ai/context-engine/langcache/api-examples.md
+++ b/content/develop/ai/langcache/api-examples.md
@@ -10,10 +10,10 @@ linktitle: API and SDK examples
title: Use the LangCache API and SDK
weight: 10
aliases:
-- /develop/ai/langcache/api-examples
+- /develop/ai/context-engine/langcache/api-examples/
---
-Use the [LangCache API](/content/develop/ai/context-engine/langcache/api-reference.md) from your client app to store and retrieve LLM, RAG, or agent responses.
+Use the [LangCache API](/content/develop/ai/langcache/api-reference.md) from your client app to store and retrieve LLM, RAG, or agent responses.
You can use any standard REST client or library to access the API. If your app is written in Python or Javascript, you can also use the LangCache Software Development Kits (SDKs) to access the API:
@@ -49,7 +49,7 @@ This example expects several variables to be set in the shell:
### Search LangCache for similar responses
-Use [`POST /v1/caches/{cacheId}/entries/search`](/content/develop/ai/context-engine/langcache/api-reference.md#tag/Cache-Entries/operation/search) to search the cache for matching responses to a user prompt.
+Use [`POST /v1/caches/{cacheId}/entries/search`](/content/develop/ai/langcache/api-reference.md#tag/Cache-Entries/operation/search) to search the cache for matching responses to a user prompt.
{{< clients-example set="langcache_sdk" step="search_basic" dft_tab_name="REST API" show_footer="false" description="Foundational: Search the cache for semantically similar responses to a user prompt" difficulty="beginner" >}}
POST https://[host]/v1/caches/{cacheId}/entries/search
@@ -93,7 +93,7 @@ POST https://[host]/v1/caches/{cacheId}/entries/search
### Store a new response in LangCache
-Use [`POST /v1/caches/{cacheId}/entries`](/content/develop/ai/context-engine/langcache/api-reference.md#tag/Cache-Entries/operation/set) to store a new response in the cache.
+Use [`POST /v1/caches/{cacheId}/entries`](/content/develop/ai/langcache/api-reference.md#tag/Cache-Entries/operation/set) to store a new response in the cache.
{{< clients-example set="langcache_sdk" step="store_basic" dft_tab_name="REST API" show_footer="false" description="Foundational: Store a new LLM response in the cache with its corresponding prompt for future retrieval" difficulty="beginner" >}}
POST https://[host]/v1/caches/{cacheId}/entries
@@ -120,13 +120,13 @@ POST https://[host]/v1/caches/{cacheId}/entries
### Delete cached responses
-Use [`DELETE /v1/caches/{cacheId}/entries/{entryId}`](/content/develop/ai/context-engine/langcache/api-reference.md#tag/Cache-Entries/operation/delete) to delete a cached response from the cache.
+Use [`DELETE /v1/caches/{cacheId}/entries/{entryId}`](/content/develop/ai/langcache/api-reference.md#tag/Cache-Entries/operation/delete) to delete a cached response from the cache.
{{< clients-example set="langcache_sdk" step="delete_entry" dft_tab_name="REST API" show_footer="false" description="Foundational: Delete a specific cached response by its entry ID when you need to remove outdated or incorrect cache entries" difficulty="beginner" >}}
DELETE https://[host]/v1/caches/{cacheId}/entries/{entryId}
{{< /clients-example >}}
-You can also use [`DELETE /v1/caches/{cacheId}/entries`](/content/develop/ai/context-engine/langcache/api-reference.md#tag/Cache-Entries/operation/deleteQuery) to delete multiple cached responses based on the `attributes` you specify. If you specify multiple `attributes`, LangCache will delete entries that contain all given attributes.
+You can also use [`DELETE /v1/caches/{cacheId}/entries`](/content/develop/ai/langcache/api-reference.md#tag/Cache-Entries/operation/deleteQuery) to delete multiple cached responses based on the `attributes` you specify. If you specify multiple `attributes`, LangCache will delete entries that contain all given attributes.
> [!WARNING]
> If you do not specify any `attributes`, all responses in the cache will be deleted. This cannot be undone.
@@ -145,7 +145,7 @@ DELETE https://[host]/v1/caches/{cacheId}/entries
### Flush the cache
Use
-[POST /v1/caches/{cacheId}/flush](https://redis.io/docs/latest/develop/ai/context-engine/langcache/api-reference/#tag/Cache-Entries/operation/flush)
+[POST /v1/caches/{cacheId}/flush](https://redis.io/docs/latest/develop/ai/langcache/api-reference/#tag/Cache-Entries/operation/flush)
to flush all entries from the cache.
{{< clients-example set="langcache_sdk" step="flush" dft_tab_name="REST API" show_footer="false" description="Flush cache: Clear all cached responses from the cache in a single operation (use with caution as this cannot be undone)" difficulty="advanced" >}}
diff --git a/content/develop/ai/context-engine/langcache/api-reference.md b/content/develop/ai/langcache/api-reference.md
similarity index 74%
rename from content/develop/ai/context-engine/langcache/api-reference.md
rename to content/develop/ai/langcache/api-reference.md
index c7451224c7..4c1c4dbb73 100644
--- a/content/develop/ai/context-engine/langcache/api-reference.md
+++ b/content/develop/ai/langcache/api-reference.md
@@ -1,11 +1,11 @@
---
Title: LangCache REST API
linkTitle: API reference
-aliases:
-- /develop/ai/langcache/api-reference
layout: apireference
type: page
params:
sourcefile: ./api.yaml
sortOperationsAlphabetically: false
----
\ No newline at end of file
+aliases:
+- /develop/ai/context-engine/langcache/api-reference/
+---
diff --git a/content/develop/ai/context-engine/langcache/api-reference/api.yaml b/content/develop/ai/langcache/api-reference/api.yaml
similarity index 99%
rename from content/develop/ai/context-engine/langcache/api-reference/api.yaml
rename to content/develop/ai/langcache/api-reference/api.yaml
index 92ed72630e..e3a1629492 100644
--- a/content/develop/ai/context-engine/langcache/api-reference/api.yaml
+++ b/content/develop/ai/langcache/api-reference/api.yaml
@@ -1,7 +1,7 @@
openapi: 3.0.2
info:
title: Redis LangCache Service
- description: API for managing a [Redis LangCache](https://redis.io/docs/latest/develop/ai/context-engine/langcache/) service.
+ description: API for managing a [Redis LangCache](https://redis.io/docs/latest/develop/ai/langcache/) service.
contact:
name: Redis
email: support@redis.com
diff --git a/content/develop/ai/context-engine/langcache/concepts.md b/content/develop/ai/langcache/concepts.md
similarity index 85%
rename from content/develop/ai/context-engine/langcache/concepts.md
rename to content/develop/ai/langcache/concepts.md
index 18d4f911b3..da8af3fad0 100644
--- a/content/develop/ai/context-engine/langcache/concepts.md
+++ b/content/develop/ai/langcache/concepts.md
@@ -9,6 +9,8 @@ hideListLinks: true
linktitle: Concepts
title: LangCache concepts
weight: 3
+aliases:
+- /develop/ai/context-engine/langcache/concepts/
---
## Semantic caching
@@ -57,8 +59,8 @@ See the [AI agent context engine FAQ](https://redis.io/blog/faq-real-time-contex
## Next steps
-- Try the [LangCache interactive demo]({{< relref "/develop/ai/context-engine/langcache/interactive-demo" >}}) to see how the similarity threshold changes hits and misses.
-- [Create a LangCache service]({{< relref "/operate/iris/langcache/create-service" >}}) on Redis Cloud.
-- [Deploy LangCache self-managed]({{< relref "/operate/iris/langcache/self-managed/deploy" >}}) on your own Kubernetes infrastructure.
-- [Use the LangCache API and SDK]({{< relref "/develop/ai/context-engine/langcache/api-examples" >}}) to search and populate a cache.
-- [LangCache REST API reference]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}) for the full endpoint and parameter details, including threshold configuration.
+- Try the [LangCache interactive demo]({{< relref "/develop/ai/langcache/interactive-demo" >}}) to see how the similarity threshold changes hits and misses.
+- [Create a LangCache service]({{< relref "/operate/rc/langcache/create-service" >}}) on Redis Cloud.
+- [Deploy LangCache self-managed]({{< relref "/operate/rc/langcache/self-managed/deploy" >}}) on your own Kubernetes infrastructure.
+- [Use the LangCache API and SDK]({{< relref "/develop/ai/langcache/api-examples" >}}) to search and populate a cache.
+- [LangCache REST API reference]({{< relref "/develop/ai/langcache/api-reference" >}}) for the full endpoint and parameter details, including threshold configuration.
diff --git a/content/develop/ai/context-engine/langcache/interactive-demo.md b/content/develop/ai/langcache/interactive-demo.md
similarity index 67%
rename from content/develop/ai/context-engine/langcache/interactive-demo.md
rename to content/develop/ai/langcache/interactive-demo.md
index 388852979a..2f7d733642 100644
--- a/content/develop/ai/context-engine/langcache/interactive-demo.md
+++ b/content/develop/ai/langcache/interactive-demo.md
@@ -9,11 +9,13 @@ hideListLinks: true
linktitle: Interactive demo
title: Redis LangCache interactive demo
weight: 5
+aliases:
+- /develop/ai/context-engine/langcache/interactive-demo/
---
Redis LangCache stores the answers your LLM generates and returns them when someone asks a similar question, so your app doesn't call the LLM again. This demo follows the help assistant of a food delivery app. You choose which questions its customers ask, and the demo shows each search, each cache hit or miss, and what the cache stores.
-The demo runs in your browser and doesn't connect to a LangCache service or an LLM. Its requests and responses follow the shapes of the [LangCache API](/content/develop/ai/context-engine/langcache/api-reference.md). The similarity scores, answers, and timings are illustrative. The customers and restaurants come from the same sample data as the [Redis Iris interactive demo](/content/develop/ai/context-engine/concepts/interactive-demo.md).
+The demo runs in your browser and doesn't connect to a LangCache service or an LLM. Its requests and responses follow the shapes of the [LangCache API](/content/develop/ai/langcache/api-reference.md). The similarity scores, answers, and timings are illustrative. The customers and restaurants come from the same sample data as the [Redis Iris interactive demo](/content/develop/ai/context-engine/concepts/interactive-demo.md).
{{< langcache-demo >}}
@@ -25,6 +27,6 @@ The demo runs in your browser and doesn't connect to a LangCache service or an L
## Next steps
-- Read [LangCache concepts](/content/develop/ai/context-engine/langcache/concepts.md) to learn how to choose a similarity threshold.
-- [Create a LangCache service](/content/operate/iris/langcache/create-service.md) on Redis Cloud.
-- Use the [LangCache API and SDK](/content/develop/ai/context-engine/langcache/api-examples.md) to search and store entries from your app.
+- Read [LangCache concepts](/content/develop/ai/langcache/concepts.md) to learn how to choose a similarity threshold.
+- [Create a LangCache service](/content/operate/rc/langcache/create-service.md) on Redis Cloud.
+- Use the [LangCache API and SDK](/content/develop/ai/langcache/api-examples.md) to search and store entries from your app.
diff --git a/content/develop/use-cases/semantic-cache/_index.md b/content/develop/use-cases/semantic-cache/_index.md
index ed38fcee83..f682f925c2 100644
--- a/content/develop/use-cases/semantic-cache/_index.md
+++ b/content/develop/use-cases/semantic-cache/_index.md
@@ -58,7 +58,7 @@ The following libraries, frameworks, and managed services build on Redis for sem
- **Python**: [RedisVL](https://github.com/redis/redis-vl-python) provides the `SemanticCache` API with built-in embedding, distance thresholds, TTL, and metadata filters. See the [RedisVL LLM cache user guide](/content/develop/ai/redisvl/user_guide/how_to_guides/llmcache.md) and the [LangCache integration guide](/content/develop/ai/redisvl/user_guide/how_to_guides/langcache_semantic_cache.md).
- **Frameworks**: [LangChain](https://python.langchain.com/docs/integrations/llm_caching/#redis-cache) (Redis as an LLM cache and vector store), [LlamaIndex](https://developers.llamaindex.ai/python/examples/vector_stores/redisindexdemo/), and [LangGraph](https://langchain-ai.github.io/langgraph/) for agent memory and response caching.
-- **Managed**: [Redis LangCache](/content/develop/ai/context-engine/langcache/_index.md) is a fully managed semantic cache with a REST API, configurable distance thresholds, automatic eviction, and built-in metrics — no index management or embedding wiring required.
+- **Managed**: [Redis LangCache](/content/develop/ai/langcache/_index.md) is a fully managed semantic cache with a REST API, configurable distance thresholds, automatic eviction, and built-in metrics — no index management or embedding wiring required.
## Code examples to build your own Redis semantic cache
diff --git a/content/develop/whats-new/_index.md b/content/develop/whats-new/_index.md
index 726d79397c..608a556a7d 100644
--- a/content/develop/whats-new/_index.md
+++ b/content/develop/whats-new/_index.md
@@ -22,8 +22,8 @@ weight: 10
### Redis Iris (Context Engine)
-- Added self-managed deployment documentation for all four Redis Iris services: [LangCache](/content/operate/iris/langcache/self-managed/_index.md), [Agent Memory](/content/operate/iris/agent-memory/self-managed/_index.md), Context Retriever, and [Data Integration](/content/integrate/redis-data-integration/_index.md)
-- Updated [LangCache](/content/develop/ai/context-engine/langcache/_index.md), [Agent Memory](/content/develop/ai/context-engine/agent-memory/_index.md), Context Retriever, and [Data Integration](/content/develop/ai/context-engine/data-integration/_index.md) quickstarts with fully managed and self-managed deployment paths
+- Added self-managed deployment documentation for all four Redis Iris services: [LangCache](/content/operate/rc/langcache/self-managed/_index.md), [Agent Memory](/content/operate/iris/agent-memory/self-managed/_index.md), Context Retriever, and [Data Integration](/content/integrate/redis-data-integration/_index.md)
+- Updated [LangCache](/content/develop/ai/langcache/_index.md), [Agent Memory](/content/develop/ai/context-engine/agent-memory/_index.md), Context Retriever, and [Data Integration](/content/develop/ai/context-engine/data-integration/_index.md) quickstarts with fully managed and self-managed deployment paths
- Added [Redis Iris concepts](/content/develop/ai/context-engine/concepts/_index.md) explaining how agents get context from Redis Iris
- Added new [AI agent builder](/content/develop/ai/agent-builder/_index.md) templates for knowledge assistants (RAG) and Redis Iris conversational assistants
@@ -149,7 +149,7 @@ weight: 10
- Vectorizers
- Added [AI video tutorials](/content/develop/ai/ai-videos.md) with YouTube content
- Added [AI notebook collection](/content/develop/ai/notebook-collection.md) with notebook links
-- Added [LangCache documentation](/content/develop/ai/context-engine/langcache/_index.md) with API examples
+- Added [LangCache documentation](/content/develop/ai/langcache/_index.md) with API examples
---
@@ -189,7 +189,7 @@ weight: 10
- Updated [vector types documentation](/content/develop/ai/search-and-query/vectors/_index.md) for INT8 and UINT8
- Added [GEO search precision information](/content/develop/ai/search-and-query/indexing/geoindex.md)
-- Enhanced [LangCache SDK](/content/develop/ai/context-engine/langcache/_index.md) with savings calculator and improved API documentation
+- Enhanced [LangCache SDK](/content/develop/ai/langcache/_index.md) with savings calculator and improved API documentation
---
@@ -248,7 +248,7 @@ weight: 10
- [Lettuce vector queries](/content/develop/clients/lettuce/vecsearch.md)
- [Lettuce vector sets](/content/develop/clients/lettuce/vecsets.md)
- Updated [redisvl documentation](/content/develop/ai/redisvl/_index.md) for versions 0.6.0-0.8.2
-- Added [LangCache SDK](/content/develop/ai/context-engine/langcache/_index.md) documentation with [API reference](/content/develop/ai/context-engine/langcache/api-examples.md)
+- Added [LangCache SDK](/content/develop/ai/langcache/_index.md) documentation with [API reference](/content/develop/ai/langcache/api-examples.md)
---
diff --git a/content/embeds/rc-langcache-get-started.md b/content/embeds/rc-langcache-get-started.md
index ea0bdfd9b6..dd1fe7be1c 100644
--- a/content/embeds/rc-langcache-get-started.md
+++ b/content/embeds/rc-langcache-get-started.md
@@ -1,10 +1,10 @@
To set up LangCache on Redis Cloud:
1. [Create a database]({{< relref "/operate/rc/databases/create-database" >}}) on Redis Cloud.
-2. [Create a LangCache service]({{< relref "/operate/iris/langcache/create-service" >}}) for your database on Redis Cloud.
-3. [Use the LangCache API]({{< relref "/operate/iris/langcache/use-langcache" >}}) from your client app.
+2. [Create a LangCache service]({{< relref "/operate/rc/langcache/create-service" >}}) for your database on Redis Cloud.
+3. [Use the LangCache API]({{< relref "/operate/rc/langcache/use-langcache" >}}) from your client app.
-After you set up LangCache, you can [view and edit the cache]({{< relref "/operate/iris/langcache/view-edit-cache" >}}) and [monitor the cache's performance]({{< relref "/operate/iris/langcache/monitor-cache" >}}).
+After you set up LangCache, you can [view and edit the cache]({{< relref "/operate/rc/langcache/view-edit-cache" >}}) and [monitor the cache's performance]({{< relref "/operate/rc/langcache/monitor-cache" >}}).
See also our [Redis LangCache setup](https://www.youtube.com/watch?v=UOGhMZlZLko)
tutorial video for advice on how to get started.
diff --git a/content/operate/_index.md b/content/operate/_index.md
index 309596ba51..c4b24a3ffc 100644
--- a/content/operate/_index.md
+++ b/content/operate/_index.md
@@ -85,7 +85,7 @@ Services available on cloud or self-managed infrastructure for AI applications.
}}">Overview→
}}">Enable Agent Memory→
}}">Deploy Context Gateway→
- }}">Enable LangCache
+ }}">Enable LangCache
diff --git a/content/operate/iris/_index.md b/content/operate/iris/_index.md
index 71c1ec1a43..3908a78613 100644
--- a/content/operate/iris/_index.md
+++ b/content/operate/iris/_index.md
@@ -17,10 +17,11 @@ Use this section to deploy, configure, and operate Redis Iris services. Develope
{{< tile-card icon="images/dev/icons/icon-redis-agent-memory-64-duotone.png" title="Redis Agent Memory" description="Create and manage a service on Redis Cloud or deploy it on your own infrastructure" url="/operate/iris/agent-memory" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Redis Agent Playbooks" description="Create a playbook of approved answers and procedures on Redis Cloud" url="/operate/iris/agent-playbook" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Redis Agent Playbooks" description="Create a playbook of published answers and procedures on Redis Cloud or your own infrastructure" url="/operate/iris/agent-playbook" >}}
{{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Redis Context Gateway" description="Create one MCP endpoint for your agents' tools on Redis Cloud or your own infrastructure" url="/operate/iris/context-gateway" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Redis Intent Router" description="Deploy a service that classifies requests into intents on your own infrastructure" url="/operate/iris/intent-router" >}}
- {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Lens" description="Trace your agents' turns on Redis Cloud" url="/operate/iris/lens" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Redis Intent Router" description="Classify requests into intents on Redis Cloud or your own infrastructure" url="/operate/iris/intent-router" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Lens (beta)" description="Trace your agents' turns on Redis Cloud or your own infrastructure" url="/operate/iris/lens" >}}
+ {{< tile-card icon="images/dev/icons/icon-redis-iris-64-duotone.png" title="Identity Service" description="Issue and check agent keys for every self-managed Redis Iris service" url="/operate/iris/identity-service" >}}
## Deployment options
@@ -41,8 +42,11 @@ Create and manage Redis Iris services through the Redis Cloud console without de
Deploy Redis Iris services on Kubernetes when you need to operate them on your own infrastructure.
- [Self-managed Redis Agent Memory]({{< relref "/operate/iris/agent-memory/self-managed" >}})
+- [Self-managed Redis Agent Playbooks](/content/operate/iris/agent-playbook/self-managed/_index.md)
- [Self-managed Redis Context Gateway]({{< relref "/operate/iris/context-gateway/self-managed" >}})
- [Self-managed Redis Intent Router]({{< relref "/operate/iris/intent-router/self-managed" >}})
+- [Self-managed Lens](/content/operate/iris/lens/self-managed/_index.md) (beta)
+- [Identity Service](/content/operate/iris/identity-service/_index.md), which issues and checks agent keys for every self-managed service
## Agent Mesh SDK beta
diff --git a/content/operate/iris/agent-memory/_index.md b/content/operate/iris/agent-memory/_index.md
index 5a3fdf2f22..d23caa63b0 100644
--- a/content/operate/iris/agent-memory/_index.md
+++ b/content/operate/iris/agent-memory/_index.md
@@ -21,8 +21,10 @@ Use Redis Agent Memory as a managed service on Redis Cloud.
[Create a Redis Agent Memory service]({{< relref "/operate/iris/agent-memory/create-service" >}}), [configure its AI models]({{< relref "/operate/iris/agent-memory/model-configuration" >}}), or [view and manage an existing service]({{< relref "/operate/iris/agent-memory/view-service" >}}).
+After setup, use the [developer quickstart](/content/develop/ai/context-engine/agent-memory/quickstart.md) to store a conversation and recall what Agent Memory extracted from it.
+
### Self-managed
-Deploy, configure, secure, and operate Redis Agent Memory on your own Kubernetes infrastructure.
+Deploy Redis Agent Memory on Kubernetes to run it on your own infrastructure.
-[Open the self-managed Redis Agent Memory documentation]({{< relref "/operate/iris/agent-memory/self-managed" >}})
+[Start with the self-managed deployment guide](/content/operate/iris/agent-memory/self-managed/_index.md).
diff --git a/content/operate/iris/agent-memory/create-service.md b/content/operate/iris/agent-memory/create-service.md
index e5836a99b2..fec69dfcef 100644
--- a/content/operate/iris/agent-memory/create-service.md
+++ b/content/operate/iris/agent-memory/create-service.md
@@ -6,8 +6,8 @@ categories:
- iris
description: Create an Agent Memory service in Redis Cloud to store working and long-term memory for AI agents.
hideListLinks: true
-linktitle: Create service
-title: Create an Agent Memory service
+linktitle: Create Cloud service
+title: Create an Agent Memory service on Redis Cloud
weight: 5
aliases:
- /operate/rc/context-engine/agent-memory/create-service/
diff --git a/content/operate/iris/agent-memory/self-managed/_index.md b/content/operate/iris/agent-memory/self-managed/_index.md
index fffdb88fa3..3ba8743d73 100644
--- a/content/operate/iris/agent-memory/self-managed/_index.md
+++ b/content/operate/iris/agent-memory/self-managed/_index.md
@@ -32,7 +32,7 @@ documents the self-managed admin endpoints for stores.
## What you are deploying
The `redis-agent-memory` chart `1.0.0` deploys the Data Plane, workers, and Control Plane.
-Install the `iris-identity-service` chart `1.0.0` as a separate release first, then connect
+Install the `iris-identity-service` chart `1.2.0` as a separate release first, then connect
Memory to it. Memory does not deploy Identity Service resources or include it as a subchart.
A unified Redis Iris chart that installs Memory and Identity Service as one release is planned.
These pages document the separate releases.
@@ -94,3 +94,67 @@ provides searchable context across sessions.
Long-term memory `memoryType` is an open identifier. When omitted on create,
Redis Agent Memory stores the record as `semantic`; built-in names include `semantic`,
`episodic`, and `message`.
+
+## Create a store with the CLI and SDK
+
+After you [deploy](/content/operate/iris/agent-memory/self-managed/deploy.md), the `iris` CLI in the [`redis-iris`](https://pypi.org/project/redis-iris/) package creates a store, mints its agent key, and checks every hop. The [Control Plane API examples](/content/operate/iris/agent-memory/self-managed/api-examples.md) show the same steps over HTTP.
+
+1. Install the package:
+
+ ```bash
+ pip install 'redis-iris>=1.0.0'
+ ```
+
+1. Create `iris.toml` with a profile for your deployment. It holds URLs only:
+
+ ```toml
+ [profiles.suite]
+ kind = "self-managed"
+
+ [profiles.suite.agent_memory]
+ service_url = ""
+ url = ""
+ identity_url = ""
+ ```
+
+1. Put the operator tokens in `.env.admin`, separate from your application's `.env`:
+
+ ```bash
+ IRIS_CONFIG=./iris.toml
+ IRIS_PROFILE=suite
+ IRIS_AGENT_MEMORY_SERVICE_TOKEN=
+ IRIS_IDENTITY_TOKEN=
+ ```
+
+1. Load the tokens and do a dry run. It sends nothing:
+
+ ```bash
+ set -a; source .env.admin; set +a
+ iris agent-memory service create --name support-memory --dry-run
+ ```
+
+1. Create the store. The CLI mints its agent key and writes `IRIS_AGENT_MEMORY_URL`, `IRIS_AGENT_MEMORY_STORE_ID`, and `IRIS_AGENT_MEMORY_API_KEY` to `.env` without printing the key:
+
+ ```bash
+ iris agent-memory service create --name support-memory --write-env .env
+ ```
+
+1. Check every hop, from the Control Plane to a read with the agent key:
+
+ ```bash
+ set -a; source .env; set +a
+ iris agent-memory service check "$IRIS_AGENT_MEMORY_STORE_ID" --env-file .env
+ ```
+
+Your application reads the same `.env`. With the Python SDK:
+
+```python
+from redis_iris import AgentMemory
+
+memory = AgentMemory.from_env()
+convo = memory.conversation(owner="user-1042", session_id="support-thread-1")
+convo.user("Please send updates by email.")
+print(memory.recall("How does this user want updates?", owner="user-1042").as_prompt())
+```
+
+See [SDK and CLI setup](/content/develop/ai/context-engine/sdk-and-cli.md) for profiles and credentials.
diff --git a/content/operate/iris/agent-memory/self-managed/deploy.md b/content/operate/iris/agent-memory/self-managed/deploy.md
index 37ac03161c..a2e36a3e25 100644
--- a/content/operate/iris/agent-memory/self-managed/deploy.md
+++ b/content/operate/iris/agent-memory/self-managed/deploy.md
@@ -22,7 +22,7 @@ These steps install Redis Agent Memory with chart-rendered configuration and age
authentication, and end with one authenticated call to the Data Plane.
Install Identity Service as release `ids`, then Memory as release `redis-agent-memory`.
-These steps use Memory chart `1.0.0` and Identity Service chart `1.0.0` in one namespace.
+These steps use Memory chart `1.0.0` and Identity Service chart `1.2.0` in one namespace.
You create the shared credentials and Identity Service control token; Memory generates its
Control Plane admin token. See [Credentials](/content/operate/iris/agent-memory/self-managed/authentication.md#credentials).
@@ -126,6 +126,8 @@ metadata:
### Install Identity Service first
+For every Identity Service setting, and for running one release that serves several products, see the [Identity Service guide](/content/operate/iris/identity-service/_index.md).
+
Save this as `values-ids.yaml`:
```yaml
@@ -160,7 +162,7 @@ tls:
helm repo add redis-ai https://helm.redis.io/ai
helm repo update redis-ai
helm install ids redis-ai/iris-identity-service \
- --version 1.0.0 \
+ --version 1.2.0 \
--namespace \
-f values-ids.yaml
```
diff --git a/content/operate/iris/agent-memory/self-managed/operations.md b/content/operate/iris/agent-memory/self-managed/operations.md
index 5318f81f24..947953b3eb 100644
--- a/content/operate/iris/agent-memory/self-managed/operations.md
+++ b/content/operate/iris/agent-memory/self-managed/operations.md
@@ -82,7 +82,7 @@ kubectl -n create secret generic memory-dp-credential \
RUNTIME_CREDENTIAL_CHECKSUM="$(shasum -a 256 ./memory-dp-token | awk '{print $1}')"
helm upgrade ids redis-ai/iris-identity-service \
- --version 1.0.0 \
+ --version 1.2.0 \
--namespace \
-f values-ids.yaml \
--set-string "runtime.serviceCredentials[0].existingSecretChecksum=$RUNTIME_CREDENTIAL_CHECKSUM"
@@ -294,7 +294,7 @@ helm upgrade redis-agent-memory redis-ai/redis-agent-memory \
-f redis-agent-memory/values-fips.yaml
helm upgrade ids redis-ai/iris-identity-service \
- --version 1.0.0 \
+ --version 1.2.0 \
--namespace \
-f values-ids.yaml
```
diff --git a/content/operate/iris/agent-memory/self-managed/prerequisites.md b/content/operate/iris/agent-memory/self-managed/prerequisites.md
index 6bfd167cc6..ee29d972fe 100644
--- a/content/operate/iris/agent-memory/self-managed/prerequisites.md
+++ b/content/operate/iris/agent-memory/self-managed/prerequisites.md
@@ -18,7 +18,7 @@ aliases:
Redis Agent Memory is distributed as container images on Docker Hub plus a Helm
chart in the Redis AI Helm repository. The chart deploys the Redis Agent Memory Data
Plane, Redis Agent Memory workers, and the Redis Agent Memory Control Plane. Install Identity
-Service separately with the `iris-identity-service` chart `1.0.0` before connecting Memory chart `1.0.0`.
+Service separately with the `iris-identity-service` chart `1.2.0` before connecting Memory chart `1.0.0`.
You provide the Redis databases, provider credentials, Kubernetes exposure, and
license material used by the deployment.
@@ -132,7 +132,7 @@ To supply a complete configuration file in your own Secret instead, see
## Release artifacts and image tags
Memory chart `1.0.0` defaults `image.tag` and `controlplane.image.tag` to `1.0.0`.
-Identity Service chart `1.0.0` defaults its image to its own application version, `1.0.0`.
+Identity Service chart `1.2.0` defaults its image to its own application version, `1.2.0`.
Set tags explicitly when pinning images or using a mirror. The releases have independent versions.
Both charts are published at `https://helm.redis.io/ai` as `redis-ai/redis-agent-memory`
@@ -156,7 +156,7 @@ Mirror these images into your internal registry:
For this release, `` is `1.0.0` and `` is `1.0.0`.
Inspect each package with `helm show chart redis-ai/redis-agent-memory --version 1.0.0`
-and `helm show chart redis-ai/iris-identity-service --version 1.0.0`. Memory does not pin
+and `helm show chart redis-ai/iris-identity-service --version 1.2.0`. Memory does not pin
or install the Identity Service chart.
```bash
diff --git a/content/operate/iris/agent-memory/self-managed/reference.md b/content/operate/iris/agent-memory/self-managed/reference.md
index f2fd6ad8d0..4a7fe8efea 100644
--- a/content/operate/iris/agent-memory/self-managed/reference.md
+++ b/content/operate/iris/agent-memory/self-managed/reference.md
@@ -83,7 +83,7 @@ CSI-synced Secrets, make sure a Control Plane pod also mounts the corresponding
| Need | Reference |
| --- | --- |
| Helm chart values | `values.yaml` at the chart root (`helm pull redis-ai/redis-agent-memory --version 1.0.0 --untar`) |
-| Identity Service chart values | `helm show values redis-ai/iris-identity-service --version 1.0.0` |
+| Identity Service chart values | `helm show values redis-ai/iris-identity-service --version 1.2.0` |
| FIPS values overlay | `values-fips.yaml` at the chart root |
| NetworkPolicy reference | `networkpolicy.reference.yaml` at the chart root |
| Chart README | `README.md` at the chart root |
diff --git a/content/operate/iris/agent-playbook/_index.md b/content/operate/iris/agent-playbook/_index.md
index db4a9bc12a..70b47c24e4 100644
--- a/content/operate/iris/agent-playbook/_index.md
+++ b/content/operate/iris/agent-playbook/_index.md
@@ -1,6 +1,6 @@
---
title: Redis Agent Playbooks
-description: Create and operate Redis Agent Playbooks on Redis Cloud.
+description: Create and operate Redis Agent Playbooks on Redis Cloud or your own infrastructure.
linkTitle: Agent Playbooks
alwaysopen: false
categories:
@@ -22,3 +22,9 @@ Use Redis Agent Playbooks as a managed service on Redis Cloud.
[Create a playbook](/content/operate/iris/agent-playbook/create-playbook.md), or [view and manage an existing playbook](/content/operate/iris/agent-playbook/manage-playbook.md) and its entries, proposals, and settings.
After setup, use the [developer quickstart](/content/develop/ai/context-engine/agent-playbooks/quickstart.md) to publish and retrieve your first FAQ.
+
+### Self-managed
+
+Deploy Redis Agent Playbooks on Kubernetes to run it on your own infrastructure.
+
+[Start with the self-managed deployment guide](/content/operate/iris/agent-playbook/self-managed/_index.md).
diff --git a/content/operate/iris/agent-playbook/self-managed/_index.md b/content/operate/iris/agent-playbook/self-managed/_index.md
new file mode 100644
index 0000000000..c64d9249fa
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/_index.md
@@ -0,0 +1,76 @@
+---
+Title: Self-managed Redis Agent Playbooks
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Deploy, configure, and operate Redis Agent Playbooks on a self-managed Kubernetes cluster.
+linkTitle: Self-managed
+weight: 40
+hideListLinks: true
+bannerText: A license key is required to deploy. Contact your Redis representative or [contact sales](https://redis.io/contact/).
+bannerChildren: true
+---
+
+Redis Agent Playbooks store the answers and procedures your business approves as versioned FAQs and skills, and serve the published versions to your agents. Developers author entries and review proposals in a playbook; agents retrieve published entries over REST or the Model Context Protocol (MCP). Before developers can do that, a platform administrator deploys Agent Playbooks and creates playbooks and agent keys for them.
+
+This guide is for that administrator. It covers deploying Agent Playbooks on your own Kubernetes cluster with a Helm chart, then configuring, securing, and operating it. To install, start with the [prerequisites](/content/operate/iris/agent-playbook/self-managed/prerequisites.md).
+
+The `redis-agent-playbook` Helm chart deploys the Agent Playbooks control plane and data plane, and optionally a background extraction worker. It connects to a separately installed Identity Service release, which issues and checks agent keys. You provide the Identity Service release, the Redis databases, the embedding provider, and the license. The chart does not install Redis or configure ingress and certificates.
+
+These guides use `redis-agent-playbook` chart `1.0.0`.
+
+Applications call the data plane to author, review, and retrieve entries, as described in the [data-plane API reference](/content/develop/ai/context-engine/agent-playbooks/api-reference.md). The [control-plane API reference](/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md) documents the administration endpoints for playbooks.
+
+## What you deploy
+
+| Component | Purpose | Service port |
+| --- | --- | --- |
+| Control plane | Create playbooks, manage their settings and lifecycle, and validate agent-key grants. | `9200` |
+| Data plane | Author and retrieve FAQs and skills, review proposals, and serve MCP requests. | `9201` |
+| Extraction worker | Optionally propose FAQs from connected Redis Agent Memory sessions. | `9203` |
+| Identity Service | Issue agent keys and check them for the data plane. Installed as its own release. | `9200` |
+| Metadata Redis | Store playbook configuration. | Customer-provided |
+| Content Redis | Store entries, proposals, and search indexes. Needs JSON and Search. | Customer-provided |
+
+Metadata and content need physically separate Redis deployments.
+
+### How the components work together
+
+| Flow | Caller | Service | Backing store |
+| --- | --- | --- | --- |
+| Playbook administration | Platform admin | Control plane | Metadata Redis |
+| Agent-key administration | Platform admin | Identity Service | Identity Service metadata Redis |
+| Grant validation | Identity Service | Control plane | Metadata Redis |
+| Authoring, review, and retrieval | Application or agent | Data plane | Content Redis and the embedding provider |
+
+1. Platform admins create playbooks through the control plane, then mint agent keys through the Identity Service.
+1. The Identity Service asks the control plane to confirm each playbook grant before it stores a key.
+1. Applications call the data plane with an agent key. The data plane checks the key with the Identity Service and reads or writes the playbook's content.
+
+### API surfaces
+
+| API surface | Endpoint | Purpose |
+| --- | --- | --- |
+| Data plane | `/iris/data/v1/agent-playbooks/playbooks/{playbookId}` | Authoring, review, and retrieval for one playbook. |
+| MCP | `/iris/data/v1/agent-playbooks/playbooks/{playbookId}/mcp` | Read-only MCP tools for agents, on the data-plane port. |
+| Control plane | `/iris/v1/agent-playbooks/playbooks`, `/iris/v1/agent-playbooks/models` | Administration of playbooks, their settings, and extraction bindings. |
+| Health | `/health/liveness`, `/health/readiness` | Liveness and readiness on both planes. |
+| Identity Service | `/v1/api-keys` | Administration of agent keys. |
+
+## Get started
+
+1. Review the [prerequisites](/content/operate/iris/agent-playbook/self-managed/prerequisites.md).
+1. Prepare the [configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md).
+1. [Deploy the chart](/content/operate/iris/agent-playbook/self-managed/deploy.md).
+1. [Load administrative credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#load-the-administrative-credentials).
+1. [Create a playbook and agent keys](/content/operate/iris/agent-playbook/self-managed/api-examples.md).
+1. Optional: [configure background FAQ extraction](/content/operate/iris/agent-playbook/self-managed/extraction.md).
+
+## Manage the deployment
+
+- [Rotate or revoke agent keys](/content/operate/iris/agent-playbook/self-managed/operations.md#rotate-or-revoke-agent-keys).
+- [Check health, clear content, rotate Secrets, back up, and upgrade](/content/operate/iris/agent-playbook/self-managed/operations.md).
+- [Configure operator sign-in with OpenID Connect (OIDC)](/content/operate/iris/agent-playbook/self-managed/authentication.md#configure-operator-oidc-access).
+- [Troubleshoot the deployment](/content/operate/iris/agent-playbook/self-managed/reference.md#troubleshooting).
diff --git a/content/operate/iris/agent-playbook/self-managed/api-examples.md b/content/operate/iris/agent-playbook/self-managed/api-examples.md
new file mode 100644
index 0000000000..e1e20f250b
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/api-examples.md
@@ -0,0 +1,159 @@
+---
+Title: Self-managed Agent Playbooks API examples
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Create a playbook, mint publisher and reader agent keys, verify agent access, and hand connection details to a developer.
+linkTitle: API examples
+weight: 70
+hideListLinks: true
+---
+
+Create a playbook, issue publisher and reader agent keys, and verify application access with curl or the Iris command-line interface (CLI).
+
+Before you begin, [deploy the chart and forward the APIs](/content/operate/iris/agent-playbook/self-managed/deploy.md#6-verify-pods-and-health), then [load the administrative credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#load-the-administrative-credentials). Keep response files private:
+
+```bash
+umask 077
+```
+
+The local HTTP addresses use the Kubernetes port-forwards. For application deployment, give developers the data-plane endpoint your platform exposes.
+
+## Create a playbook
+
+List the embedding models configured for this deployment:
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/models" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ | jq '.items[] | select(.purpose == "EMBEDDING")'
+```
+
+Create the playbook with one of the returned identities:
+
+```bash
+jq -n \
+ --arg provider '' \
+ --arg model '' \
+ --argjson dimensions '' \
+ '{name: "support", embedding: {provider: $provider, model: $model, dimensions: $dimensions}}' \
+ > playbook-request.json
+
+curl --fail-with-body -sS \
+ -X POST "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data-binary @playbook-request.json > playbook.json
+export IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID="$(jq -er '.playbookId' playbook.json)"
+```
+
+Playbook IDs start with `pb_`. Read the playbook's state:
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ | jq '{playbookId, state, embedding, discovery}'
+```
+
+Continue when `state` is `READY`. If it is `PROVISIONING`, repeat the read. If it is `FAILED`, check service health and logs before you retry. Creating a playbook with a name already in use returns `409`.
+
+To list playbooks, send `GET /iris/v1/agent-playbooks/playbooks`. The response holds `items` and, when more follow, a `nextCursor` to pass back as `cursor`.
+
+## Create agent keys
+
+Create a publisher grant for this playbook:
+
+```bash
+jq -n --arg id "$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" '{
+ name: "support-publisher",
+ grants: [{
+ tenant: "default",
+ product: "playbook",
+ resourceType: "playbook",
+ resourceId: $id,
+ actions: ["write", "publish"]
+ }]
+}' > publisher-grant.json
+```
+
+Use the deployment's `tenantId` as `tenant`. Issue the key through the Identity Service:
+
+```bash
+curl --fail-with-body -sS \
+ -X POST "$IRIS_IDENTITY_URL/v1/api-keys" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data-binary @publisher-grant.json > publisher-key.json
+export IRIS_AGENT_PLAYBOOKS_API_KEY="$(jq -er '.token' publisher-key.json)"
+```
+
+Issue a separate reader key for the same playbook:
+
+```bash
+jq '.name = "support-reader" | .grants[0].actions = ["read"]' publisher-grant.json \
+ | curl --fail-with-body -sS \
+ -X POST "$IRIS_IDENTITY_URL/v1/api-keys" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data-binary @- > reader-key.json
+```
+
+Save both tokens in your secret manager and keep their `keyId` values. The Identity Service returns a token only when it creates or rotates a key. Minting fails if the playbook doesn't exist or the grant names another tenant.
+
+## Verify application access
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_URL/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/health" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY"
+```
+
+The response reports `READY` for the playbook, its metadata and content Redis, the embedding provider, and the license.
+
+## Hand off to a developer
+
+Give the content team the data-plane endpoint, the playbook ID, and the publisher key for the [developer quickstart](/content/develop/ai/context-engine/agent-playbooks/quickstart.md). They set these variables:
+
+```dotenv
+IRIS_AGENT_PLAYBOOKS_URL=''
+IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID=''
+IRIS_AGENT_PLAYBOOKS_API_KEY=''
+```
+
+Give runtime agents the reader key instead, for [agent integration](/content/develop/ai/context-engine/agent-playbooks/agent-integration.md) over REST or [MCP](/content/develop/ai/context-engine/agent-playbooks/mcp.md). Remove the local key-response files after you save both tokens.
+
+## Use the Iris CLI
+
+The Iris CLI reads the same variables. Install it with Python 3.11 or later:
+
+```bash
+python -m pip install 'redis-iris>=1.0.0'
+```
+
+Create a playbook and mint a read-only key for it in one step, writing the connection values to `.env`:
+
+```bash
+iris agent-playbooks service create --name support \
+ --embedding-provider openai \
+ --embedding-model '' \
+ --embedding-dimensions '' \
+ --key-actions read \
+ --write-env .env
+```
+
+`--embedding-provider` accepts `openai` or `noop`, so the CLI can create playbooks only for a connection named `openai`. The CLI sends FAQ and skill minimum scores of `0.3` unless you pass `--faq-min-score` and `--skill-min-score`; calibrate them against your own scores. Add `--dry-run` to print the request without sending it.
+
+Mint a content key with `read`, `write`, and `publish` for an existing playbook, then check every hop from the control plane to a data read:
+
+```bash
+iris agent-playbooks service key "$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" --role content --write .env
+iris agent-playbooks service check "$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" --env-file .env
+```
+
+Inspect a playbook with `iris agent-playbooks service show `, and list, rotate, or revoke keys with `iris identity keys`. Keys the CLI mints expire after 90 days unless you pass `--expires`.
+
+For retrieval settings, see [Playbook settings](/content/operate/iris/agent-playbook/self-managed/configuration.md#playbook-settings).
diff --git a/content/operate/iris/agent-playbook/self-managed/authentication.md b/content/operate/iris/agent-playbook/self-managed/authentication.md
new file mode 100644
index 0000000000..ddb090c4fb
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/authentication.md
@@ -0,0 +1,143 @@
+---
+Title: Authentication and authorization
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Understand the Agent Playbooks credentials, load the administration tokens, scope agent-key grants, and configure operator sign-in with OpenID Connect.
+linkTitle: Authentication and authorization
+weight: 60
+hideListLinks: true
+---
+
+Self-managed Agent Playbooks uses administrative tokens for management and scoped agent keys for applications.
+
+| Caller | API | Credential |
+| --- | --- | --- |
+| Playbook administrator | Control plane, `/iris/v1/agent-playbooks` | Admin token, or an operator's OpenID Connect (OIDC) access token. |
+| Key administrator | Identity Service, `/v1/api-keys` | Identity Service control token. |
+| Application or agent | Data plane, `/iris/data/v1/agent-playbooks` | Agent key with grants for the requested playbook. |
+| Administrator working with content | Data plane, `/iris/data/v1/agent-playbooks` | Admin token, or an OIDC access token with a mapped admin role. |
+
+Keep administrative tokens out of application configuration and model prompts.
+
+## Credentials
+
+| Credential | Who presents it to whom | Secret / key | Auto-generated? | What it unlocks |
+| --- | --- | --- | --- | --- |
+| Admin token | Operator → control plane (`:9200`) and data plane (`:9201`) | `playbook-controlplane-admin-token` / `token` | Yes (`controlplane.adminToken.autoGenerate`) | Full Agent Playbooks access in `tenantId` on both planes, including content, proposals, and skill uploads |
+| Control-plane internal token | Identity Service → control plane | `playbook-controlplane-internal` / `token` in the walkthrough | You provision it for both releases | Validating playbook grants before a key is stored. Set `controlplane.internalToken.existingSecret` on Agent Playbooks and `productValidation.products.playbook.credential.existingSecret` on Identity Service. |
+| Data-plane runtime credential | Data plane → Identity Service | `playbook-dp-credential` / `token` in the walkthrough | You provision it for both releases | Checking agent keys for `playbook`. Set `identityService.credential.existingSecret` on Agent Playbooks and register it in `runtime.serviceCredentials[]` as `playbook-dp` on Identity Service. |
+| Identity Service control token | Operator → Identity Service (`:9200`) | `ids-control-token` / `token` in the walkthrough | Supplied through `control.existingSecret` on Identity Service; that chart can also generate one | Creating, listing, rotating, and revoking agent keys |
+
+Keep every credential distinct. The chart refuses to mount one Secret key as two of its credentials, but it can't compare values held in differently named Secrets.
+
+The admin token is a shared recovery credential. It grants no access to other Iris products, and audits identify shared recovery use rather than an individual operator. Prefer [operator OIDC access](#configure-operator-oidc-access) for day-to-day administration and keep the admin token for recovery.
+
+## Load the administrative credentials
+
+Use an account that can read Secrets, with the [port-forwards from Deploy](/content/operate/iris/agent-playbook/self-managed/deploy.md#6-verify-pods-and-health) running:
+
+```bash
+export IRIS_AGENT_PLAYBOOKS_SERVICE_URL='http://localhost:9200'
+export IRIS_AGENT_PLAYBOOKS_URL='http://localhost:9201'
+export IRIS_IDENTITY_URL='http://localhost:9202'
+export IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN="$(kubectl -n get secret \
+ playbook-controlplane-admin-token -o jsonpath='{.data.token}' | base64 --decode)"
+export IRIS_IDENTITY_TOKEN="$(kubectl -n get secret \
+ ids-control-token -o jsonpath='{.data.token}' | base64 --decode)"
+```
+
+The Secret name assumes `fullnameOverride: playbook` and a chart-generated admin token. If you set `controlplane.adminToken.existingSecret`, read that Secret, or load the token from your secret manager. The [API examples](/content/operate/iris/agent-playbook/self-managed/api-examples.md) and the Iris command-line interface (CLI) read these variables.
+
+## Supply the admin token
+
+By default, the chart generates the admin token in a Secret annotated `helm.sh/resource-policy: keep` and reuses its value on each live `helm upgrade`. For GitOps or offline chart rendering, which can't look up the existing value, supply your own Secret so a fresh render doesn't generate a new token:
+
+```yaml
+controlplane:
+ adminToken:
+ existingSecret: playbook-controlplane-admin
+ autoGenerate: false
+```
+
+The same `existingSecret`, `secretKey` (default `token`), `autoGenerate`, and `existingSecretChecksum` settings apply to `controlplane.internalToken`. The data-plane runtime credential has no generator; you always supply it.
+
+## Agent-key grants
+
+Each grant names a tenant, the `playbook` product and resource type, one playbook ID, and its actions:
+
+```json
+{
+ "tenant": "default",
+ "product": "playbook",
+ "resourceType": "playbook",
+ "resourceId": "",
+ "actions": ["read"]
+}
+```
+
+Set `tenant` to the deployment's `tenantId`. The Identity Service fills an omitted tenant with its `runtime.apiKeyTenant.singleTenantID` and rejects grants for another tenant. Before it stores a key, it asks the control plane to confirm that the playbook exists.
+
+| Action | What it allows |
+| --- | --- |
+| `read` | Retrieve published knowledge, list and inspect entry summaries, and read proposals. |
+| `write` | Create entries, append versions, inspect drafts, delete entries, and review proposals. Includes `read`. |
+| `publish` | Publish or withdraw entries and inspect versions. Includes `read`. |
+| `propose` | Create proposals and attach evidence. Includes `read`. |
+
+`write` doesn't include `publish` or `propose`. See [Playbooks](/content/develop/ai/context-engine/agent-playbooks/concepts.md#playbooks) for how developers use these actions. The [key examples](/content/operate/iris/agent-playbook/self-managed/api-examples.md#create-agent-keys) show the complete request. For rotation and revocation, see [Operations](/content/operate/iris/agent-playbook/self-managed/operations.md#rotate-or-revoke-agent-keys).
+
+## Configure operator OIDC access
+
+You can keep the admin token and also accept OIDC access tokens from your identity provider (IdP). The control plane and data plane share one issuer, tenant source, audience, and trusted group mapping. Both validate tokens locally against the IdP's JSON Web Key Set (JWKS); neither calls the Identity Service for this. Agent keys stay enabled.
+
+Add this overlay to `playbook-values.yaml`:
+
+```yaml
+auth:
+ oidc:
+ audience: api://redis-iris
+
+dataplane:
+ oidc:
+ enabled: true
+ issuer: https:///
+ jwksURI: https:///
+ tenantIDClaim:
+ roleClaims:
+ - groups
+ roleMappings:
+ : viewer
+ : operator
+ : product_admin
+
+controlplane:
+ oidc:
+ enabled: true
+```
+
+- `auth.oidc.audience` is the value your IdP puts in the token's `aud` claim. It defaults to `api://redis-iris`, the audience shared by every Iris service; use the same value in every Iris chart. On Entra ID with v2 tokens, use the API's Application (client) ID instead. The chart refuses an empty or wildcard audience.
+- `issuer` is compared with the token's `iss` claim and is never fetched, so it can use `http://`, including under the Federal Information Processing Standards (FIPS) profile. On Active Directory Federation Services (AD FS), set it to the discovery document's `access_token_issuer`, such as `http:///adfs/services/trust`.
+- `jwksURI` is fetched for signing keys, so it must use `https://` unless you set the development-only `allowInsecureTransport: true`. The FIPS profile refuses that setting. Mount a private CA through `tls.caCertSecret` when the IdP uses one, and allow both planes egress to the JWKS endpoint.
+- Set exactly one of `tenantIDClaim` and `staticTenantID`. A resolved or static tenant must equal `tenantId`. Use `staticTenantID` only when the issuer and its mapped groups are confined to this deployment's tenant.
+- `controlplane.oidc.enabled` requires `dataplane.oidc.enabled` and non-empty `roleMappings`.
+
+`roleMappings` defaults to empty. Unmapped claim values grant no access, even when a value matches an Iris role name. Map only trusted human administrator groups, and keep service identities out of them.
+
+The control plane applies these role tiers:
+
+| Role | Control-plane access |
+| --- | --- |
+| `viewer` | List models, and list and read playbooks. |
+| `operator` | Viewer access plus create and update playbooks. |
+| `product_admin`, `suite_admin` | Operator access plus clear or delete playbooks, and list extraction sources and create or enable extraction bindings. |
+
+On the data plane, explicitly mapped `product_admin` and `suite_admin` users receive full Agent Playbooks access within the configured tenant.
+
+The planes cache the JWKS for 10 minutes and allow 5 minutes of clock skew. If a key refresh fails and no cached key validates the token, the request fails with a temporary service error rather than an authentication error. A signed token normally stays usable until it expires. Account for these fixed defaults when you set token lifetimes and retire an IdP signing key.
+
+## OIDC access to agent-key administration
+
+The Identity Service has its own OIDC policy for its control API, configured on the Identity Service release with `controlAuth.oidc` and `controlAuth.roleBindings`. Configure it when operators must manage agent keys without the Identity Service control token. The control token remains available as a deployment-administration credential. See [operator sign-in with your identity provider](/content/operate/iris/identity-service/authentication.md#operator-sign-in-with-your-identity-provider) in the Identity Service guide.
diff --git a/content/operate/iris/agent-playbook/self-managed/configuration.md b/content/operate/iris/agent-playbook/self-managed/configuration.md
new file mode 100644
index 0000000000..7183260d77
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/configuration.md
@@ -0,0 +1,202 @@
+---
+Title: Configure self-managed Agent Playbooks
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Prepare Helm values, the storage and embedding Secrets, Identity Service connection settings, private CA trust, security, and tracing for Agent Playbooks.
+linkTitle: Configuration
+weight: 30
+hideListLinks: true
+---
+
+The chart renders the control-plane and data-plane configuration from Helm values. Storage URLs, provider credentials, the license, and tokens stay in existing Secrets. These examples use release `playbook`, `fullnameOverride: playbook`, tenant `default`, and chart `1.0.0`.
+
+## Storage configuration
+
+Save `playbook-storage.yaml` with the two Redis endpoints:
+
+```yaml
+storage:
+ metadata:
+ urls:
+ - rediss://:@:6379
+ content:
+ urls:
+ - rediss://:@:6379
+```
+
+The control plane and data plane both mount this file. The Identity Service's metadata Redis belongs to the Identity Service release. Save `ids-metadata.yaml` for it, with credentials for its own Redis user:
+
+```yaml
+metadata:
+ urls:
+ - rediss://:@:6379
+```
+
+The [deploy steps](/content/operate/iris/agent-playbook/self-managed/deploy.md#2-create-secrets) put each file in its own Secret.
+
+## Embedding configuration
+
+Put provider endpoints and credentials in `inference.yaml`. Helm values contain only the model identity.
+
+Each key under `embedders_connection_details` names a connection. A model's `provider` in `inference.models` selects the connection with the same name. This example names the connection `openai`, which also lets the [Iris command-line interface (CLI)](/content/operate/iris/agent-playbook/self-managed/api-examples.md#use-the-iris-cli) create playbooks with it. Use the provider and model approved for your deployment.
+
+Save `inference.yaml`:
+
+```yaml
+embedders_connection_details:
+ openai:
+ protocol: openai
+ base_url: https:///v1
+ credentials:
+ type: static
+ api_key:
+ http_client:
+ timeout: 30s
+ max_retry_attempts: 3
+ batching:
+ embeddings:
+ enabled: true
+```
+
+The endpoint and credential reach only the data plane. The control plane receives only the public model list. A connection accepts `protocol` (defaults to the connection name), `base_url`, `azure`, `credentials`, `http_client`, `embedding_input_max_chars`, `embedding_input_fast_truncate`, and `batching.embeddings`. Batching is off unless you enable it.
+
+When you change a connection, keep the vector space it serves. A model or dimension change needs a new playbook.
+
+## Helm values
+
+Save `playbook-values.yaml`:
+
+```yaml
+fullnameOverride: playbook
+tenantId: default
+
+controlplane:
+ image:
+ tag: "1.0.0"
+ internalToken:
+ existingSecret: playbook-controlplane-internal
+
+dataplane:
+ image:
+ tag: "1.0.0"
+ identityServiceBaseURL: https://
+
+identityService:
+ credential:
+ existingSecret: playbook-dp-credential
+
+storage:
+ existingSecret: playbook-storage
+
+license:
+ existingSecret: playbook-license
+
+inference:
+ existingSecret: playbook-inference
+ models:
+ - provider: openai
+ model:
+ dimensions:
+
+tls:
+ caCertSecret: playbook-ca
+
+tests:
+ enabled: true
+```
+
+- `tenantId` must equal `runtime.apiKeyTenant.singleTenantID` on the Identity Service release. Neither chart can check that the two match.
+- `dataplane.identityServiceBaseURL` is the Identity Service release's TLS endpoint. The data plane checks agent keys there.
+- `identityService.credential` is the data plane's runtime credential. Register the same Secret on the Identity Service release.
+- `controlplane.internalToken` is the token the Identity Service presents when it validates grants. Register the same Secret on the Identity Service release.
+- The chart generates the admin token and keeps it across upgrades unless you set `controlplane.adminToken.existingSecret`. See [Credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#credentials).
+- `tls.caCertSecret` names the CA bundle that the planes trust for the Identity Service endpoint and other private endpoints. See [Trust a private CA](#trust-a-private-ca).
+- `tests.enabled` adds the pods that `helm test` runs.
+
+With `fullnameOverride: playbook`, the chart creates the Services `playbook-controlplane` and `playbook-dataplane`. Without it, names start with `-redis-agent-playbook`.
+
+The install fails with a named message when a required value is missing: the image tags, `tenantId`, the storage and license Secrets, at least one model, the Identity Service URL and credential, and a generated or existing Secret for each control-plane token. It also fails when two credentials reference the same Secret key. Keep every credential value distinct, even in differently named Secrets.
+
+For every value and its default, see the [configuration reference](/content/operate/iris/agent-playbook/self-managed/reference.md#configuration-reference), or run:
+
+```bash
+helm show values redis-ai/redis-agent-playbook --version 1.0.0
+```
+
+### Isolated lab without TLS
+
+For a network-isolated lab without the Federal Information Processing Standards (FIPS) profile, you can point the data plane at the in-cluster Identity Service Service instead of a TLS endpoint:
+
+```yaml
+dataplane:
+ identityServiceBaseURL: http://ids-iris-identity-service:9200
+identityService:
+ allowInsecureTransport: true
+ credential:
+ existingSecret: playbook-dp-credential
+```
+
+On the Identity Service release, set `productValidation.products.playbook.baseURL: http://playbook-controlplane:9200`. Tokens travel over plaintext HTTP on these two hops; use TLS for production. The FIPS profile refuses this configuration.
+
+### Identity Service in another namespace
+
+The tested layout puts both releases in one namespace. If the Identity Service runs in another namespace:
+
+- Point `dataplane.identityServiceBaseURL` at its fully qualified Service or TLS endpoint, for example `http://ids-iris-identity-service..svc:9200`.
+- Set its `productValidation.products.playbook.baseURL` to `http://playbook-controlplane..svc:9200`, or to that endpoint's TLS frontend.
+- Provision both shared Secrets with the same values in both namespaces. A pod mounts Secrets only from its own namespace.
+- Allow the Identity Service to reach the control plane on port `9200`, and both planes to reach the Identity Service.
+
+## Trust a private CA
+
+If Redis, the Identity Service endpoint, or another dependency uses a private CA, save the CA certificates as `ca.crt` and create a Secret in the deployment namespace:
+
+```bash
+kubectl -n create secret generic playbook-ca \
+ --from-file=ca.crt=./ca.crt
+```
+
+Set `tls.caCertSecret: playbook-ca` in `playbook-values.yaml`. The chart mounts the CA at `/etc/ssl/custom` in every container, on top of the system CAs. Keep certificate verification enabled.
+
+## Configure security and tracing
+
+Set `security.profile: fips` only with images built for the FIPS profile and with all dependency transport ready:
+
+```yaml
+security:
+ profile: fips
+dataplane:
+ identityServiceBaseURL: https://
+tls:
+ caCertSecret: playbook-ca
+```
+
+Under this profile:
+
+- Storage URLs must use `rediss://`. Both planes check this at startup.
+- `dataplane.identityServiceBaseURL` must be an `https://` endpoint, and the chart refuses `identityService.allowInsecureTransport`.
+- On the Identity Service release, set its own `security.profile` and an `https://` validator URL for `productValidation.products.playbook.baseURL`.
+
+The profile configures the processes. It does not provide TLS termination or establish compliance by itself; the workloads still listen on HTTP.
+
+To export traces from the control plane, data plane, and extraction worker, configure a trusted OpenTelemetry Protocol (OTLP) collector:
+
+```yaml
+tracing:
+ enabled: true
+ otlpGRPCEndpoint: :4317
+ capture: none
+```
+
+The exporter uses plaintext gRPC for the collector hop, so keep the collector on a trusted network. `tracing.capture: received` adds bounded query and returned content to data-plane serving spans; `tracing.capture` doesn't affect the control plane or worker.
+
+## Playbook settings
+
+Select a configured embedding model when you [create a playbook](/content/operate/iris/agent-playbook/self-managed/api-examples.md#create-a-playbook). Use the control plane to update discovery settings and the proposal review policy. When you omit them, a playbook uses FAQ and skill minimum scores of `0.7`, at most 10 results, a review window of 2,592,000 seconds (30 days), and at most 5,000 open proposals.
+
+`storage.maxPlaybooksPerTenant` limits how many playbooks the tenant can hold. The default is `128`.
+
+See the [control-plane API reference](/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md) for fields and limits, and [Retrieval](/content/develop/ai/context-engine/agent-playbooks/retrieval.md) for how applications use these settings.
diff --git a/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md b/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md
new file mode 100644
index 0000000000..7fbeef21b7
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md
@@ -0,0 +1,11 @@
+---
+Title: Agent Playbooks control-plane API reference
+linkTitle: Control-plane API reference
+layout: apireference
+type: page
+weight: 80
+params:
+ sourcefile: ./openapi-control-plane.json
+ sortOperationsAlphabetically: false
+ schemaDefinitionsTagName: Data models
+---
diff --git a/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference/openapi-control-plane.json b/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference/openapi-control-plane.json
new file mode 100644
index 0000000000..acf32d8dee
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference/openapi-control-plane.json
@@ -0,0 +1,4336 @@
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "Redis Agent Playbooks Control Plane API",
+ "version": "1.0.0",
+ "description": "Administrative API for Redis Agent Playbooks provisioning and policy.\n\nOperations and fields marked `x-deployment: cloud` are available on Redis Cloud only. Self-managed deployments don't serve those operations and never return those fields.\n"
+ },
+ "paths": {
+ "/iris/v1/agent-playbooks/databases": {
+ "get": {
+ "description": "Lists account databases using Playbook eligibility. Free plans remain visible even when ineligible or not ready.",
+ "operationId": "ListDatabases",
+ "responses": {
+ "200": {
+ "description": "ListDatabases 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ListDatabasesResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "x-deployment": "cloud"
+ }
+ },
+ "/iris/v1/agent-playbooks/models": {
+ "get": {
+ "description": "Lists models supported by this deployment. On-prem returns the configured embedding allowlist; cloud may also advertise extraction models.",
+ "operationId": "ListModels",
+ "responses": {
+ "200": {
+ "description": "ListModels 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ListModelsResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "models"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/network/info": {
+ "get": {
+ "description": "Returns configured control-plane egress addresses for database allow-listing. Requires operator read authority.",
+ "operationId": "GetNetworkInfo",
+ "responses": {
+ "200": {
+ "description": "GetNetworkInfo 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/GetNetworkInfoResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "x-deployment": "cloud"
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks": {
+ "get": {
+ "description": "Lists the account's Playbooks. If a selected database is unavailable, its Playbook remains listed with state=UNAVAILABLE and without endpoint, database name or accessCidrs enrichment for recognized missing/deleted database or metadata connection failures. Other inventory enrichment failures retain the saved state.",
+ "operationId": "ListPlaybooks",
+ "parameters": [
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Maximum number of Playbooks to return. Defaults to 50.",
+ "schema": {
+ "type": "integer",
+ "default": 50,
+ "maximum": 200,
+ "minimum": 1,
+ "description": "Maximum number of Playbooks to return. Defaults to 50.",
+ "format": "int32"
+ }
+ },
+ {
+ "name": "cursor",
+ "in": "query",
+ "description": "Opaque position from a previous page's nextCursor.",
+ "schema": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Opaque position from a previous page's nextCursor."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "ListPlaybooks 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ListPlaybooksResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ },
+ "post": {
+ "description": "Creates and provisions one Playbook. A deployment-configured per-tenant limit applies; the on-prem default is 128.",
+ "operationId": "CreatePlaybook",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreatePlaybookRequestContent"
+ }
+ }
+ },
+ "required": true
+ },
+ "parameters": [
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "CreatePlaybook 201 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreatePlaybookResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}": {
+ "delete": {
+ "operationId": "DeletePlaybook",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "DeletePlaybook 204 response"
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ },
+ "get": {
+ "description": "Reads one Playbook. A missing or deleted database, or a recognized metadata connection failure, returns saved configuration with state=UNAVAILABLE and without endpoints, databaseBinding.name, or databaseBinding.accessCidrs. This effective read state is not persisted and is not a mutation input. It reports unavailable live database information, not confirmed deletion or a content Redis health probe. Authorization, certificate-verification, cancellation/deadline, malformed-response, and unrelated service errors still fail the request.",
+ "operationId": "GetPlaybook",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "GetPlaybook 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/GetPlaybookResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ },
+ "patch": {
+ "description": "Updates mutable Playbook settings.",
+ "operationId": "UpdatePlaybook",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdatePlaybookRequestContent"
+ }
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "UpdatePlaybook 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdatePlaybookResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}/clear": {
+ "post": {
+ "description": "Administratively clears ALL, ENTRIES or PROPOSALS from a READY Playbook, preserving configuration and index readiness. Requires product_admin or suite_admin. Cleanup is not atomic across content: failures can leave partial progress; retry the same scope after resolving the failure. Without new writes, repeating a successful clear removes no additional entry families.",
+ "operationId": "ClearPlaybook",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ },
+ {
+ "name": "scope",
+ "in": "query",
+ "description": "Content to clear. Required, so an omitted scope never clears everything.",
+ "schema": {
+ "$ref": "#/components/schemas/ClearScope"
+ },
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "ClearPlaybook 204 response"
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "423": {
+ "description": "ResourceSuspendedError 423 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResourceSuspendedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "playbooks"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}/extraction/bindings": {
+ "get": {
+ "operationId": "ListExtractionBindings",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Page size of a list. Defaults to 50 where a service does not say otherwise. A list may\ndocument a smaller maximum, never a larger one.",
+ "schema": {
+ "type": "integer",
+ "default": 50,
+ "maximum": 200,
+ "minimum": 1,
+ "description": "Page size of a list. Defaults to 50 where a service does not say otherwise. A list may\ndocument a smaller maximum, never a larger one.",
+ "format": "int32"
+ }
+ },
+ {
+ "name": "cursor",
+ "in": "query",
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`.",
+ "schema": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "ListExtractionBindings 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ListExtractionBindingsResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ },
+ "post": {
+ "description": "Validates caller management consent, exact same-account Redis Agent Memory source ownership, destination readiness and execution scope synchronously. Success returns ready and enabled=false. Every explicit enable revalidates with the current caller. Pause/delete require destination management only and make no source or grant-administration request. A foreign or missing source is refused without revealing its metadata.",
+ "operationId": "CreateExtractionBinding",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateExtractionBindingRequestContent"
+ }
+ }
+ },
+ "required": true
+ },
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "CreateExtractionBinding 201 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateExtractionBindingResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}/extraction/bindings/{bindingId}": {
+ "delete": {
+ "operationId": "DeleteExtractionBinding",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "bindingId",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "DeleteExtractionBinding 202 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DeleteExtractionBindingResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "412": {
+ "description": "PreconditionFailedError 412 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PreconditionFailedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ },
+ "get": {
+ "operationId": "GetExtractionBinding",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "bindingId",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "GetExtractionBinding 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/GetExtractionBindingResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ },
+ "patch": {
+ "description": "Updates FAQ policy or activation using expectedRevision. Supply job or enabled. Enabling requires the READY state; pause is allowed while extraction is disabled. The deployment gate blocks policy updates and activation. Source identity is immutable; create a replacement binding to change stores. A stale expectedRevision returns 412 /errors/revision-conflict.",
+ "operationId": "UpdateExtractionBinding",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateExtractionBindingRequestContent"
+ }
+ }
+ },
+ "required": true
+ },
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "bindingId",
+ "in": "path",
+ "schema": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "UpdateExtractionBinding 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateExtractionBindingResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "412": {
+ "description": "PreconditionFailedError 412 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PreconditionFailedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}/extraction/stores": {
+ "get": {
+ "description": "Returns tenant-scoped store suggestions, which may be empty. A suggestion does not approve a store. A client may submit another syntactically valid storeId; CreateExtractionBinding checks the caller's access to the store.",
+ "operationId": "ListExtractionStores",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Page size of a list. Defaults to 50 where a service does not say otherwise. A list may\ndocument a smaller maximum, never a larger one.",
+ "schema": {
+ "type": "integer",
+ "default": 50,
+ "maximum": 200,
+ "minimum": 1,
+ "description": "Page size of a list. Defaults to 50 where a service does not say otherwise. A list may\ndocument a smaller maximum, never a larger one.",
+ "format": "int32"
+ }
+ },
+ {
+ "name": "cursor",
+ "in": "query",
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`.",
+ "schema": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "ListExtractionStores 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ListExtractionStoresResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "ConflictError 409 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ConflictErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "extraction"
+ ]
+ }
+ },
+ "/iris/v1/agent-playbooks/playbooks/{playbookId}/model-credentials/{purpose}": {
+ "delete": {
+ "operationId": "DeleteModelCredential",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "purpose",
+ "in": "path",
+ "schema": {
+ "$ref": "#/components/schemas/ModelPurpose"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "DeleteModelCredential 204 response"
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "x-deployment": "cloud"
+ },
+ "get": {
+ "operationId": "GetModelCredential",
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "purpose",
+ "in": "path",
+ "schema": {
+ "$ref": "#/components/schemas/ModelPurpose"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "GetModelCredential 200 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/GetModelCredentialResponseContent"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "x-deployment": "cloud"
+ },
+ "put": {
+ "description": "Creates or rotates the selected customer-funded provider's credential after account/resource authorization. No secret is returned. Each new attempt reloads credentials; in-flight attempts retain their resolved credential until completion or their configured timeout.",
+ "operationId": "PutModelCredential",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PutModelCredentialRequestContent"
+ }
+ }
+ },
+ "required": true
+ },
+ "parameters": [
+ {
+ "name": "playbookId",
+ "in": "path",
+ "description": "Opaque Playbook identifier.",
+ "schema": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "required": true
+ },
+ {
+ "name": "purpose",
+ "in": "path",
+ "schema": {
+ "$ref": "#/components/schemas/ModelPurpose"
+ },
+ "required": true
+ },
+ {
+ "name": "projectId",
+ "in": "query",
+ "description": "The project. Not supported yet; omit it.",
+ "schema": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "The project. Not supported yet; omit it."
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "PutModelCredential 204 response"
+ },
+ "400": {
+ "description": "BadRequestError 400 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/BadRequestErrorResponseContent"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "AuthenticationError 401 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthenticationErrorResponseContent"
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "ForbiddenError 403 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForbiddenErrorResponseContent"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "NotFoundError 404 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotFoundErrorResponseContent"
+ }
+ }
+ }
+ },
+ "408": {
+ "description": "TimeoutError 408 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TimeoutErrorResponseContent"
+ }
+ }
+ }
+ },
+ "424": {
+ "description": "FailedDependencyError 424 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FailedDependencyErrorResponseContent"
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "UnexpectedError 500 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UnexpectedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "501": {
+ "description": "NotImplementedError 501 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/NotImplementedErrorResponseContent"
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "ServiceUnavailableError 503 response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent"
+ }
+ }
+ }
+ }
+ },
+ "x-deployment": "cloud"
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "AuthenticationErrorResponseContent": {
+ "type": "object",
+ "description": "Authentication credentials are missing, malformed, or invalid.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 401,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/AuthenticationErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "AuthenticationErrorType": {
+ "type": "string",
+ "description": "Problem type URI for authentication errors.",
+ "enum": [
+ "/errors/authentication-failed"
+ ]
+ },
+ "BadRequestErrorResponseContent": {
+ "type": "object",
+ "description": "Request validation or input decoding failed.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 400,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/BadRequestErrorType"
+ },
+ "errors": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FieldError"
+ },
+ "description": "Every invalid request member found, when the failure is about members."
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "BadRequestErrorType": {
+ "type": "string",
+ "description": "Problem type URI for bad request errors.",
+ "enum": [
+ "/errors/invalid-data",
+ "/errors/invalid-cursor",
+ "/errors/unknown-request-member",
+ "/errors/invalid-model-config",
+ "/errors/model-config-immutable",
+ "/errors/model-config-not-supported"
+ ]
+ },
+ "ClearScope": {
+ "type": "string",
+ "enum": [
+ "ALL",
+ "ENTRIES",
+ "PROPOSALS"
+ ]
+ },
+ "CloudDatabase": {
+ "type": "object",
+ "description": "Account-owned database metadata. Credentials and Redis URLs are never returned.",
+ "properties": {
+ "databaseId": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "subscriptionId": {
+ "type": "string"
+ },
+ "databaseProvider": {
+ "type": "string"
+ },
+ "databaseRegion": {
+ "type": "string"
+ },
+ "planType": {
+ "type": "string"
+ },
+ "accessCidrs": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "controlPlaneAccessible": {
+ "type": "boolean"
+ },
+ "eligible": {
+ "type": "boolean"
+ },
+ "ready": {
+ "type": "boolean"
+ },
+ "tlsEnabled": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "controlPlaneAccessible",
+ "databaseId",
+ "eligible",
+ "name",
+ "ready"
+ ]
+ },
+ "ConflictErrorResponseContent": {
+ "type": "object",
+ "description": "The request conflicts with the current state of the resource.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 409,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/ConflictErrorType"
+ },
+ "existingId": {
+ "type": "string",
+ "description": "The ID of the existing resource the request collided with, when the conflict names one."
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "ConflictErrorType": {
+ "type": "string",
+ "description": "Problem type URI for conflict errors.",
+ "enum": [
+ "/errors/conflict",
+ "/errors/entry-not-published",
+ "/errors/entry-key-conflict",
+ "/errors/content-limit-exceeded",
+ "/errors/pinned-entry-unavailable",
+ "/errors/proposal-already-exists",
+ "/errors/proposal-evidence-conflict",
+ "/errors/proposal-evidence-capacity",
+ "/errors/proposal-trashed",
+ "/errors/proposal-open",
+ "/errors/proposal-promotion-locked",
+ "/errors/extraction-disabled",
+ "/errors/gateway-mutation-in-progress",
+ "/errors/surface-mutation-in-progress",
+ "/errors/namespace-conflict",
+ "/errors/gateway-not-empty",
+ "/errors/gateway-deleting",
+ "/errors/catalog-publication-conflict",
+ "/errors/summary-view-conflict"
+ ]
+ },
+ "CreateExtractionBindingRequestContent": {
+ "type": "object",
+ "properties": {
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJobConfiguration"
+ }
+ },
+ "required": [
+ "job",
+ "source"
+ ]
+ },
+ "CreateExtractionBindingResponseContent": {
+ "type": "object",
+ "description": "Durable tenant-owned metadata for one Playbook, one Redis Agent Memory store, and one FAQ policy. Creation synchronously validates caller consent and exact Redis Agent Memory source ownership, returning READY and disabled. Every explicit enable revalidates with the current caller. Consent is durable account-owned configuration.",
+ "properties": {
+ "bindingId": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJob"
+ },
+ "state": {
+ "$ref": "#/components/schemas/ExtractionBindingState"
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "Activation intent. Creation is disabled. A separate enable PATCH revalidates current source consent and ownership, and can recover a blocked binding. Pausing clears intent without a Redis Agent Memory request or source permission."
+ },
+ "revision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Optimistic configuration revision, independent of schedules and job runs. Opaque: send it back as expectedRevision."
+ },
+ "blockedReason": {
+ "type": "string",
+ "description": "Machine-readable runtime failure reason, such as source_not_found or source_access_denied. Clients must tolerate unknown reasons."
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "bindingId",
+ "createdAt",
+ "enabled",
+ "job",
+ "playbookId",
+ "revision",
+ "source",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "CreatePlaybookRequestContent": {
+ "type": "object",
+ "properties": {
+ "databaseId": {
+ "type": "string",
+ "pattern": "^[1-9][0-9]*$",
+ "description": "Existing Redis Cloud database ID. Required in Redis Cloud; omitted for self-managed storage."
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "embedding": {
+ "$ref": "#/components/schemas/EmbeddingConfig"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfig"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/ModelSelection"
+ }
+ },
+ "required": [
+ "embedding",
+ "name"
+ ]
+ },
+ "CreatePlaybookResponseContent": {
+ "type": "object",
+ "properties": {
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DataPlaneEndpoint"
+ },
+ "x-deployment": "cloud"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/EffectiveModelSelection"
+ },
+ "databaseBinding": {
+ "$ref": "#/components/schemas/DatabaseBinding"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "state": {
+ "$ref": "#/components/schemas/PlaybookState"
+ },
+ "embedding": {
+ "$ref": "#/components/schemas/EmbeddingConfig"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfig"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "createdAt",
+ "discovery",
+ "embedding",
+ "name",
+ "playbookId",
+ "proposalPolicy",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "DataPlaneEndpoint": {
+ "type": "object",
+ "description": "A public data plane API endpoint and its database network accessibility.",
+ "properties": {
+ "url": {
+ "type": "string"
+ },
+ "provider": {
+ "type": "string"
+ },
+ "region": {
+ "type": "string"
+ },
+ "egressIps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "accessible": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "accessible",
+ "provider",
+ "region",
+ "url"
+ ]
+ },
+ "DatabaseBinding": {
+ "type": "object",
+ "description": "Create-only SM database identity. Connection endpoints and credentials remain internal.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "x-deployment": "cloud"
+ },
+ "accessCidrs": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "x-deployment": "cloud"
+ },
+ "subscriptionId": {
+ "type": "string",
+ "pattern": "^[1-9][0-9]*$"
+ },
+ "databaseId": {
+ "type": "string",
+ "pattern": "^[1-9][0-9]*$"
+ },
+ "provider": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "region": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1
+ }
+ },
+ "required": [
+ "databaseId",
+ "provider",
+ "region",
+ "subscriptionId"
+ ]
+ },
+ "DeleteExtractionBindingResponseContent": {
+ "type": "object",
+ "description": "Durable tenant-owned metadata for one Playbook, one Redis Agent Memory store, and one FAQ policy. Creation synchronously validates caller consent and exact Redis Agent Memory source ownership, returning READY and disabled. Every explicit enable revalidates with the current caller. Consent is durable account-owned configuration.",
+ "properties": {
+ "bindingId": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJob"
+ },
+ "state": {
+ "$ref": "#/components/schemas/ExtractionBindingState"
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "Activation intent. Creation is disabled. A separate enable PATCH revalidates current source consent and ownership, and can recover a blocked binding. Pausing clears intent without a Redis Agent Memory request or source permission."
+ },
+ "revision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Optimistic configuration revision, independent of schedules and job runs. Opaque: send it back as expectedRevision."
+ },
+ "blockedReason": {
+ "type": "string",
+ "description": "Machine-readable runtime failure reason, such as source_not_found or source_access_denied. Clients must tolerate unknown reasons."
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "bindingId",
+ "createdAt",
+ "enabled",
+ "job",
+ "playbookId",
+ "revision",
+ "source",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "DiscoveryConfig": {
+ "type": "object",
+ "description": "Playbook-owned discovery policy.",
+ "properties": {
+ "faqMinimumScore": {
+ "type": "number",
+ "maximum": 1,
+ "minimum": 0,
+ "format": "float"
+ },
+ "skillMinimumScore": {
+ "type": "number",
+ "maximum": 1,
+ "minimum": 0,
+ "format": "float"
+ },
+ "maxResults": {
+ "type": "integer",
+ "maximum": 50,
+ "minimum": 1,
+ "format": "int32"
+ },
+ "previewTokenBudgetEnabled": {
+ "type": "boolean",
+ "default": false,
+ "description": "Enforces previewTokenBudget for REST and MCP discovery when true. Defaults to false on create. Enabling requires a configured budget; disabling retains it. Explicit null is rejected."
+ },
+ "previewTokenBudget": {
+ "type": "integer",
+ "maximum": 2147483647,
+ "minimum": 64,
+ "description": "Saved estimated ceiling on one discovery preview payload, retained while disabled and omitted until configured. Supplying it alone does not enable budgeting. Explicit null is rejected. Estimates use stored o200k_base preview tokens plus fixed allowances; this does not limit the agent's total context window, conversation history, model framing or subsequently fetched Skill content.",
+ "format": "int32"
+ }
+ },
+ "required": [
+ "faqMinimumScore",
+ "maxResults",
+ "skillMinimumScore"
+ ],
+ "default": {
+ "faqMinimumScore": 0.7,
+ "skillMinimumScore": 0.7,
+ "maxResults": 10,
+ "previewTokenBudgetEnabled": false
+ }
+ },
+ "DiscoveryConfigUpdate": {
+ "type": "object",
+ "description": "Partial discovery-policy update. Each omitted field retains its current value; explicit null is rejected. The resulting policy must be valid before saving. Enabling requires a budget supplied here or already stored; disabling retains the saved limit.",
+ "properties": {
+ "faqMinimumScore": {
+ "type": "number",
+ "maximum": 1,
+ "minimum": 0,
+ "format": "float"
+ },
+ "skillMinimumScore": {
+ "type": "number",
+ "maximum": 1,
+ "minimum": 0,
+ "format": "float"
+ },
+ "maxResults": {
+ "type": "integer",
+ "maximum": 50,
+ "minimum": 1,
+ "format": "int32"
+ },
+ "previewTokenBudgetEnabled": {
+ "type": "boolean"
+ },
+ "previewTokenBudget": {
+ "type": "integer",
+ "maximum": 2147483647,
+ "minimum": 64,
+ "description": "Estimated ceiling on one discovery preview payload, using stored o200k_base estimates over compact preview JSON plus fixed allowances. It does not limit the agent's total context window, conversation history, model framing or subsequently fetched Skill content. Zero never means disabled.",
+ "format": "int32"
+ }
+ }
+ },
+ "EffectiveModelSelection": {
+ "type": "object",
+ "properties": {
+ "provider": {
+ "type": "string"
+ },
+ "model": {
+ "type": "string"
+ },
+ "inherited": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "inherited",
+ "model",
+ "provider"
+ ]
+ },
+ "EmbeddingConfig": {
+ "type": "object",
+ "description": "Create-only embedding identity for a Playbook.",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "model": {
+ "type": "string",
+ "maxLength": 256,
+ "minLength": 1
+ },
+ "dimensions": {
+ "type": "integer",
+ "maximum": 4096,
+ "minimum": 1,
+ "format": "int32"
+ }
+ },
+ "required": [
+ "dimensions",
+ "model",
+ "provider"
+ ]
+ },
+ "ExtractionBinding": {
+ "type": "object",
+ "description": "Durable tenant-owned metadata for one Playbook, one Redis Agent Memory store, and one FAQ policy. Creation synchronously validates caller consent and exact Redis Agent Memory source ownership, returning READY and disabled. Every explicit enable revalidates with the current caller. Consent is durable account-owned configuration.",
+ "properties": {
+ "bindingId": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJob"
+ },
+ "state": {
+ "$ref": "#/components/schemas/ExtractionBindingState"
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "Activation intent. Creation is disabled. A separate enable PATCH revalidates current source consent and ownership, and can recover a blocked binding. Pausing clears intent without a Redis Agent Memory request or source permission."
+ },
+ "revision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Optimistic configuration revision, independent of schedules and job runs. Opaque: send it back as expectedRevision."
+ },
+ "blockedReason": {
+ "type": "string",
+ "description": "Machine-readable runtime failure reason, such as source_not_found or source_access_denied. Clients must tolerate unknown reasons."
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "bindingId",
+ "createdAt",
+ "enabled",
+ "job",
+ "playbookId",
+ "revision",
+ "source",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "ExtractionBindingSource": {
+ "type": "object",
+ "description": "Typed Redis Agent Memory store reference. Only REDIS_AGENT_MEMORY with a client-supplied storeId is supported. The source is implicitly whole-store. The control plane verifies source consent and same-account/tenant Redis Agent Memory ownership on create and every explicit enable. Namespace selection is not supported. Credentials are never accepted here. Unknown fields are rejected.",
+ "properties": {
+ "storeId": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "pattern": "^[A-Za-z0-9_-]+$",
+ "description": "A Redis Agent Memory store or namespace ID: letters, digits, `_` and `-`, so minted `st_` store IDs fit."
+ },
+ "kind": {
+ "$ref": "#/components/schemas/ExtractionSourceKind"
+ }
+ },
+ "required": [
+ "kind",
+ "storeId"
+ ]
+ },
+ "ExtractionBindingState": {
+ "type": "string",
+ "enum": [
+ "READY",
+ "BLOCKED",
+ "DELETING"
+ ]
+ },
+ "ExtractionJob": {
+ "type": "object",
+ "properties": {
+ "kind": {
+ "$ref": "#/components/schemas/ExtractionJobKind"
+ },
+ "idleWindowSeconds": {
+ "type": "integer",
+ "maximum": 86400,
+ "minimum": 60,
+ "format": "int32"
+ }
+ },
+ "required": [
+ "idleWindowSeconds",
+ "kind"
+ ]
+ },
+ "ExtractionJobConfiguration": {
+ "type": "object",
+ "description": "One extraction kind and its user-owned policy. Scan cadence is deployment-owned worker configuration and is not accepted in requests or returned on bindings. Omitted idleWindowSeconds defaults to 1800 on create and retains its existing value on update. Idle bounds are 60\u201386400 seconds. Model context and output budgets are deployment-owned worker settings rather than binding fields. Job kind is immutable; changing extraction kind requires a new binding. Policy changes advance the binding revision and do not reset completed-source deduplication.",
+ "properties": {
+ "kind": {
+ "$ref": "#/components/schemas/ExtractionJobKind"
+ },
+ "idleWindowSeconds": {
+ "type": "integer",
+ "maximum": 86400,
+ "minimum": 60,
+ "format": "int32"
+ }
+ },
+ "required": [
+ "kind"
+ ]
+ },
+ "ExtractionJobKind": {
+ "type": "string",
+ "description": "Exactly one extraction job kind. Skill extraction is reserved for future implementation and is currently rejected.",
+ "enum": [
+ "FAQ"
+ ]
+ },
+ "ExtractionSourceKind": {
+ "type": "string",
+ "enum": [
+ "REDIS_AGENT_MEMORY"
+ ]
+ },
+ "ExtractionStore": {
+ "type": "object",
+ "properties": {
+ "storeId": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "pattern": "^[A-Za-z0-9_-]+$",
+ "description": "Optional deployment-configured suggestion; not an approval or verification of this store."
+ }
+ },
+ "required": [
+ "storeId"
+ ]
+ },
+ "FailedDependencyErrorResponseContent": {
+ "type": "object",
+ "description": "A dependent resource required to process the request is unavailable or unhealthy.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 424,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/FailedDependencyErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "FailedDependencyErrorType": {
+ "type": "string",
+ "description": "Problem type URI for failed-dependency errors.",
+ "enum": [
+ "/errors/resource-unavailable",
+ "/errors/database-out-of-memory",
+ "/errors/invalid-model-credentials",
+ "/errors/model-quota-exceeded"
+ ]
+ },
+ "FieldError": {
+ "type": "object",
+ "description": "One invalid request member. A body member is named by `pointer`, a path or query parameter by `parameter`; exactly one of the two is present.",
+ "properties": {
+ "pointer": {
+ "type": "string",
+ "description": "JSON Pointer (RFC 6901) to the invalid body member, such as `/vectorSpace/dimensions`."
+ },
+ "parameter": {
+ "type": "string",
+ "description": "Name of the invalid path or query parameter, such as `limit`."
+ },
+ "detail": {
+ "type": "string",
+ "description": "What is wrong with the member, in fixed words about the rule it broke, never the rejected value."
+ }
+ },
+ "required": [
+ "detail"
+ ]
+ },
+ "ForbiddenErrorResponseContent": {
+ "type": "object",
+ "description": "The caller is authenticated but not allowed to access the requested resource.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 403,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/ForbiddenErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "ForbiddenErrorType": {
+ "type": "string",
+ "description": "Problem type URI for authorization errors.",
+ "enum": [
+ "/errors/insufficient-permissions"
+ ]
+ },
+ "GetExtractionBindingResponseContent": {
+ "type": "object",
+ "description": "Durable tenant-owned metadata for one Playbook, one Redis Agent Memory store, and one FAQ policy. Creation synchronously validates caller consent and exact Redis Agent Memory source ownership, returning READY and disabled. Every explicit enable revalidates with the current caller. Consent is durable account-owned configuration.",
+ "properties": {
+ "bindingId": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJob"
+ },
+ "state": {
+ "$ref": "#/components/schemas/ExtractionBindingState"
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "Activation intent. Creation is disabled. A separate enable PATCH revalidates current source consent and ownership, and can recover a blocked binding. Pausing clears intent without a Redis Agent Memory request or source permission."
+ },
+ "revision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Optimistic configuration revision, independent of schedules and job runs. Opaque: send it back as expectedRevision."
+ },
+ "blockedReason": {
+ "type": "string",
+ "description": "Machine-readable runtime failure reason, such as source_not_found or source_access_denied. Clients must tolerate unknown reasons."
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "bindingId",
+ "createdAt",
+ "enabled",
+ "job",
+ "playbookId",
+ "revision",
+ "source",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "GetModelCredentialResponseContent": {
+ "type": "object",
+ "description": "Safe credential status; never a secret value or secret backend path.",
+ "properties": {
+ "present": {
+ "type": "boolean"
+ },
+ "type": {
+ "type": "string"
+ },
+ "funding": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "funding",
+ "present",
+ "type"
+ ]
+ },
+ "GetNetworkInfoResponseContent": {
+ "type": "object",
+ "description": "The service's egress IP addresses, for allow-listing on the backing database.\nData plane endpoint responses report their own egress addresses separately.",
+ "properties": {
+ "egressIps": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "description": "List of egress IP addresses"
+ }
+ },
+ "required": [
+ "egressIps"
+ ]
+ },
+ "GetPlaybookResponseContent": {
+ "type": "object",
+ "properties": {
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DataPlaneEndpoint"
+ },
+ "x-deployment": "cloud"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/EffectiveModelSelection"
+ },
+ "databaseBinding": {
+ "$ref": "#/components/schemas/DatabaseBinding"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "state": {
+ "$ref": "#/components/schemas/PlaybookState"
+ },
+ "embedding": {
+ "$ref": "#/components/schemas/EmbeddingConfig"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfig"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "createdAt",
+ "discovery",
+ "embedding",
+ "name",
+ "playbookId",
+ "proposalPolicy",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "ListDatabasesResponseContent": {
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/CloudDatabase"
+ }
+ }
+ },
+ "required": [
+ "items"
+ ]
+ },
+ "ListExtractionBindingsResponseContent": {
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExtractionBinding"
+ }
+ },
+ "nextCursor": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`."
+ }
+ },
+ "required": [
+ "items"
+ ]
+ },
+ "ListExtractionStoresResponseContent": {
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ExtractionStore"
+ }
+ },
+ "nextCursor": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Opaque position in a list, returned as `nextCursor` and passed back as `cursor`."
+ }
+ },
+ "required": [
+ "items"
+ ]
+ },
+ "ListModelsResponseContent": {
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/SupportedModel"
+ }
+ }
+ },
+ "required": [
+ "items"
+ ]
+ },
+ "ListPlaybooksResponseContent": {
+ "type": "object",
+ "properties": {
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Playbook"
+ },
+ "description": "The Playbooks, ordered by Playbook ID."
+ },
+ "nextCursor": {
+ "type": "string",
+ "maxLength": 1024,
+ "minLength": 1,
+ "description": "Present when more Playbooks follow; pass it back as cursor."
+ }
+ },
+ "required": [
+ "items"
+ ]
+ },
+ "ModelPurpose": {
+ "type": "string",
+ "enum": [
+ "EMBEDDING",
+ "EXTRACTION"
+ ]
+ },
+ "ModelSelection": {
+ "type": "object",
+ "properties": {
+ "provider": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1
+ },
+ "model": {
+ "type": "string",
+ "maxLength": 256,
+ "minLength": 1
+ }
+ },
+ "required": [
+ "model",
+ "provider"
+ ]
+ },
+ "MutablePlaybookState": {
+ "type": "string",
+ "enum": [
+ "READY",
+ "SUSPENDED"
+ ]
+ },
+ "NotFoundErrorResponseContent": {
+ "type": "object",
+ "description": "The requested resource does not exist.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 404,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/NotFoundErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "NotFoundErrorType": {
+ "type": "string",
+ "description": "Problem type URI for not-found errors.",
+ "enum": [
+ "/errors/resource-not-found",
+ "/errors/gateway-not-found",
+ "/errors/upstream-not-found"
+ ]
+ },
+ "NotImplementedErrorResponseContent": {
+ "type": "object",
+ "description": "The requested capability is recognized but not implemented.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 501,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/NotImplementedErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "NotImplementedErrorType": {
+ "type": "string",
+ "description": "Problem type URI for not-implemented errors.",
+ "enum": [
+ "/errors/not-implemented"
+ ]
+ },
+ "Playbook": {
+ "type": "object",
+ "properties": {
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DataPlaneEndpoint"
+ },
+ "x-deployment": "cloud"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/EffectiveModelSelection"
+ },
+ "databaseBinding": {
+ "$ref": "#/components/schemas/DatabaseBinding"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "state": {
+ "$ref": "#/components/schemas/PlaybookState"
+ },
+ "embedding": {
+ "$ref": "#/components/schemas/EmbeddingConfig"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfig"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "createdAt",
+ "discovery",
+ "embedding",
+ "name",
+ "playbookId",
+ "proposalPolicy",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "PlaybookState": {
+ "type": "string",
+ "description": "Effective read state. Cloud reads can report unavailable when live database metadata cannot be obtained; this state is never persisted and cannot be submitted in a mutation.",
+ "enum": [
+ "PROVISIONING",
+ "READY",
+ "FAILED",
+ "SUSPENDED",
+ "DELETING",
+ "UNAVAILABLE"
+ ]
+ },
+ "PreconditionFailedErrorResponseContent": {
+ "type": "object",
+ "description": "The write named an expected revision (expectedRevision or If-Match) that is no longer current. Read the resource again and retry.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 412,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/PreconditionFailedErrorType"
+ },
+ "currentRevision": {
+ "type": "string",
+ "description": "The resource's current revision, when the service reports it. Read the resource again before retrying; do not send this value back without reading."
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "PreconditionFailedErrorType": {
+ "type": "string",
+ "description": "Problem type URI for a write whose expected revision is no longer current. A write guarded by an If-Match header on an HTTP entity tag uses a different type; see the Identity Service API.",
+ "enum": [
+ "/errors/revision-conflict"
+ ]
+ },
+ "ProposalPolicy": {
+ "type": "object",
+ "description": "Playbook-owned proposal lifecycle and Inbox policy.",
+ "properties": {
+ "reviewWindowSeconds": {
+ "type": "integer",
+ "maximum": 31536000,
+ "minimum": 86400,
+ "format": "int32"
+ },
+ "maxOpenProposals": {
+ "type": "integer",
+ "maximum": 10000,
+ "minimum": 1,
+ "format": "int32"
+ }
+ },
+ "required": [
+ "maxOpenProposals",
+ "reviewWindowSeconds"
+ ],
+ "default": {
+ "reviewWindowSeconds": 2592000,
+ "maxOpenProposals": 5000
+ }
+ },
+ "PutModelCredentialRequestContent": {
+ "type": "object",
+ "properties": {
+ "apiKey": {
+ "type": "string",
+ "maxLength": 8192,
+ "minLength": 1,
+ "format": "password"
+ }
+ },
+ "required": [
+ "apiKey"
+ ]
+ },
+ "ResourceSuspendedErrorResponseContent": {
+ "type": "object",
+ "description": "The requested resource exists but is suspended by an administrator.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 423,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/ResourceSuspendedErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "ResourceSuspendedErrorType": {
+ "type": "string",
+ "description": "Problem type URI for suspended resources.",
+ "enum": [
+ "/errors/resource-suspended"
+ ]
+ },
+ "ServiceUnavailableErrorResponseContent": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 503,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/ServiceUnavailableErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "ServiceUnavailableErrorType": {
+ "type": "string",
+ "enum": [
+ "/errors/service-unavailable",
+ "/errors/playbook-not-ready",
+ "/errors/resource-unavailable"
+ ]
+ },
+ "SupportedModel": {
+ "type": "object",
+ "properties": {
+ "provider": {
+ "type": "string"
+ },
+ "model": {
+ "type": "string"
+ },
+ "purpose": {
+ "$ref": "#/components/schemas/ModelPurpose"
+ },
+ "dimensions": {
+ "type": "integer",
+ "maximum": 4096,
+ "minimum": 1,
+ "format": "int32"
+ },
+ "credentialsRequired": {
+ "type": "boolean"
+ },
+ "funding": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "credentialsRequired",
+ "funding",
+ "model",
+ "provider",
+ "purpose"
+ ]
+ },
+ "TimeoutErrorResponseContent": {
+ "type": "object",
+ "description": "The request timed out before the service could complete it.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 408,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/TimeoutErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "TimeoutErrorType": {
+ "type": "string",
+ "description": "Problem type URI for timeout errors.",
+ "enum": [
+ "/errors/timeout"
+ ]
+ },
+ "UnexpectedErrorResponseContent": {
+ "type": "object",
+ "description": "The service failed with an unexpected internal error.",
+ "properties": {
+ "title": {
+ "type": "string",
+ "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)."
+ },
+ "status": {
+ "type": "integer",
+ "default": 500,
+ "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.",
+ "format": "int32"
+ },
+ "detail": {
+ "type": "string",
+ "description": "A human-readable explanation specific to this occurrence of the problem."
+ },
+ "instance": {
+ "type": "string",
+ "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced."
+ },
+ "type": {
+ "$ref": "#/components/schemas/UnexpectedErrorType"
+ }
+ },
+ "required": [
+ "status",
+ "title",
+ "type"
+ ]
+ },
+ "UnexpectedErrorType": {
+ "type": "string",
+ "description": "Problem type URI for unexpected internal errors.",
+ "enum": [
+ "/errors/unexpected-error",
+ "/errors/content-integrity-failed"
+ ]
+ },
+ "UpdateExtractionBindingRequestContent": {
+ "type": "object",
+ "properties": {
+ "expectedRevision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Resource revision. Opaque: each change to a resource's own configuration writes a\nnew value, and a resource never gets a value it had before. Compare for equality\nonly; its format is the service's, so only its length is constrained. Returned as\n`revision`; sent back as `expectedRevision` to make a write conditional. Omitting\n`expectedRevision` makes the write unconditional."
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJobConfiguration"
+ },
+ "enabled": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "expectedRevision"
+ ]
+ },
+ "UpdateExtractionBindingResponseContent": {
+ "type": "object",
+ "description": "Durable tenant-owned metadata for one Playbook, one Redis Agent Memory store, and one FAQ policy. Creation synchronously validates caller consent and exact Redis Agent Memory source ownership, returning READY and disabled. Every explicit enable revalidates with the current caller. Consent is durable account-owned configuration.",
+ "properties": {
+ "bindingId": {
+ "type": "string",
+ "pattern": "^bind_[0-9a-f]{32}$"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "source": {
+ "$ref": "#/components/schemas/ExtractionBindingSource"
+ },
+ "job": {
+ "$ref": "#/components/schemas/ExtractionJob"
+ },
+ "state": {
+ "$ref": "#/components/schemas/ExtractionBindingState"
+ },
+ "enabled": {
+ "type": "boolean",
+ "description": "Activation intent. Creation is disabled. A separate enable PATCH revalidates current source consent and ownership, and can recover a blocked binding. Pausing clears intent without a Redis Agent Memory request or source permission."
+ },
+ "revision": {
+ "type": "string",
+ "maxLength": 64,
+ "minLength": 1,
+ "description": "Optimistic configuration revision, independent of schedules and job runs. Opaque: send it back as expectedRevision."
+ },
+ "blockedReason": {
+ "type": "string",
+ "description": "Machine-readable runtime failure reason, such as source_not_found or source_access_denied. Clients must tolerate unknown reasons."
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "bindingId",
+ "createdAt",
+ "enabled",
+ "job",
+ "playbookId",
+ "revision",
+ "source",
+ "state",
+ "updatedAt"
+ ]
+ },
+ "UpdatePlaybookRequestContent": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "state": {
+ "$ref": "#/components/schemas/MutablePlaybookState"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfigUpdate"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/ModelSelection"
+ }
+ },
+ "minProperties": 1
+ },
+ "UpdatePlaybookResponseContent": {
+ "type": "object",
+ "properties": {
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/DataPlaneEndpoint"
+ },
+ "x-deployment": "cloud"
+ },
+ "llm": {
+ "$ref": "#/components/schemas/EffectiveModelSelection"
+ },
+ "databaseBinding": {
+ "$ref": "#/components/schemas/DatabaseBinding"
+ },
+ "playbookId": {
+ "type": "string",
+ "pattern": "^pb_[0-9a-f]{32}$",
+ "description": "Opaque Playbook identifier."
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 128,
+ "minLength": 1,
+ "description": "Display name of any API resource."
+ },
+ "state": {
+ "$ref": "#/components/schemas/PlaybookState"
+ },
+ "embedding": {
+ "$ref": "#/components/schemas/EmbeddingConfig"
+ },
+ "discovery": {
+ "$ref": "#/components/schemas/DiscoveryConfig"
+ },
+ "proposalPolicy": {
+ "$ref": "#/components/schemas/ProposalPolicy"
+ },
+ "createdAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ },
+ "updatedAt": {
+ "type": "string",
+ "description": "UTC timestamp resolved to microsecond precision.",
+ "format": "date-time"
+ }
+ },
+ "required": [
+ "createdAt",
+ "discovery",
+ "embedding",
+ "name",
+ "playbookId",
+ "proposalPolicy",
+ "state",
+ "updatedAt"
+ ]
+ }
+ },
+ "securitySchemes": {
+ "smithy.api.httpBearerAuth": {
+ "type": "http",
+ "description": "HTTP Bearer authentication",
+ "scheme": "Bearer"
+ }
+ }
+ },
+ "security": [
+ {
+ "smithy.api.httpBearerAuth": []
+ }
+ ]
+}
diff --git a/content/operate/iris/agent-playbook/self-managed/deploy.md b/content/operate/iris/agent-playbook/self-managed/deploy.md
new file mode 100644
index 0000000000..7f6b1c402f
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/deploy.md
@@ -0,0 +1,190 @@
+---
+Title: Deploy Redis Agent Playbooks
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Install the Identity Service and Redis Agent Playbooks, then create a playbook, mint an agent key, and make one authenticated call.
+linkTitle: Deploy
+weight: 50
+hideListLinks: true
+---
+
+Follow these steps to install the Agent Playbooks control plane and data plane with the `redis-agent-playbook` Helm chart, connect them to an Identity Service release, and end with one authenticated call to the data plane.
+
+Install Identity Service as release `ids`, then Agent Playbooks as release `playbook`, in one namespace. These steps use Agent Playbooks chart `1.0.0` and Identity Service chart `1.2.0`. You create the two credentials both releases share and the Identity Service control token; Agent Playbooks generates its admin token. See [Credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#credentials).
+
+
+Before installing, provide two Transport Layer Security (TLS) endpoints through your hosting environment: one forwarding to `ids-iris-identity-service:9200`, and one forwarding to `playbook-controlplane:9200`. Neither chart terminates TLS. Obtain their certificate authority (CA) certificates as a PEM bundle named `ca.crt`. For a network-isolated lab without TLS, see [Isolated lab without TLS](/content/operate/iris/agent-playbook/self-managed/configuration.md#isolated-lab-without-tls).
+
+If an Identity Service release already serves Redis Agent Memory in this namespace, use it: add the Agent Playbooks entries from [step 3](#3-install-identity-service-first) to its values and upgrade it instead of installing a second release. Both products must use the same tenant.
+
+Before you begin, review the [prerequisites](/content/operate/iris/agent-playbook/self-managed/prerequisites.md).
+
+## 1. Create the namespace
+
+```bash
+kubectl create namespace
+```
+
+## 2. Create Secrets
+
+Prepare `playbook-storage.yaml`, `ids-metadata.yaml`, and `inference.yaml` as shown in [Configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md), and save your license as `license`. Then create the Secrets:
+
+```bash
+kubectl -n create secret generic playbook-storage \
+ --from-file=playbook-storage.yaml=./playbook-storage.yaml
+kubectl -n create secret generic playbook-license \
+ --from-file=license=./license
+kubectl -n create secret generic playbook-inference \
+ --from-file=inference.yaml=./inference.yaml
+kubectl -n create secret generic ids-metadata \
+ --from-file=metadata.yaml=./ids-metadata.yaml
+kubectl -n create secret generic playbook-dp-credential \
+ --from-literal=token="$(openssl rand -hex 32)"
+kubectl -n create secret generic playbook-controlplane-internal \
+ --from-literal=token="$(openssl rand -hex 32)"
+kubectl -n create secret generic ids-control-token \
+ --from-literal=token="$(openssl rand -hex 32)"
+kubectl -n create secret generic playbook-ca \
+ --from-file=ca.crt=./ca.crt
+```
+
+Both releases mount `playbook-dp-credential` and `playbook-controlplane-internal`. You own these Secrets; neither release generates them in this procedure. The runtime credential lets the data plane check agent keys. The internal token lets the Identity Service validate grants against the control plane. The `ids-control-token` Secret is used only by the Identity Service.
+
+## 3. Install Identity Service first
+
+For every Identity Service setting, and for running one release that serves several products, see the [Identity Service guide](/content/operate/iris/identity-service/_index.md).
+
+Save this as `values-ids.yaml`:
+
+```yaml
+metadata:
+ existingSecret: ids-metadata
+control:
+ existingSecret: ids-control-token
+ autoGenerate: false
+runtime:
+ apiKeyTenant:
+ singleTenantID: default
+ serviceCredentials:
+ - name: playbook-dp
+ subject: playbook-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [playbook]
+ existingSecret: playbook-dp-credential
+ secretKey: token
+productValidation:
+ products:
+ playbook:
+ baseURL: https://
+ credential:
+ existingSecret: playbook-controlplane-internal
+ secretKey: token
+tls:
+ caCertSecret: playbook-ca
+```
+
+If the release also serves Agent Memory, keep its `memory-dp` credential, `memory` validator, and `runtime.unscopedGrantsProduct: memory`, and add these `playbook-dp` and `playbook` entries next to them.
+
+```bash
+helm repo add redis-ai https://helm.redis.io/ai
+helm repo update redis-ai
+helm install ids redis-ai/iris-identity-service \
+ --version 1.2.0 \
+ --namespace \
+ -f values-ids.yaml
+```
+
+The Agent Playbooks control plane doesn't exist yet. Configure its endpoint now, but wait until both releases and the TLS routes are ready before you mint keys: the Identity Service calls the control plane to validate each playbook grant.
+
+## 4. Create `playbook-values.yaml`
+
+Write the values file from [Helm values](/content/operate/iris/agent-playbook/self-managed/configuration.md#helm-values), with your embedding model and the Identity Service TLS endpoint.
+
+## Before you install: check your values
+
+Check each value before you install. If one is wrong, you see the symptom in its row.
+
+{{< table-scrollable >}}
+| Check | Symptom | Fix |
+| --- | --- | --- |
+| `controlplane.image.tag` and `dataplane.image.tag` are set | Rendering fails with a named message, or pods `ImagePullBackOff` | Set both tags. |
+| `dataplane.identityServiceBaseURL` is `https://`, or `identityService.allowInsecureTransport` is `true` | Rendering fails | Use the TLS endpoint, or the [lab option](/content/operate/iris/agent-playbook/self-managed/configuration.md#isolated-lab-without-tls). |
+| The admin token, internal token, and runtime credential reference three different Secret keys | Rendering fails | Use distinct Secrets. |
+| `inference.models` lists at least one model | Rendering fails | List each model the deployment offers. |
+| Each model's `provider` names an `embedders_connection_details` entry in `inference.yaml` | Creating a playbook fails, or it doesn't become `READY` | Add the entry under that provider name. |
+| `tenantId` equals the Identity Service's `runtime.apiKeyTenant.singleTenantID` | Minting a key fails, or agent keys get `403` | Set both to the same tenant. |
+| The content Redis has JSON and Search | The data plane isn't ready, or a playbook is `FAILED` | Use a Redis 8 build that includes JSON and Search. |
+{{< /table-scrollable >}}
+
+## 5. Install
+
+```bash
+helm install playbook redis-ai/redis-agent-playbook \
+ --version 1.0.0 \
+ --namespace \
+ -f playbook-values.yaml \
+ --wait --timeout 10m
+```
+
+## 6. Verify pods and health
+
+```bash
+kubectl -n rollout status deployment/playbook-controlplane
+kubectl -n rollout status deployment/playbook-dataplane
+kubectl -n get pods -l app.kubernetes.io/instance=ids
+helm test playbook --namespace --logs
+```
+
+`helm test` checks readiness on both planes and the configured security profile. It doesn't check that the two releases are consistent with each other; the remaining steps do.
+
+Run each port-forward in its own terminal and leave it running:
+
+```bash
+kubectl -n port-forward svc/playbook-controlplane 9200:9200
+```
+
+```bash
+kubectl -n port-forward svc/playbook-dataplane 9201:9201
+```
+
+```bash
+kubectl -n port-forward svc/ids-iris-identity-service 9202:9200
+```
+
+Then check readiness on every service:
+
+```bash
+curl -sS http://localhost:9200/health/readiness
+curl -sS http://localhost:9201/health/readiness
+curl -sS http://localhost:9202/health/readiness
+```
+
+Rerun a port-forward after its pod is replaced.
+
+## 7. Create a playbook
+
+[Load the administrative credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#load-the-administrative-credentials), then follow [Create a playbook](/content/operate/iris/agent-playbook/self-managed/api-examples.md#create-a-playbook). Continue when its state is `READY`.
+
+## 8. Mint an agent key
+
+Mint a key with a grant on the playbook through the Identity Service. See [Create agent keys](/content/operate/iris/agent-playbook/self-managed/api-examples.md#create-agent-keys).
+
+## 9. Make one authenticated call
+
+Check the playbook with the key against the data plane:
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_URL/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/health" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY"
+```
+
+The response reports `READY` for the playbook and for its metadata Redis, content Redis, embedding provider, and license. A `401` means the key is wrong, expired, or revoked. A `403` means it has no grant on the playbook.
+
+## Next steps
+
+- [Publish and retrieve your first FAQ](/content/develop/ai/context-engine/agent-playbooks/quickstart.md).
+- [Operate the deployment](/content/operate/iris/agent-playbook/self-managed/operations.md).
diff --git a/content/operate/iris/agent-playbook/self-managed/extraction.md b/content/operate/iris/agent-playbook/self-managed/extraction.md
new file mode 100644
index 0000000000..72ad193a9b
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/extraction.md
@@ -0,0 +1,255 @@
+---
+Title: Configure background FAQ extraction
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Connect Redis Agent Memory, run the Agent Playbooks extraction worker, and create, enable, pause, and remove extraction bindings.
+linkTitle: Background FAQ extraction
+weight: 85
+hideListLinks: true
+---
+
+Background extraction reads idle Redis Agent Memory sessions and creates frequently asked question (FAQ) proposals for human review. It doesn't publish FAQs or create skills. An accepted proposal still needs review and publication before agents receive it.
+
+Extraction is optional. It needs Redis Agent Memory in the same tenant, a persistent queue Redis, a generation model, and workload identity between the two products. It needs no Identity Service subject grants, lookup credentials, or Identity Service control trust.
+
+## How extraction is wired
+
+| Caller | Calls | Credential | Trust you configure |
+| --- | --- | --- | --- |
+| Agent Playbooks control plane | Redis Agent Memory control plane, to list stores and confirm the source store's tenant | Projected ServiceAccount token, audience `api://memory-cp` | `controlplane.configData.auth.workload_identity` on Redis Agent Memory, role `viewer` |
+| Extraction worker | Redis Agent Memory data plane, to read sessions | Projected ServiceAccount token, audience `api://memory-dp` | `memory.auth.jwt_subjects` on Redis Agent Memory, `authority: static`, `mem-store:*` read |
+| Extraction worker | Agent Playbooks data plane, to search and propose | Projected ServiceAccount token, audience `api://playbook-dp` | Rendered by this chart when the worker is enabled |
+
+With release `playbook`, namespace ``, and `fullnameOverride: playbook`, the two subjects are:
+
+- `system:serviceaccount::playbook-controlplane`
+- `system:serviceaccount::playbook-worker`
+
+If you change the namespace or resource names, change these subjects everywhere.
+
+## Plan the connection
+
+Prepare these values before you enable extraction:
+
+| Value | Purpose |
+| --- | --- |
+| Redis Agent Memory store | The source store for a binding. Its tenant must match `tenantId`. |
+| ServiceAccount issuer and JSON Web Key Set (JWKS) URI | Validate the projected control-plane and worker tokens. Both must use `https://`. The issuer must exactly match the issuer Redis Agent Memory accepts. |
+| Redis Agent Memory control-plane URL | Let the Agent Playbooks control plane discover stores and check ownership. |
+| Redis Agent Memory data-plane URL | Let the worker read sessions. |
+| Queue Redis URL | Store extraction jobs. Use persistence, `noeviction`, and capacity monitoring. Don't reuse the Agent Playbooks metadata or content Redis. |
+| Generation provider and model | Extract and consolidate FAQ candidates. These credentials are separate from the embedding configuration. |
+
+Use certificate-verified endpoints. Redis Agent Memory must be able to fetch the JWKS without a bearer token. See [Prepare worker identity for your platform](/content/operate/iris/agent-memory/self-managed/deploy.md#prepare-worker-identity-for-your-platform) for where each Kubernetes platform serves its issuer. Allow network paths for the control plane, worker, queue Redis, both data planes, and the model provider.
+
+## Configure Redis Agent Memory trust
+
+Add these settings to the Redis Agent Memory values. Merge the list entries with its existing worker identity and authentication settings, and keep `memory.auth.method: agent_key`:
+
+```yaml
+memory:
+ auth:
+ method: agent_key
+ jwt_subjects:
+ - issuer: https://
+ jwks_uri: https://
+ audience: [api://memory-dp]
+ subjects:
+ - subject: system:serviceaccount::playbook-worker
+ authority: static
+ roles: [viewer]
+ resources:
+ "mem-store:*": {permissions: [read]}
+
+controlplane:
+ configData:
+ auth:
+ workload_identity:
+ enabled: true
+ issuer: https://
+ jwks_uri: https://
+ audience: [api://memory-cp]
+ subjects:
+ - subject: system:serviceaccount::playbook-controlplane
+ tenant: default
+ roles: [viewer]
+```
+
+Set `tenant` to the Agent Playbooks `tenantId`. Don't give the control-plane subject a suite administrator role: that bypasses the ownership checks extraction relies on. Upgrade the Redis Agent Memory release, and wait for its planes to be ready.
+
+See the [Redis Agent Memory authentication guide](/content/operate/iris/agent-memory/self-managed/authentication.md) before you change an existing authentication configuration.
+
+
+## Configure Agent Playbooks extraction
+
+Save the private worker configuration as `worker.yaml`:
+
+```yaml
+inference_providers:
+ private-generation:
+ protocol: openai
+ endpoint:
+ base_url: https:///v1
+ generation_api: chat_completions
+ http_client:
+ timeout: 30s
+ max_retry_attempts: 0
+
+worker:
+ redis:
+ urls:
+ - rediss://:@:6379
+ llm:
+ provider: private-generation
+ models:
+ default_chat_model:
+ reasoning_mappings:
+ - model_patterns:
+ -
+ values:
+ low:
+ reasoning_effort: low
+ credentials:
+ type: static
+ api_key:
+```
+
+The reasoning mapping tells the client how to send the worker's `low` reasoning effort to this model. `generation_api` accepts `chat_completions` or `responses`. Don't add `worker.target_token`; the chart supplies the worker's own token for the Agent Playbooks data plane.
+
+Create the Secret:
+
+```bash
+kubectl -n create secret generic playbook-extraction-worker \
+ --from-file=worker.yaml=./worker.yaml
+```
+
+Save `playbook-extraction-values.yaml`:
+
+```yaml
+extraction:
+ enabled: true
+ connection:
+ enabled: true
+ issuer: https://
+ jwksURI: https://
+ ramControlPlaneBaseURL: https://
+
+worker:
+ enabled: true
+ replicaCount: 1
+ region:
+ existingSecret: playbook-extraction-worker
+ sourceURL: https://
+ scanConcurrency: 1
+ extractConcurrency: 1
+```
+
+- `ramControlPlaneBaseURL` is the Redis Agent Memory control plane. `extraction.enabled` requires it.
+- `worker.sourceURL` is the Redis Agent Memory data plane. `worker.targetURL` defaults to this release's data-plane Service; set an `https://` endpoint when the security profile requires it.
+- `worker.region` names the queues, `playbook-extraction::scan` and `playbook-extraction::extract`. Run one active regional deployment per binding inventory.
+- Bindings start disabled, so the worker reads nothing until you [enable a binding](#create-and-enable-a-binding).
+
+Apply both values files:
+
+```bash
+helm upgrade playbook redis-ai/redis-agent-playbook \
+ --version 1.0.0 \
+ --namespace \
+ -f playbook-values.yaml \
+ -f playbook-extraction-values.yaml \
+ --wait --timeout 10m
+kubectl -n rollout status deployment/playbook-worker
+```
+
+Startup fails when the source URL, model, region, or token file is missing, or when the queue Redis is unreachable. Check the worker's `/health/readiness` and `/metrics` on port `9203` before you enable a binding.
+
+## Create and enable a binding
+
+These requests need the admin token or an OpenID Connect (OIDC) token with the `product_admin` or `suite_admin` role. Operators and viewers can't list sources or create or enable bindings. Each playbook has one binding.
+
+List the Redis Agent Memory stores the control plane can see:
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/extraction/stores" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" | jq '.items'
+```
+
+Create a binding for one store:
+
+```bash
+jq -n --arg store '' \
+ '{source: {kind: "REDIS_AGENT_MEMORY", storeId: $store}, job: {kind: "FAQ"}}' \
+ > binding-request.json
+
+curl --fail-with-body -sS \
+ -X POST "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/extraction/bindings" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data-binary @binding-request.json > binding.json
+export BINDING_ID="$(jq -er '.bindingId' binding.json)"
+```
+
+A successful create returns `201` with `state: READY` and `enabled: false`. It confirms that the store exists in your tenant and that the caller may connect it. It doesn't check model access or worker connectivity. Binding IDs start with `bind_`.
+
+Enable the binding with its current `revision`:
+
+```bash
+curl --fail-with-body -sS \
+ "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/extraction/bindings/$BINDING_ID" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" > binding.json
+
+jq '{expectedRevision: .revision, enabled: true}' binding.json > activation.json
+
+curl --fail-with-body -sS \
+ -X PATCH "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/extraction/bindings/$BINDING_ID" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data-binary @activation.json > binding.json
+```
+
+Enabling checks the store and the caller again. A stale `expectedRevision` returns `412`; read the binding again and rebuild `activation.json`. If the check fails, the binding is unchanged. A binding that later fails reports `state: BLOCKED` with a `blockedReason`, such as `source_not_found` or `source_access_denied`.
+
+The Iris command-line interface (CLI) runs the same steps: `iris agent-playbooks extraction bind --enable`, then `extraction list`, `show`, `pause`, `enable`, and `delete`.
+
+The worker looks for due bindings every five minutes (`worker.scanInterval`, default `300s`). A session must stay idle for 30 minutes by default before the worker extracts from it. Set `job.idleWindowSeconds` from 60 to 86,400 when you create or update a binding. Neither setting is an end-to-end freshness guarantee: queue and model time also affect when a proposal appears.
+
+For the first run, send a small session with a known FAQ to the bound store, let it go idle, and review the proposals and evidence in the playbook. A healthy deployment can produce no proposal for a session that has no reusable FAQ.
+
+## Tune the worker
+
+| Value | Default | Purpose |
+| --- | --- | --- |
+| `worker.scanInterval` | `300s` | How often the worker looks for due bindings. Use the same value on every worker that shares a queue, and restart them after a change. Shorter intervals add source-listing load. |
+| `worker.timeout` | `2m` | FAQ strategy timeout. |
+| `worker.reasoningEffort` | `low` | Reasoning effort sent through the model's reasoning mapping. |
+| `worker.maxInputTokens` | `8192` | Input cap for each model request. |
+| `worker.maxCompletionTokens` | `4096` | Output cap for each model request. |
+| `worker.scanConcurrency`, `worker.extractConcurrency` | `1` | Consumers per queue per replica. |
+| `worker.maxPending` | `1000` | Bound on unfinished tasks per queue. |
+
+These settings apply to every binding. Model and credential changes apply to unfinished and new sessions; completed sessions aren't extracted again. Keep the first deployment at one replica and one extraction consumer, and qualify model quality and load before you scale.
+
+## Monitor extraction
+
+Scrape `/metrics` on port `9203` of every worker pod, and alert on sustained queue age, permanent failures, exhausted attempts, lease loss, provider errors, and dispatch staleness. Useful signals include:
+
+- `iris_jobqueue_oldest_pending_seconds`, for backlog. Use `max` across pods, not a sum.
+- `iris_jobqueue_processing_duration_seconds_count{processing_outcome="permanent_failure"}`
+- `iris_playbook_extraction_runs_total{exhausted="true"}`
+- `iris_playbook_extraction_dispatch_last_success_age_seconds`
+
+Four charged failures exhaust a session's attempts. An empty queue doesn't prove that every session was processed.
+
+## Pause or remove extraction
+
+To pause a binding, send `enabled: false` with its current `expectedRevision`. To remove it, send `DELETE` to the binding; the request returns `202`. Both work while Redis Agent Memory is unavailable. Deleting a binding doesn't delete Redis Agent Memory data, proposals, or FAQs.
+
+Work the worker already accepted can still finish after a pause or delete. The worker's static read access lasts until you remove its subject from the Redis Agent Memory values and both data planes roll out.
+
+To stop new extraction configuration while keeping the worker and connection, set `extraction.enabled: false`. Bindings can still be paused and deleted.
+
+To remove extraction from the deployment, delete the bindings first, then set `extraction.enabled`, `extraction.connection.enabled`, and `worker.enabled` to `false` together, and remove both subjects from the Redis Agent Memory values. The chart refuses an enabled connection without the worker unless `extraction.connection.workerSubjects` lists another worker.
diff --git a/content/operate/iris/agent-playbook/self-managed/operations.md b/content/operate/iris/agent-playbook/self-managed/operations.md
new file mode 100644
index 0000000000..0ac59d3236
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/operations.md
@@ -0,0 +1,194 @@
+---
+Title: Operate self-managed Agent Playbooks
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Check health, rotate keys and Secrets, clear, suspend, or delete playbooks, back up storage, and upgrade Agent Playbooks.
+linkTitle: Operations
+weight: 90
+hideListLinks: true
+---
+
+## Check service health
+
+With the [local port-forwards](/content/operate/iris/agent-playbook/self-managed/deploy.md#6-verify-pods-and-health) running:
+
+```bash
+curl --fail-with-body -sS http://localhost:9200/health/readiness
+curl --fail-with-body -sS http://localhost:9201/health/readiness
+curl --fail-with-body -sS http://localhost:9202/health/readiness
+```
+
+Inspect pods and the affected service's logs when readiness fails:
+
+```bash
+kubectl -n get pods -l app.kubernetes.io/instance=playbook
+kubectl -n describe pod
+kubectl -n logs deployment/playbook-dataplane
+```
+
+Redact credentials and content before you share logs or configuration. For common symptoms, see [Troubleshooting](/content/operate/iris/agent-playbook/self-managed/reference.md#troubleshooting).
+
+Scrape `/metrics` on every control-plane and data-plane pod, on ports `9200` and `9201`, and on the [extraction worker](/content/operate/iris/agent-playbook/self-managed/extraction.md#monitor-extraction). Metrics use bounded operation and outcome labels. Agent Playbooks doesn't emit per-entry usage records. All three services can export traces through the shared [tracing configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md#configure-security-and-tracing).
+
+## Rotate or revoke agent keys
+
+Use the Identity Service control token and connection values from [Load the administrative credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#load-the-administrative-credentials).
+
+Rotate a key with a one-hour grace period:
+
+```bash
+umask 077
+curl --fail-with-body -sS \
+ -X POST "$IRIS_IDENTITY_URL/v1/api-keys//rotate?graceSeconds=3600" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" > rotated-key.json
+```
+
+Store the returned token and update its consumers before the grace period ends. The Identity Service caps the grace period with `apiKeys.maxRotateGraceSeconds`, 604,800 seconds (seven days) by default.
+
+Revoke a key:
+
+```bash
+curl --fail-with-body -sS \
+ -X DELETE "$IRIS_IDENTITY_URL/v1/api-keys/" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN"
+```
+
+With the Iris command-line interface (CLI), run `iris identity keys rotate --grace 1h` or `iris identity keys revoke `.
+
+Key validation is cached. The Identity Service release's `runtime.cache.hardTtlSeconds` defaults to 300 seconds. Allow for cached decisions, and verify that the old key is denied before you treat revocation as complete.
+
+## Clear playbook content
+
+Clearing removes entries, proposals, or both, and keeps the playbook and its configuration. It needs the admin token or an OpenID Connect (OIDC) token with the `product_admin` or `suite_admin` role. For example, clear entries:
+
+```bash
+curl --fail-with-body -sS \
+ -X POST "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID/clear?scope=ENTRIES" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN"
+```
+
+Set `scope` to `ENTRIES`, `PROPOSALS`, or `ALL`. The scope is required. A successful clear returns `204`. The playbook must be `READY`.
+
+Clearing isn't atomic across content. After a failure, resolve it and retry the same scope. Clearing doesn't suspend the playbook or stop concurrent writers, including the extraction worker.
+
+With the CLI, run `iris agent-playbooks clear --scope entries`.
+
+## Suspend or remove a playbook
+
+Suspend a playbook to stop runtime access and keep its content and configuration:
+
+```bash
+curl --fail-with-body -sS \
+ -X PATCH "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN" \
+ -H 'Content-Type: application/json' \
+ --data '{"state":"SUSPENDED"}'
+```
+
+Resume it by setting `state` to `READY`.
+
+Deleting a playbook permanently removes its content and configuration. Back up what you need and revoke its agent keys first:
+
+```bash
+curl --fail-with-body -sS \
+ -X DELETE "$IRIS_AGENT_PLAYBOOKS_SERVICE_URL/iris/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID" \
+ -H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_SERVICE_TOKEN"
+```
+
+Deleting needs the same roles as clearing.
+
+## Update configuration, license, and credential Secrets
+
+Update an existing Secret from its source files. For example, update the storage configuration:
+
+```bash
+kubectl -n create secret generic playbook-storage \
+ --from-file=playbook-storage.yaml=./playbook-storage.yaml \
+ --dry-run=client -o yaml | kubectl apply -f -
+```
+
+Calculate the updated Secret payload's checksum:
+
+{{< multitabs id="playbook-storage-checksum" tab1="Linux" tab2="macOS" >}}
+
+```bash
+kubectl -n get secret playbook-storage -o json \
+ | jq -cS '.data' | sha256sum | awk '{print $1}'
+```
+
+-tab-sep-
+
+```bash
+kubectl -n get secret playbook-storage -o json \
+ | jq -cS '.data' | shasum -a 256 | awk '{print $1}'
+```
+
+{{< /multitabs >}}
+
+Copy it into `storage.existingSecretChecksum` in `playbook-values.yaml` and [upgrade the chart](#upgrade-the-chart). A changed checksum rolls only the workloads that consume that Secret. It triggers a rollout; it doesn't validate integrity. If a Secret controller already restarts consumers on rotation, leave the checksum empty. Without a checksum, restart the affected Deployment after you change a Secret in place.
+
+The same pattern applies to these Secrets:
+
+| Secret | Checksum value | Rolls |
+| --- | --- | --- |
+| License | `license.existingSecretChecksum` | Control plane, data plane, and extraction worker |
+| Embedding configuration | `inference.existingSecretChecksum` | Data plane |
+| Private certificate authority (CA) | `tls.caCertSecretChecksum` | Every workload |
+| Admin token | `controlplane.adminToken.existingSecretChecksum` | Control plane and data plane |
+| Internal token | `controlplane.internalToken.existingSecretChecksum` | Control plane |
+| Data-plane runtime credential | `identityService.credential.existingSecretChecksum` | Data plane |
+| Extraction worker configuration | `worker.existingSecretChecksum` | Extraction worker |
+
+Both planes reread the admin-token file on each request, but Kubernetes updates mounted Secrets eventually, so rotation isn't atomic across pods. The internal token and the runtime credential are shared with the Identity Service release: update the Secret, then roll both releases. For immutable Secrets, create a new name and update the reference.
+
+## Back up the deployment
+
+- Back up the metadata Redis, which holds playbook configuration and extraction bindings.
+- Back up the content Redis, which holds entries, proposals, and search indexes.
+- Back up the Identity Service metadata Redis, which holds agent-key records.
+- Keep the values files, configuration files, license material, and secret-manager records you need to recreate the services.
+
+Coordinate metadata and content snapshots. A metadata-only restore can't recover authored content. Validate restore procedures in an isolated environment before you rely on them.
+
+
+
+## Upgrade the chart
+
+Review the target release's configuration and compatibility notes. Keep the control-plane and data-plane image tags on the same release, and recalculate checksums for changed Secrets.
+
+```bash
+helm upgrade playbook redis-ai/redis-agent-playbook \
+ --version \
+ --namespace \
+ -f playbook-values.yaml \
+ --wait --timeout 10m
+```
+
+Include `-f playbook-extraction-values.yaml` when extraction is configured. Then check the rollouts and rerun the chart tests:
+
+```bash
+kubectl -n rollout status deployment/playbook-controlplane
+kubectl -n rollout status deployment/playbook-dataplane
+helm test playbook --namespace --logs
+```
+
+If the worker is enabled, also run `kubectl -n rollout status deployment/playbook-worker`. Reconnect the local port-forwards, then repeat the [application-access check](/content/operate/iris/agent-playbook/self-managed/api-examples.md#verify-application-access). Review release compatibility before a rollback; Helm doesn't restore Redis data.
+
+### Upgrade from earlier charts
+
+- **`0.1.x`**: those charts bundled the Identity Service. `helm upgrade` to `1.0.0` is unsupported. Install a separate Identity Service release that uses the same metadata Redis and key namespace, so existing agent keys keep working, then install `1.0.0` with the connection values. Remove every old `identityService.*` key except `allowInsecureTransport` and `credential`, and remove `storage.identityServiceKey`; the schema rejects them.
+- **Embedding configuration**: the data plane and control plane reject the legacy `inference.models[].client` field. Keep only `provider`, `model`, and `dimensions` in `inference.models`, and move endpoints and credentials into `embedders_connection_details` in the [embedding Secret](/content/operate/iris/agent-playbook/self-managed/configuration.md#embedding-configuration). Keep the same vector-space identity.
+- **OIDC audience**: see [Upgrade with OIDC enabled](/content/operate/iris/agent-playbook/self-managed/authentication.md#upgrade-with-oidc-enabled).
+
+
+
+## Uninstall
+
+```bash
+helm uninstall playbook --namespace
+```
+
+Helm keeps the generated admin-token Secret, which is annotated `helm.sh/resource-policy: keep`. Delete it, the Secrets you created, and the Redis data if you don't plan to reinstall. Uninstalling Agent Playbooks doesn't remove the Identity Service release or its agent-key records.
diff --git a/content/operate/iris/agent-playbook/self-managed/prerequisites.md b/content/operate/iris/agent-playbook/self-managed/prerequisites.md
new file mode 100644
index 0000000000..23d51d2732
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/prerequisites.md
@@ -0,0 +1,104 @@
+---
+Title: Self-managed Agent Playbooks prerequisites
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Review software, Identity Service, Redis, embedding, network, Secret, and image prerequisites for self-managed Agent Playbooks.
+linkTitle: Prerequisites
+weight: 20
+hideListLinks: true
+---
+
+Redis Agent Playbooks is distributed as container images on Docker Hub plus the `redis-agent-playbook` Helm chart in the Redis AI Helm repository. The chart deploys the control plane, the data plane, and the optional extraction worker. Install the `iris-identity-service` chart as its own release before you install Agent Playbooks.
+
+You provide the Identity Service release, the Redis databases, the embedding provider, Kubernetes exposure, and the license.
+
+> [!NOTE]
+> This guide is for system administrators deploying Redis Agent Playbooks on a self-managed
+> Kubernetes cluster.
+
+## What you need
+
+| Requirement | Purpose |
+| --- | --- |
+| Kubernetes cluster and `kubectl` | Run the services and create Secrets in the deployment namespace. |
+| [Helm 3](https://helm.sh/docs/intro/install/) | Install `redis-ai/redis-agent-playbook` and `redis-ai/iris-identity-service` from `https://helm.redis.io/ai`. |
+| Bash, curl, jq, and OpenSSL | Generate tokens and run the administrative API examples. Use a curl version that supports `--fail-with-body`. |
+| License key | Contact your Redis representative or [contact sales](https://redis.io/contact/). An Agent Playbooks license or an Iris suite license that includes Agent Playbooks. |
+| Embedding provider | A provider and model the data plane can reach, with its credentials. |
+| Identity Service | An `iris-identity-service` release, chart `1.2.0` or later, with the Agent Playbooks entries registered. See [Deploy](/content/operate/iris/agent-playbook/self-managed/deploy.md#3-install-identity-service-first). |
+
+
+
+## Deployment decisions
+
+Choose these settings before you create playbooks:
+
+| Decision | What to plan |
+| --- | --- |
+| Tenant | Choose one `tenantId` for the deployment. The Identity Service release's `runtime.apiKeyTenant.singleTenantID` must match it, and agent-key grants name it. |
+| Storage | Provision separate metadata and content Redis deployments. |
+| Embeddings | List each provider, model, and dimension identity the deployment offers. Each playbook selects one when you create it. |
+| API exposure | Keep the control plane and Identity Service private. Expose the data plane to approved applications through your platform's ingress. |
+| Credentials | Provision the two credentials the Identity Service release shares with Agent Playbooks. Let the chart generate the admin token, or supply it. Give applications separate scoped agent keys. |
+| Operator identity | Use the admin token, OpenID Connect (OIDC) access tokens from your identity provider, or both. |
+| Extraction | To propose FAQs from Redis Agent Memory sessions, plan a durable queue Redis, a generation model, workload identity, and network paths between both products. See [Configure background FAQ extraction](/content/operate/iris/agent-playbook/self-managed/extraction.md). |
+
+### Choose embedding models
+
+A playbook's embedding identity (`provider`, `model`, and `dimensions`) can't change after you create it. To change its model or dimensions, create a new playbook and migrate the content. You can offer several identities in one deployment. There is no default; every playbook names one.
+
+Set up the models in [Embedding configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md#embedding-configuration).
+
+### Plan API exposure
+
+The chart creates `ClusterIP` Services. Your platform owns ingress, network policy, and Transport Layer Security (TLS) termination. Neither the Agent Playbooks chart nor the Identity Service chart terminates TLS.
+
+The data-plane Service on port `9201` serves both REST and MCP. To expose MCP, route `/iris/data/v1/agent-playbooks/playbooks/{playbookId}/mcp` to the data-plane Service and keep the complete path, the `Authorization` header, the request body, and the MCP and `Accept` headers. MCP messages use `POST`. The transport is stateless, so an authenticated `GET` or `DELETE` returns `405`.
+
+Exposing a whole Identity Service also exposes its administration routes. Expose only the routes your applications need.
+
+### Plan capacity and recovery
+
+The chart starts one replica of each service and leaves `resources` unset for the control plane and data plane. These defaults are not a production sizing recommendation. Set resource requests and limits, and leave capacity for old and new pods during upgrades.
+
+Plan coordinated storage backups in [Operations](/content/operate/iris/agent-playbook/self-managed/operations.md#back-up-the-deployment).
+
+
+
+## Redis databases
+
+The chart uses existing Redis deployments. It does not provision them.
+
+| Redis deployment | Requirements | Use |
+| --- | --- | --- |
+| Metadata | Core Redis commands and Lua scripting. Also JSON when extraction is enabled. | Playbook configuration and extraction bindings. |
+| Content | JSON and Search, including vector indexes. | Entries, proposals, and retrieval. |
+| Identity Service metadata | Core Redis commands. Configured on the Identity Service release. | Agent-key records. |
+| Extraction queue | Persistence and a `noeviction` policy. Only with extraction. | Extraction jobs. |
+
+Use physically separate deployments for metadata and content. The services reject aliased endpoints, so different database numbers or credentials on the same Redis endpoint don't satisfy this requirement. A Redis 8 build that includes JSON and Search, such as the official `redis:8` image, meets both requirements.
+
+The Identity Service can use the metadata deployment with its own, least-privileged Redis user. Use authenticated, certificate-verified `rediss://` connections for production, and trust the issuing certificate authority (CA).
+
+## Images and network access
+
+The chart requires an explicit image tag for each plane.
+
+| Component | Image |
+| --- | --- |
+| Control plane | `redislabs/iris-agent-playbook-control:1.0.0` |
+| Data plane and extraction worker | `redislabs/iris-agent-playbook-data:1.0.0` |
+| Identity Service | The image that its own chart pins. |
+
+
+
+Allow chart downloads, image pulls, Redis connections, and data-plane access to the embedding provider. The data plane and control plane must reach the Identity Service, and the Identity Service must reach the control plane on port `9200`. For a disconnected installation, mirror the images, use a downloaded chart package, and set the image repositories and `imagePullSecrets` in your Helm values.
+
+## Secrets
+
+Prepare the files and Secrets described in [Configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md). Storage URLs, provider credentials, and license material belong in Secrets, not in Helm values or source control.
+
+For the credentials each release needs, see [Credentials](/content/operate/iris/agent-playbook/self-managed/authentication.md#credentials).
diff --git a/content/operate/iris/agent-playbook/self-managed/reference.md b/content/operate/iris/agent-playbook/self-managed/reference.md
new file mode 100644
index 0000000000..28db44bda1
--- /dev/null
+++ b/content/operate/iris/agent-playbook/self-managed/reference.md
@@ -0,0 +1,75 @@
+---
+Title: Configuration and troubleshooting
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Look up Helm values and resolve common Agent Playbooks deployment problems.
+linkTitle: Configuration and troubleshooting
+weight: 100
+hideListLinks: true
+---
+
+This page is a lookup reference for self-managed Agent Playbooks. It lists the main Helm values with their defaults, and a troubleshooting table that matches common symptoms to their causes and fixes. For how to choose and set these values, see [Configuration](/content/operate/iris/agent-playbook/self-managed/configuration.md).
+
+## Configuration reference
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `tenantId` | None | The one tenant the installation serves. Required. |
+| `auth.oidc.audience` | `api://redis-iris` | The audience both planes accept in operator access tokens. |
+| `security.profile` | `""` | Set `fips` for the Federal Information Processing Standards (FIPS) profile. |
+| `storage.existingSecret` | None | The Secret with `playbook-storage.yaml`. Required. |
+| `storage.playbookKey` | `playbook-storage.yaml` | The key in the storage Secret. |
+| `storage.keyPrefix` | `iris:playbook` | The Redis key prefix. |
+| `storage.maxPlaybooksPerTenant` | `128` | Playbooks the tenant can hold. |
+| `license.existingSecret` | None | The Secret with the license. Required. |
+| `license.secretKey` | `license` | The key in the license Secret. |
+| `inference.models` | None | The embedding identities the deployment offers. Required. |
+| `inference.existingSecret` | None | The Secret with `embedders_connection_details`. Required for a provider other than `noop`. |
+| `inference.secretKey` | `inference.yaml` | The key in the inference Secret. |
+| `controlplane.image.repository` | `redislabs/iris-agent-playbook-control` | The control-plane image. |
+| `dataplane.image.repository` | `redislabs/iris-agent-playbook-data` | The data-plane and worker image. |
+| `controlplane.image.tag`, `dataplane.image.tag` | None | The image tags. Required. |
+| `controlplane.service.port` | `9200` | The control-plane Service port. |
+| `dataplane.service.port` | `9201` | The data-plane Service port, for REST and MCP. |
+| `controlplane.adminToken.autoGenerate` | `true` | Generate the admin token when `existingSecret` is empty. |
+| `controlplane.internalToken.existingSecret` | None | The internal token shared with the Identity Service. |
+| `controlplane.config.existingSecret` | None | Bring your own control-plane configuration instead of the chart's rendering. |
+| `dataplane.identityServiceBaseURL` | None | The Identity Service endpoint. Required. |
+| `identityService.allowInsecureTransport` | `false` | Accept an `http://` Identity Service URL. Refused under FIPS. |
+| `identityService.credential.existingSecret` | None | The data-plane runtime credential. Required. |
+| `dataplane.oidc.enabled`, `controlplane.oidc.enabled` | `false` | Accept operator OpenID Connect (OIDC) tokens. |
+| `tls.caCertSecret` | None | A Secret with extra CA certificates for every container. |
+| `tracing.enabled` | `false` | Send spans to an OpenTelemetry collector. |
+| `tracing.capture` | `none` | Set `received` to capture bounded data-plane content in spans. |
+| `extraction.enabled`, `extraction.connection.enabled` | `false` | Allow extraction bindings and the Redis Agent Memory connection. |
+| `worker.enabled` | `false` | Run the extraction worker. |
+| `worker.port` | `9203` | The worker's health and metrics port. |
+| `tests.enabled` | `false` | Add `helm test` pods. |
+
+`imagePullSecrets`, `security.profile`, and `tls.caCertSecret` fall back to `global.imagePullSecrets`, `global.security.profile`, and `global.tls.caCertSecret` when empty. For worker tuning values, see [Tune the worker](/content/operate/iris/agent-playbook/self-managed/extraction.md#tune-the-worker).
+
+## Troubleshooting
+
+| Symptom | Likely cause | Fix |
+| --- | --- | --- |
+| `helm install` fails with a named message | A required value is missing, or two credentials share a Secret key. | Set the value named in the message, or use distinct Secrets. |
+| `helm install` fails naming `extraction.connection.workerSubjects` | The extraction connection is enabled without the worker. | Enable the worker, or disable the connection. |
+| Pods are `Pending` or `ImagePullBackOff` | Cluster capacity, image tags, registry access, or `imagePullSecrets`. | Check pod events and the image values. |
+| Readiness fails | Redis is unreachable, a Secret key is wrong, or the license is invalid or expired. | Check the service logs. For an unknown certificate authority, [trust the private CA](/content/operate/iris/agent-playbook/self-managed/configuration.md#trust-a-private-ca). |
+| A new playbook stays `PROVISIONING` or becomes `FAILED` | A dependency failed during provisioning, such as a content Redis without JSON and Search. | Check service health and logs, and the [Redis requirements](/content/operate/iris/agent-playbook/self-managed/prerequisites.md#redis-databases). Use an embedding identity from `GET /iris/v1/agent-playbooks/models`. |
+| Minting a key fails | `tenantId` differs from the Identity Service's tenant, the playbook doesn't exist, or the Identity Service can't reach the control plane. | Set both tenants to the same value, check the playbook ID, and check `productValidation.products.playbook`. |
+| An application receives `401` | The key is wrong, expired, rotated, or revoked, or it sent an administrative token. | Send its current agent key. |
+| An application receives `403` | The key has no grant on the playbook, or lacks the action. | Mint a key with the right grant. See [Agent-key grants](/content/operate/iris/agent-playbook/self-managed/authentication.md#agent-key-grants). |
+| Every OIDC token is rejected after an upgrade | The tokens carry the old `api://playbook-dp` audience. | Set `auth.oidc.audience` to match. See [Upgrade with OIDC enabled](/content/operate/iris/agent-playbook/self-managed/authentication.md#upgrade-with-oidc-enabled). |
+| An MCP client can't connect | The ingress drops the path, headers, or body, or the client sends `GET`. | Route the full MCP path to the data plane and use `POST`. |
+| Updating an extraction binding returns `412` | The `expectedRevision` is stale. | Read the binding again and resend with its current `revision`. |
+| An extraction binding is `BLOCKED` | The source store is gone, or the control plane lost access to it. | Read `blockedReason`, fix the store or trust, and enable the binding again. |
+
+## References
+
+- [Data-plane API reference](/content/develop/ai/context-engine/agent-playbooks/api-reference.md)
+- [Control-plane API reference](/content/operate/iris/agent-playbook/self-managed/control-plane-api-reference.md)
+- [Service limits](/content/develop/ai/context-engine/agent-playbooks/limits.md)
diff --git a/content/operate/iris/context-gateway/_index.md b/content/operate/iris/context-gateway/_index.md
index 84c7c731ef..5bcc5a1cd7 100644
--- a/content/operate/iris/context-gateway/_index.md
+++ b/content/operate/iris/context-gateway/_index.md
@@ -24,10 +24,10 @@ Use Redis Context Gateway as a managed service on Redis Cloud.
[Create a Context Gateway](/content/operate/iris/context-gateway/create-gateway.md) and connect an agent, or [view and manage an existing Gateway](/content/operate/iris/context-gateway/manage-gateway.md).
+After setup, use the [developer quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md) to list and call your first tools.
+
### Self-managed
Deploy Redis Context Gateway on Kubernetes to run it on your own infrastructure.
[Start with the self-managed deployment guide](/content/operate/iris/context-gateway/self-managed/_index.md).
-
-After setup, use the [developer quickstart](/content/develop/ai/context-engine/context-gateway/quickstart.md) to list and call your first tools. The [developer guides](/content/develop/ai/context-engine/context-gateway/_index.md) cover Upstream registration, tool policies, and agent integration.
diff --git a/content/operate/iris/context-gateway/self-managed/_index.md b/content/operate/iris/context-gateway/self-managed/_index.md
index a19d2688b2..ad08446e8e 100644
--- a/content/operate/iris/context-gateway/self-managed/_index.md
+++ b/content/operate/iris/context-gateway/self-managed/_index.md
@@ -17,9 +17,7 @@ The `redis-context-gateway` Helm chart deploys one tenant's Context Gateway Cont
Agents call the Data Plane's Model Context Protocol (MCP) endpoint, described in the [MCP API Reference](/content/develop/ai/context-engine/context-gateway/api-reference.md). The [Control Plane API Reference](/content/operate/iris/context-gateway/self-managed/control-plane-api-reference.md) documents the self-managed administration endpoints for Gateways and Upstreams.
-Set the chart version from the approved release. Each chart release pins its matching Control Plane and Data Plane images by default. Use a release that includes the unified Gateway API and GA hardening described in these guides.
-
-
+These guides use `redis-context-gateway` chart `0.2.0`. Each chart release pins its matching Control Plane and Data Plane images by default.
## What you deploy
diff --git a/content/operate/iris/context-gateway/self-managed/authentication.md b/content/operate/iris/context-gateway/self-managed/authentication.md
index c19a985217..55121b94ac 100644
--- a/content/operate/iris/context-gateway/self-managed/authentication.md
+++ b/content/operate/iris/context-gateway/self-managed/authentication.md
@@ -89,11 +89,11 @@ MCP clients then need to sign in again to receive tokens for the new audience.
Grant signed-in users access in either way:
- Map an IdP group to the `gateway_user` role. The role grants `use` on every Gateway in the tenant.
-- Assign Identity Service subject grants to individual users for selected Gateways, with `PUT /v1/subject-grants` on the Identity Service. A subject grant names the IdP's issuer, the user's `user_id_claim` value, and the same product, resource type, Gateway ID, and `use` action as an agent-key grant.
+- Assign Identity Service subject grants to individual users for selected Gateways, with `POST /v1/subject-grants/apply` on the Identity Service. See [subject grants](/content/operate/iris/identity-service/authentication.md#subject-grants) for the request. A subject grant names the IdP's issuer, the user's `user_id_claim` value, and the same product, resource type, Gateway ID, and `use` action as an agent-key grant.
A specific subject grant cannot narrow the all-Gateway role, and removing a subject grant does not remove access that a role gives. To restrict a user to selected Gateways, don't map them to `gateway_user`.
-
+
## Rotate credentials
diff --git a/content/operate/iris/context-gateway/self-managed/deploy.md b/content/operate/iris/context-gateway/self-managed/deploy.md
index eaace5b921..c05eca996d 100644
--- a/content/operate/iris/context-gateway/self-managed/deploy.md
+++ b/content/operate/iris/context-gateway/self-managed/deploy.md
@@ -27,11 +27,13 @@ kubectl create namespace
### Configure the Identity Service release first
+For every Identity Service setting, and for running one release that serves several products, see the [Identity Service guide](/content/operate/iris/identity-service/_index.md).
+
Set these values on the Identity Service release so that it checks Gateway grants and accepts the Data Plane's runtime token:
| Identity Service value | Setting |
| --- | --- |
-| `runtime.serviceCredentials[]` | A credential for the Data Plane with `allowedOperations: [api-key-introspect]` and `allowedProducts: [context-gateway]`, from the same Secret as `dataplane.runtimeToken`. |
+| `runtime.serviceCredentials[]` | A credential for the Data Plane, `name: context-gateway-dp` and `subject: context-gateway-dataplane`, with `allowedOperations: [api-key-introspect]` and `allowedProducts: [context-gateway]`, from the same Secret as `dataplane.runtimeToken`. With Data Plane sign-in on, add `subject-grant-lookup` to `allowedOperations`. |
| `productValidation.products.context-gateway.baseURL` | The Control Plane Service, for example `http://gateway-redis-context-gateway-controlplane:9100`. |
| `productValidation.products.context-gateway.credential` | The same Secret as `controlplane.internalToken`. |
| `productValidation.products.context-gateway.enabled` | `true` |
@@ -138,7 +140,7 @@ Check each value in `gateway-values.yaml` before you install. If one is wrong, y
helm repo add redis-ai https://helm.redis.io/ai
helm repo update redis-ai
helm install gateway redis-ai/redis-context-gateway \
- --version \
+ --version 0.2.0 \
--namespace \
-f gateway-values.yaml \
--wait --timeout 5m
diff --git a/content/operate/iris/context-gateway/self-managed/prerequisites.md b/content/operate/iris/context-gateway/self-managed/prerequisites.md
index 50bf907ec7..0f11801a57 100644
--- a/content/operate/iris/context-gateway/self-managed/prerequisites.md
+++ b/content/operate/iris/context-gateway/self-managed/prerequisites.md
@@ -110,7 +110,7 @@ Redis URLs, tokens, keyrings, and the license belong in Kubernetes Secrets or Se
The chart defaults to these repositories and pins the image tags that match its chart version. Leave `image.repository` and `image.tag` unset for a public install, and override them only to pull from a mirror.
-
+Chart `0.2.0` pins both images to tag `0.1.0`.
## Air-gapped and private registry installs
diff --git a/content/operate/iris/identity-service/_index.md b/content/operate/iris/identity-service/_index.md
new file mode 100644
index 0000000000..6db92eb733
--- /dev/null
+++ b/content/operate/iris/identity-service/_index.md
@@ -0,0 +1,84 @@
+---
+title: Identity Service
+description: Deploy and operate the Identity Service, which issues and checks agent keys for self-managed Redis Iris services.
+linkTitle: Identity Service
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+weight: 29
+hideListLinks: true
+---
+
+The Identity Service issues the agent keys that applications and agents present to self-managed Redis Iris services, and checks those keys for each service's data plane. Every self-managed Iris service connects to it, and one Identity Service release can serve all of them.
+
+This guide is for the platform administrator who installs the Identity Service, registers each service with it, and manages agent keys and operator access.
+
+> [!NOTE]
+> The Identity Service needs no license key of its own. Each Iris service you connect to it needs a license. Contact your Redis representative or
+> [contact sales](https://redis.io/contact/).
+
+## Deployment options
+
+### Redis Cloud
+
+On Redis Cloud, agent keys are managed for you: there is no Identity Service to deploy. Create each service's agent keys in the Redis Cloud console.
+
+### Self-managed
+
+Deploy the Identity Service on Kubernetes to run it on your own infrastructure, before or alongside the services that use it.
+
+[Start with the deployment guide](/content/operate/iris/identity-service/deploy.md).
+
+## Which services use it
+
+Each of these services' self-managed guides installs the Identity Service as a separate release before the service:
+
+| Service | `product` in grants | `resourceType` in grants | Guide |
+| --- | --- | --- | --- |
+| Agent Memory | `memory` | `mem-store` | [Self-managed Agent Memory](/content/operate/iris/agent-memory/self-managed/_index.md) |
+| Agent Playbooks | `playbook` | `playbook` | [Self-managed Agent Playbooks](/content/operate/iris/agent-playbook/self-managed/_index.md) |
+| Context Gateway | `context-gateway` | `gateway` | [Self-managed Context Gateway](/content/operate/iris/context-gateway/self-managed/_index.md) |
+| Intent Router | `intent` | `intent-router` | [Self-managed Intent Router](/content/operate/iris/intent-router/self-managed/_index.md) |
+| Lens | `lens` | `lens-instance` | [Self-managed Lens](/content/operate/iris/lens/self-managed/_index.md) |
+
+If you already run an Identity Service release for one service, register the next service on that release instead of installing a second one. See [Register services](/content/operate/iris/identity-service/configuration.md#register-services).
+
+## What you deploy
+
+The `iris-identity-service` Helm chart deploys one Deployment and one ClusterIP Service on port `9200`. The guides install it as release `ids`, so its Service is `ids-iris-identity-service`.
+
+| Component | Purpose | Provided by |
+| --- | --- | --- |
+| Identity Service | Issues, lists, rotates, and revokes agent keys, and checks them for the service data planes. | The chart |
+| Control token Secret | The rescue credential for the Identity Service control API. | The chart generates it, or you supply it |
+| Metadata Redis | Stores the hashed agent keys, their grants, and subject grants. | You |
+| Runtime credentials and internal tokens | Shared Secrets between the Identity Service and each service. | You |
+
+The chart deploys no Redis, no service, no Ingress, and no NetworkPolicy. The Identity Service has no TLS listener: terminate Transport Layer Security (TLS) in your ingress, service mesh, or load balancer.
+
+## How it fits with the services
+
+The Identity Service listens on one port and serves three groups of routes. Each group accepts a different credential, sent as `Authorization: Bearer `.
+
+| Route group | Routes | Caller | Credential |
+| --- | --- | --- | --- |
+| Control | `/v1/api-keys`, `/v1/products`, `/v1/subject-grants` | Operators and automation | The control token, or an operator's identity provider (IdP) access token |
+| Runtime | `/v1/auth/*` | Service data planes | The service's runtime credential |
+| Operational | `/health/liveness`, `/health/readiness` | Kubernetes probes and monitoring | None |
+
+1. An operator creates a resource in a service's control plane, such as an Agent Memory store or a Router in Intent Router.
+1. The operator mints an agent key for that resource through the Identity Service control API.
+1. Before it stores the key, the Identity Service asks the service's control plane to confirm that the resource exists and that the actions are valid. This step is called grant validation. It uses the control plane's internal token.
+1. The Identity Service returns the key once. It stores only a hash of the key.
+1. The agent sends the key to the service's data plane. The data plane checks it with the Identity Service, using its runtime credential, and caches the answer.
+
+The Identity Service keeps no service data.
+
+## Pages in this guide
+
+- [Deploy](/content/operate/iris/identity-service/deploy.md): prerequisites, install, and verification.
+- [Configuration](/content/operate/iris/identity-service/configuration.md): the metadata Redis, the tenant, service registration, and the other Helm values.
+- [Authentication and authorization](/content/operate/iris/identity-service/authentication.md): credentials, roles, operator sign-in with your IdP, and subject grants.
+- [Operations](/content/operate/iris/identity-service/operations.md): the agent-key lifecycle, credential rotation, upgrades, backups, and troubleshooting.
diff --git a/content/operate/iris/identity-service/authentication.md b/content/operate/iris/identity-service/authentication.md
new file mode 100644
index 0000000000..6a2f784b73
--- /dev/null
+++ b/content/operate/iris/identity-service/authentication.md
@@ -0,0 +1,213 @@
+---
+Title: Authentication and authorization
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Understand the Identity Service credentials and roles, let operators sign in with your identity provider, and give IdP users subject grants.
+linkTitle: Authentication and authorization
+weight: 60
+hideListLinks: true
+---
+
+The Identity Service uses separate credentials for each job: operators manage agent keys through its control API, service planes call its runtime API, and agents present agent keys to service data planes. This page lists each credential and the roles on the control API. It then shows how to let operators sign in with your identity provider (IdP) and how to give IdP users access with subject grants.
+
+## Credentials
+
+| Credential | Who presents it to whom | Secret / key | What it unlocks |
+| --- | --- | --- | --- |
+| Control token | Operator → Identity Service control API (`:9200`) | `control.existingSecret` / `token`, or the generated `-iris-identity-service-control-token` | Every control operation: create, list, update, rotate, and revoke agent keys, and manage subject grants. |
+| Operator access token | Operator → Identity Service control API | None. Issued by your IdP | The control operations of the operator's roles, from `controlAuth.roleBindings`. |
+| Workload token | Kubernetes workload → Identity Service control API | None. A projected service account token | Subject grant operations only, from `controlAuth.workloadIdentity`. |
+| Runtime credential | Service data plane → Identity Service runtime API | The shared Secret in a `runtime.serviceCredentials[]` entry | Checking agent keys, and reading subject grants when allowed, for the entry's services. |
+| Internal token | Identity Service → service control plane | The shared Secret in `productValidation.products..credential` | Grant validation: confirming that a resource exists before a key is stored. |
+| Agent key | Agent → service data plane | None. Returned once when minted or rotated | The resources and actions its grants name. |
+
+Each credential needs its own value. The Identity Service doesn't start when two credentials have the same value, and the chart refuses to render when two reference the same Secret key.
+
+The control token is a shared secret, and the audit log can't name a person for it. Keep it for setup and recovery, and let operators sign in with your IdP for daily work.
+
+## Agent keys and grants
+
+An agent key looks like `iris_.`. The Identity Service returns the full key only in the response to a mint or a rotation, and stores only a SHA-256 hash of it. If you lose a key, rotate it or mint a new one.
+
+Each key carries one or more grants:
+
+| Grant field | Meaning | Example |
+| --- | --- | --- |
+| `tenant` | The installation's tenant. If you omit it, the Identity Service adds `runtime.apiKeyTenant.singleTenantID`. | `default` |
+| `product` | The Iris service. | `memory` |
+| `resourceType` | The type of resource in that service. | `mem-store` |
+| `resourceId` | One resource. Wildcards aren't accepted. | `` |
+| `actions` | What the key can do with the resource. | `["read", "write"]` |
+
+| Service | `product` | `resourceType` | Actions |
+| --- | --- | --- | --- |
+| Agent Memory | `memory` | `mem-store` | `read`; `write` (includes `read`); `full` (includes `write`) |
+| Agent Playbooks | `playbook` | `playbook` | `read`; `write`, `publish`, and `propose` (each includes `read`); `full` (includes all) |
+| Context Gateway | `context-gateway` | `gateway` | `use`; `full` (includes `use`) |
+| Intent Router | `intent` | `intent-router` | `read`; `write` (includes `read`); `full` (includes `write`) |
+| Lens | `lens` | `lens-instance` | `ingest` and `read`, independent of each other; `full` (includes both) |
+
+All the grants of one key use the same tenant. Each service's authentication page explains what its actions allow. To mint and manage keys, see [Manage agent keys](/content/operate/iris/identity-service/operations.md#manage-agent-keys).
+
+## Roles on the control API
+
+| Caller | How it gets the role | What it can do |
+| --- | --- | --- |
+| Control token | It holds the token | Every operation. |
+| `suite_admin` | A role binding with `scope: global` | Every operation for every service, in its own tenant only. |
+| `product_admin` | A role binding with `scope: product` and a `product` | Every operation for that service, in its own tenant only. |
+| `subject_grant_admin` | A workload identity subject | Subject grant operations only, in its own tenant. |
+| `deployment_admin` | A role binding with `scope: deployment` and an `issuer` | Support work across tenants: list, read, and revoke keys, and list and delete subject grants. It can't create, update, or rotate keys, or add grants. An installation with one tenant doesn't need it. |
+| Any other caller | None | Nothing. The request gets `403`. |
+
+The service control-plane roles, such as `operator` and `viewer`, give no access to the Identity Service control API. An operator who must mint keys needs `suite_admin` or `product_admin` here, in addition to their role on the service's control plane.
+
+If one of an operator's roles is `deployment_admin`, that operator can't create, update, or rotate keys, also in their own tenant and also when they have another role. Give `deployment_admin` only to people who don't need those operations.
+
+## Operator sign-in with your identity provider
+
+Operators can call the control API with an access token from your IdP, using OpenID Connect (OIDC). The audit log then names each operator, and you can grant access by IdP group. The control token keeps working.
+
+### 1. Register Iris in your IdP
+
+1. Register one API for the whole Iris suite with one audience, for example `api://redis-iris`. On Microsoft Entra ID v2, the audience is the API's application (client) ID. Use the same audience that the service control planes accept.
+1. Create groups or app roles for key administrators, for example `iris-suite-admins` and `memory-admins`, and assign operators to them.
+1. Make sure the group or role values reach the access token. On Entra ID, prefer app roles: raw `groups` claims arrive as IDs and are dropped for users in many groups. On Okta, add a groups claim with a filter.
+1. Restrict the application to the assigned groups. On Entra ID, set **User assignment required** to **Yes**.
+
+### 2. Configure `controlAuth`
+
+Add these values to `values-ids.yaml`:
+
+```yaml
+controlAuth:
+ oidc:
+ enabled: true
+ issuer: https:///
+ jwks_uri: https:///
+ audience: [api://redis-iris]
+ roleBindings:
+ - {claim_value: iris-suite-admins, scope: global, role: suite_admin}
+ - {claim_value: memory-admins, scope: product, product: memory, role: product_admin}
+```
+
+- The fields under `oidc` use snake_case, because the chart copies them into the service configuration as written.
+- `issuer` must equal the token's `iss` claim exactly, including its scheme. The Identity Service never fetches it. On Active Directory Federation Services (AD FS), use the discovery document's `access_token_issuer`.
+- `jwks_uri`, the JSON Web Key Set (JWKS) URI, must use `https://`. The pod must reach it and trust its CA. See [TLS, FIPS, and network](/content/operate/iris/identity-service/configuration.md#tls-fips-and-network).
+- Role bindings match the values of the `roles` and `groups` claims by default. Set `role_claims` under `oidc` to read other claims. A `claim_value` matches without regard to letter case.
+- With `runtime.apiKeyTenant.singleTenantID` set, the chart adds the tenant for you. Rendering fails if you also set `tenant_id_claim` or a different `static_tenant_id`.
+- The control API refuses `allow_unmapped_roles`. Use `roleBindings` for every role.
+
+### 3. Apply and check
+
+1. Run `helm upgrade ids redis-ai/iris-identity-service --version 1.2.0 -n -f values-ids.yaml`.
+1. Get an access token for an operator from your IdP.
+1. Call the control API with it:
+
+ ```bash
+ curl -sS -o /dev/null -w '%{http_code}\n' \
+ -H "Authorization: Bearer " \
+ "$IRIS_IDENTITY_URL/v1/api-keys"
+ ```
+
+| Status | Meaning |
+| --- | --- |
+| `200` | The token is valid and a role binding matches. |
+| `401` | The issuer, audience, or signature is wrong, or the token expired. Compare the token's `iss` and `aud` claims with `controlAuth.oidc`. |
+| `403` | The token is valid, but no role binding matches its groups, or the role doesn't cover this operation or service. |
+| `503` | The Identity Service can't reach the JWKS URI. The control token still works. |
+
+The `iris` command-line interface (CLI) accepts an operator access token in `IRIS_IDENTITY_TOKEN` in place of the control token.
+
+### Remove a role binding
+
+To revoke a binding that gives too much access, add a [policy overlay](/content/operate/iris/identity-service/configuration.md#configuration-overlays) Secret with the same binding and `role: none`, then change `secrets.checksum` and run `helm upgrade`.
+
+## Subject grants
+
+A subject grant gives an IdP user or workload access to a service resource without an agent key. The service's data plane checks the user's token itself, then asks the Identity Service for the grants of that subject. The Identity Service never sees the user's token.
+
+Context Gateway reads subject grants for users who sign in with your IdP. Agent Memory and Agent Playbooks read them only for service subjects. Lens and Intent Router don't use them.
+
+To give IdP users access to a Context Gateway:
+
+1. Add `subject-grant-lookup` to the data plane's runtime credential:
+
+ ```yaml
+ runtime:
+ serviceCredentials:
+ - name: context-gateway-dp
+ subject: context-gateway-dataplane
+ allowedOperations: [api-key-introspect, subject-grant-lookup]
+ allowedProducts: [context-gateway]
+ existingSecret: gateway-runtime
+ secretKey: token
+ ```
+
+1. Allow the grant shape:
+
+ ```yaml
+ subjectGrants:
+ allowed:
+ - {product: context-gateway, resourceType: gateway, actions: [use]}
+ ```
+
+1. Run `helm upgrade` for the Identity Service release.
+1. Give the grant to the user. The `subject` is the value of the user's `sub` claim, or of the claim that the data plane reads as the user ID:
+
+ ```bash
+ curl -sS -X POST "$IRIS_IDENTITY_URL/v1/subject-grants/apply" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "issuer": "https:///",
+ "subject": "",
+ "product": "context-gateway",
+ "grants": {"gateway": {"": {"actions": ["use"]}}}
+ }'
+ ```
+
+ The control token must send `issuer`. An operator who signs in with the IdP can omit it, and the Identity Service uses the issuer of the operator's token.
+
+1. To remove the grant, send the same request with `"": null`. The data plane can keep using its cached grants for up to `runtime.cache.hardTtlSeconds`.
+
+The issuer must equal the user token's `iss` claim exactly. Don't use an email address as the subject, because a user can change it.
+
+These resource types accept subject grants:
+
+| `resourceType` | Allowed actions |
+| --- | --- |
+| `mem-store` | `read`, `write`, `full`, `read_all_owners` |
+| `playbook` | `read`, `propose` |
+| `gateway` | `use`, `full` |
+
+If you remove a shape from `subjectGrants.allowed`, the Identity Service stops returning grants of that shape after its next restart. It doesn't delete them.
+
+## Workload identity
+
+A Kubernetes workload can manage subject grants with its own projected service account token instead of the control token:
+
+```yaml
+controlAuth:
+ workloadIdentity:
+ enabled: true
+ issuer:
+ jwks_uri:
+ audience: []
+ subjects:
+ - subject: system:serviceaccount::
+ roles: [subject_grant_admin]
+```
+
+Take the issuer and the JWKS URI from the cluster's `/.well-known/openid-configuration`. A subject can't get `suite_admin`. A subject without a `tenant` gets `runtime.apiKeyTenant.singleTenantID`.
+
+Agent Playbooks extraction from Agent Memory needs no workload identity on the Identity Service.
+
+## Recover from a lockout
+
+- **Your IdP is down, or the role bindings are wrong.** Use the control token. It always works.
+- **You lost the control token, and the chart generated it.** Delete its Secret, if it still exists, and run `helm upgrade`. The chart generates a new token. If you supply the token with `control.existingSecret`, put a new value in your Secret. The Identity Service reads the token file on each request, so the new value works after Kubernetes updates the mounted file, in about a minute.
+- **You lost the metadata Redis.** Restore it from your backup. See [Back up and restore](/content/operate/iris/identity-service/operations.md#back-up-and-restore).
diff --git a/content/operate/iris/identity-service/configuration.md b/content/operate/iris/identity-service/configuration.md
new file mode 100644
index 0000000000..7a5f4ccc52
--- /dev/null
+++ b/content/operate/iris/identity-service/configuration.md
@@ -0,0 +1,222 @@
+---
+Title: Configure the Identity Service
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Configure the Identity Service metadata Redis, tenant, service registration, agent-key settings, and TLS.
+linkTitle: Configuration
+weight: 30
+hideListLinks: true
+---
+
+You configure the Identity Service with the Helm values of its own release, in `values-ids.yaml`. No service chart reads these values or checks them against its own, so keep the Secret names, Service addresses, and tenant consistent across releases yourself.
+
+The Identity Service reads its configuration only when it starts. A changed value rolls the pod at `helm upgrade`. A changed Secret that you own doesn't roll the pod unless you also change its checksum value. See [Rotate credentials](/content/operate/iris/identity-service/operations.md#rotate-credentials).
+
+To see every value and its default, run:
+
+```bash
+helm show values redis-ai/iris-identity-service --version 1.2.0
+```
+
+## Metadata Redis
+
+The metadata Redis holds the hashed agent keys, their grants, and subject grants. If you lose it, every agent loses access.
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `metadata.existingSecret` | `""` | Required. The Secret that holds the metadata Redis connection. |
+| `metadata.secretKey` | `metadata.yaml` | The key in that Secret. |
+| `metadata.existingSecretChecksum` | `""` | Optional. Change it to roll the pod after you edit the Secret. |
+
+The Secret's key holds a configuration fragment:
+
+```yaml
+metadata:
+ urls: ["rediss://:@:"]
+```
+
+- The Identity Service always uses database 0. It ignores a `/` index in the URL.
+- Don't change the host after the first install. The Identity Service then reads an empty database, and every key stops working. To move the data, follow [Move the metadata Redis](/content/operate/iris/identity-service/operations.md#move-the-metadata-redis).
+- Turn on persistence (append-only file or RDB snapshots) and keep the data directory on durable storage. Without persistence, a Redis restart deletes every key.
+
+## Control token
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `control.existingSecret` | `""` | Your own Secret with the control token. |
+| `control.secretKey` | `token` | The key in that Secret. |
+| `control.autoGenerate` | `true` | Generate `-iris-identity-service-control-token` when `existingSecret` is empty. |
+| `control.existingSecretChecksum` | `""` | Optional. Change it to roll the pod after you edit your Secret. |
+
+The control token always works, also when operator sign-in is on. Give only a small group access to its Secret. For what it can do, see [Credentials](/content/operate/iris/identity-service/authentication.md#credentials).
+
+For GitOps tools such as Argo CD or Flux, supply the control token with `control.existingSecret`. These tools render the chart without cluster access, so a generated token changes on every render.
+
+## Tenant
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `runtime.apiKeyTenant.singleTenantID` | `""` | The one tenant of the installation, for example `default`. |
+
+Set `singleTenantID` to the same value as the `tenantId` of every service release. The Identity Service adds this tenant to each grant that names no tenant, and rejects a grant that names another tenant with `400`.
+
+A tenant ID is 1 to 256 characters, without `|` or control characters. Matching is exact and case-sensitive. For a numeric ID, quote it in YAML or set it with `--set-string`, so Helm keeps it as a string. You can't change the tenant after you mint keys: keys, grants, and service data keep the old ID.
+
+
+
+## Register services
+
+Each service needs two entries on the Identity Service release:
+
+- A runtime credential in `runtime.serviceCredentials`, so the service's data plane can check agent keys.
+- A grant validator in `productValidation.products.`, so the Identity Service can check the service's resources before it stores a grant.
+
+This table lists the entries for each service, with the release names and Secret names used in the associated deployment guide:
+
+{{< table-scrollable >}}
+| Service | `serviceCredentials` `name` and `subject` | `allowedProducts` | Validator key | Validator `baseURL` | Runtime credential Secret | Internal token Secret |
+| --- | --- | --- | --- | --- | --- | --- |
+| Agent Memory | `memory-dp` | `[memory]` | `memory` | `http://redis-agent-memory-controlplane:9100` | `memory-dp-credential` | `memory-internal-token` |
+| Agent Playbooks | `playbook-dp` | `[playbook]` | `playbook` | `http://playbook-controlplane:9200` | `playbook-dp-credential` | `playbook-controlplane-internal` |
+| Context Gateway | `context-gateway-dp`, subject `context-gateway-dataplane` | `[context-gateway]` | `context-gateway` | `http://gateway-redis-context-gateway-controlplane:9100` | `gateway-runtime` | `gateway-grant-validation` |
+| Intent Router | `intent-dp` | `[intent]` | `intent` | `http://intent-redis-intent-router-controlplane:9400` | `intent-dp-credential` | `intent-controlplane-internal` |
+| Lens | `lens-dataplane` | `[lens]` | `lens` | `http://lens-redis-lens-controlplane:9300` | `lens-dp-credential` | `lens-internal-token` |
+{{< /table-scrollable >}}
+
+The runtime credential Secret is the same Secret that the service's data plane mounts, and the internal token Secret is the same Secret that its control plane mounts. If you install a service under another release name or `fullnameOverride`, change the validator address to match. For the service-side values, see each service's deploy guide.
+
+### Serve several services from one release
+
+One release serves every service. Write all entries in one values file. Helm replaces lists instead of merging them, so each `helm upgrade` must restate every `serviceCredentials` entry, not only the new one.
+
+This example serves Agent Memory and Intent Router:
+
+```yaml
+runtime:
+ unscopedGrantsProduct: memory
+ apiKeyTenant:
+ singleTenantID: default
+ serviceCredentials:
+ - name: memory-dp
+ subject: memory-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [memory]
+ existingSecret: memory-dp-credential
+ secretKey: token
+ - name: intent-dp
+ subject: intent-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [intent]
+ existingSecret: intent-dp-credential
+ secretKey: token
+productValidation:
+ products:
+ memory:
+ baseURL: http://redis-agent-memory-controlplane:9100
+ credential:
+ existingSecret: memory-internal-token
+ secretKey: token
+ intent:
+ enabled: true
+ baseURL: http://intent-redis-intent-router-controlplane:9400
+ credential:
+ existingSecret: intent-controlplane-internal
+ secretKey: token
+```
+
+To add a service to a running release:
+
+1. Install the service, or note its control-plane Service and Secret names.
+1. Add the service's runtime credential and validator to `values-ids.yaml`, next to the existing entries.
+1. Run `helm upgrade ids redis-ai/iris-identity-service --version 1.2.0 -n -f values-ids.yaml`.
+1. Check that `GET /v1/products` lists the new service.
+
+Every service on one release uses the same tenant.
+
+### Runtime credential fields
+
+| Field | Meaning |
+| --- | --- |
+| `name` | Required. Unique, 1 to 44 lowercase letters, digits, and dashes, with no trailing dash. It also names the mount directory. |
+| `subject` | Required. The identity the data plane authenticates as. |
+| `allowedOperations` | Required. One or more of the operations in the next table. |
+| `allowedProducts` | Required. The services whose keys this credential may check. |
+| `existingSecret`, `secretKey` | The shared Secret and its key (default `token`). |
+| `existingSecretChecksum` | Optional. Change it to roll the pod after you edit the Secret. |
+| `autoGenerate`, `generatedSecretName` | For development only. The chart generates the token instead of reading your Secret. |
+
+| Operation | Use |
+| --- | --- |
+| `api-key-introspect` | Check an agent key. Every data plane needs it. |
+| `subject-grant-lookup` | Read subject grants. Context Gateway needs it when IdP sign-in for agents is on. See [Subject grants](/content/operate/iris/identity-service/authentication.md#subject-grants). |
+| `auth-me` | Let the caller check its own credential. |
+| `auth-introspect` | An earlier delegated token check. Don't use it for new installations. |
+
+### Grant validator fields
+
+| Field | Meaning |
+| --- | --- |
+| `enabled` | Default `true`. A disabled entry renders nothing. |
+| `baseURL` | Required. An absolute `http://` or `https://` URL of the service's control plane, with no user information, query, or fragment. |
+| `credential.existingSecret`, `credential.secretKey` | Required. The control plane's internal token Secret and its key (default `token`). |
+| `credential.existingSecretChecksum` | Optional. Change it to roll the pod after you edit the Secret. |
+
+The Identity Service calls the validator with a 5-second timeout and doesn't follow redirects. If the control plane doesn't answer, minting fails with `424`.
+
+`runtime.unscopedGrantsProduct` names the service that owns grants stored before grants carried a service. Set it to `memory` when the release serves Agent Memory. When set, it must name an enabled validator.
+
+## Agent keys and the key cache
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `apiKeys.maxRotateGraceSeconds` | `604800` (7 days) | The longest time an old key can stay valid after a rotation. |
+| `apiKeys.userBinding.enabled` | `false` | Lets a mint bind a key to a user with `userId`. Agent Memory uses it for owner isolation. |
+| `runtime.cache.softTtlSeconds` | `180` | When a data plane refreshes a cached key check. Must not exceed `hardTtlSeconds`. |
+| `runtime.cache.hardTtlSeconds` | `300` | The longest time a data plane uses a cached key check. A revoked key can keep working for up to this time. |
+
+## Operator sign-in and subject grants
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `controlAuth.oidc` | Not set | Operator sign-in to the control API with access tokens from your identity provider (IdP). |
+| `controlAuth.roleBindings` | Not set | Maps IdP group or role claims to Identity Service roles. Requires `controlAuth.oidc.enabled`. |
+| `controlAuth.workloadIdentity` | `{}` | Lets a Kubernetes workload call the control API with its service account token. |
+| `subjectGrants.allowed` | `[]` | The grant shapes that subject grants may have. Empty allows none. |
+
+See [Authentication and authorization](/content/operate/iris/identity-service/authentication.md) for how to set them.
+
+## TLS, FIPS, and network
+
+- **Private certificate authority (CA).** To reach a `rediss://` metadata Redis, an `https://` validator, or an IdP signed by a private CA, put the PEM bundle in a Secret and set `tls.caCertSecret`. The key defaults to `ca.crt` (`tls.caCertKey`). The Identity Service trusts the bundle in addition to the system CAs. The chart has no option to skip certificate verification.
+
+ ```bash
+ kubectl -n create secret generic ids-ca --from-file=ca.crt=./ca.crt
+ ```
+
+- **Federal Information Processing Standards (FIPS).** Set `security.profile: fips`. The Identity Service then refuses to start unless the metadata Redis URL is `rediss://` and every validator `baseURL` is `https://`.
+- **Network.** The chart deploys no NetworkPolicy and no Ingress. Let only the service planes, your operators, and your automation reach port `9200`. The health routes need no credential, so don't expose them outside the cluster.
+- **Another namespace.** If the Identity Service runs in another namespace than a service, use fully qualified Service names, such as `http://redis-agent-memory-controlplane..svc:9100`, and create each shared Secret in both namespaces with the same value.
+
+## Availability and resources
+
+| Value | Default | Meaning |
+| --- | --- | --- |
+| `replicaCount` | `1` | Identity Service replicas. The service keeps its state in the metadata Redis. |
+| `resources` | Requests `100m` CPU and `128Mi` memory; limits `500m` CPU and `512Mi` memory | Container resources. |
+| `nodeSelector`, `affinity`, `tolerations` | Empty | Pod scheduling. |
+| `image.repository`, `image.tag` | `redislabs/iris-identity-service`, the chart version | Set them to pull from a private registry. |
+| `imagePullSecrets` | `[]` | Pull Secrets for a private registry. |
+
+
+
+Readiness checks the metadata Redis, and liveness doesn't. When the metadata Redis is unreachable, the pod turns unready and stops receiving traffic, but Kubernetes doesn't restart it. Readiness doesn't check the service control planes, so one service's outage doesn't take the Identity Service out of service.
+
+## Configuration overlays
+
+- **`configData`** adds Identity Service settings that have no Helm value. The chart owns the credential, service, tenant, cache, and key settings, and refuses credential wiring in `configData`. Set operator policy either in `controlAuth` or in `configData.auth`, never both.
+- **Policy overlays** are Secrets that hold more configuration, such as role bindings, named by `secrets.secretName` and `secrets.additionalSecrets`. Each Secret holds the overlay under the key `overlay.yaml` (`secrets.overlayKey`). The Identity Service loads them in order, after the metadata Secret. An overlay can't change the control token, the runtime credentials, or the validators. Change `secrets.checksum` to roll the pod after you edit an overlay Secret.
+
+Role bindings in overlays merge by issuer, claim value, scope, and service. A later binding replaces a matching one, and a binding with `role: none` removes it.
diff --git a/content/operate/iris/identity-service/deploy.md b/content/operate/iris/identity-service/deploy.md
new file mode 100644
index 0000000000..fb435f1667
--- /dev/null
+++ b/content/operate/iris/identity-service/deploy.md
@@ -0,0 +1,185 @@
+---
+Title: Deploy the Identity Service
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Install the Identity Service as its own Helm release, register a service with it, and check that it answers.
+linkTitle: Deploy
+weight: 50
+hideListLinks: true
+---
+
+Follow these steps to install the Identity Service with the `iris-identity-service` Helm chart, register your first Iris service with it, and check that its control API accepts your control token.
+
+The examples install chart `1.2.0` as release `ids` in the same namespace as the services, so the Service is `ids-iris-identity-service:9200`. They register Agent Memory. For the other services, swap in their entries from [Register services](/content/operate/iris/identity-service/configuration.md#register-services).
+
+
+
+## Prerequisites
+
+| Requirement | Details |
+| --- | --- |
+| Kubernetes | A cluster and a namespace for the release. The tested layout puts the Identity Service in the same namespace as the services, because they share Secrets. |
+| Helm | Helm 3, with the Redis AI repository `https://helm.redis.io/ai`. |
+| Image | `redislabs/iris-identity-service` from Docker Hub, or a copy in your private registry. By default, the chart deploys the image tag that matches its version. |
+| Metadata Redis | A Redis database for the Identity Service. Turn on persistence (append-only file or RDB snapshots) and keep its data on durable storage. It holds every agent key, so back it up. See [Metadata Redis](/content/operate/iris/identity-service/configuration.md#metadata-redis). |
+| Tenant | One tenant ID for the installation, for example `default`. Every service release sets the same value as its `tenantId`. You can't change it later. |
+| Service details | For each service you register: its control-plane Service address, its control-plane internal token Secret, and its data-plane runtime credential Secret. Each service's deploy guide names them. |
+| Transport Layer Security (TLS) | The Identity Service has no TLS listener. For production, put a TLS endpoint in front of it and of each service control plane. |
+
+## 1. Create the namespace
+
+Skip this step if the services' namespace already exists.
+
+```bash
+kubectl create namespace
+```
+
+## 2. Create the metadata Secret
+
+1. Save the metadata Redis connection as `ids-metadata.yaml`. Use `rediss://` for TLS, and put the Redis user and password in the URL:
+
+ ```yaml
+ metadata:
+ urls: ["rediss://:@:"]
+ ```
+
+1. Create the Secret. The key must be `metadata.yaml`:
+
+ ```bash
+ kubectl -n create secret generic ids-metadata \
+ --from-file=metadata.yaml=./ids-metadata.yaml
+ ```
+
+## 3. Create the control token and shared Secrets
+
+1. Create the control token Secret. Only the Identity Service mounts it:
+
+ ```bash
+ kubectl -n create secret generic ids-control-token \
+ --from-literal=token="$(openssl rand -hex 32)"
+ ```
+
+ To let the chart generate the token instead, skip this step and omit `control` from the values file. The chart then creates `ids-iris-identity-service-control-token` and keeps it across upgrades and uninstalls.
+
+1. Create the service's data-plane runtime credential. The data plane and the Identity Service both mount it:
+
+ ```bash
+ kubectl -n create secret generic memory-dp-credential \
+ --from-literal=token="$(openssl rand -hex 32)"
+ ```
+
+1. Create the service's control-plane internal token. The control plane and the Identity Service both mount it:
+
+ ```bash
+ kubectl -n create secret generic memory-internal-token \
+ --from-literal=token="$(openssl rand -hex 32)"
+ ```
+
+Every credential needs its own value. The Identity Service doesn't start when two credentials have the same value. If you already followed a service's deploy guide, these Secrets exist: reuse them.
+
+## 4. Create `values-ids.yaml`
+
+Save this file. It registers Agent Memory over the in-cluster Service. For production, use the control plane's TLS endpoint and set `tls.caCertSecret`, as described in [TLS, Federal Information Processing Standards (FIPS), and network](/content/operate/iris/identity-service/configuration.md#tls-fips-and-network).
+
+```yaml
+metadata:
+ existingSecret: ids-metadata
+control:
+ existingSecret: ids-control-token
+ autoGenerate: false
+runtime:
+ unscopedGrantsProduct: memory
+ apiKeyTenant:
+ singleTenantID: default
+ serviceCredentials:
+ - name: memory-dp
+ subject: memory-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [memory]
+ existingSecret: memory-dp-credential
+ secretKey: token
+productValidation:
+ products:
+ memory:
+ baseURL: http://redis-agent-memory-controlplane:9100
+ credential:
+ existingSecret: memory-internal-token
+ secretKey: token
+```
+
+`runtime.unscopedGrantsProduct: memory` is for Agent Memory only. Omit it when the release doesn't serve Agent Memory.
+
+## Before you install: check your values
+
+The chart's values schema is closed: an unknown key, service, or operation fails the install. Check each value before you install. If one is wrong, you see the symptom in its row.
+
+{{< table-scrollable >}}
+| Check | Symptom | Fix |
+| --- | --- | --- |
+| `metadata.existingSecret` is set | Rendering fails | Name the metadata Secret. |
+| `runtime.serviceCredentials` has at least one entry | Rendering fails | Add an entry for each service data plane. |
+| `productValidation.products` has at least one enabled service | Rendering fails | Add a validator for each service control plane. |
+| The control token, runtime credentials, and internal tokens use different Secret keys and different values | Rendering fails, or the pod doesn't start | Create a separate Secret for each. |
+| `runtime.apiKeyTenant.singleTenantID` equals each service's `tenantId` | Minting a key fails with `400`, or agents get `403` | Set the same tenant in every release. |
+| A numeric tenant ID is a string | Rendering fails, or the tenant doesn't match | Quote it in YAML, or use `--set-string`. |
+{{< /table-scrollable >}}
+
+## 5. Install
+
+```bash
+helm repo add redis-ai https://helm.redis.io/ai
+helm repo update redis-ai
+helm install ids redis-ai/iris-identity-service \
+ --version 1.2.0 \
+ --namespace \
+ -f values-ids.yaml
+```
+
+The service's control plane can be missing at this point. The Identity Service starts without it, but minting a key for that service fails until the control plane answers grant validation.
+
+## 6. Verify the release
+
+1. Wait for the Deployment:
+
+ ```bash
+ kubectl -n rollout status deployment/ids-iris-identity-service
+ ```
+
+1. Run the chart test. It checks that the Identity Service is ready, which means it reaches the metadata Redis:
+
+ ```bash
+ helm test ids --namespace
+ ```
+
+1. In a separate terminal, forward the Service port and leave it running:
+
+ ```bash
+ kubectl -n port-forward svc/ids-iris-identity-service 9200:9200
+ ```
+
+1. Load the control token:
+
+ ```bash
+ export IRIS_IDENTITY_URL='http://localhost:9200'
+ export IRIS_IDENTITY_TOKEN="$(kubectl -n get secret \
+ ids-control-token -o jsonpath='{.data.token}' | base64 --decode)"
+ ```
+
+ If the chart generated the token, read `ids-iris-identity-service-control-token` instead. `helm status ids -n ` prints the command for your release.
+
+1. List the registered services. The response names each service that has a grant validator:
+
+ ```bash
+ curl -sS -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" "$IRIS_IDENTITY_URL/v1/products"
+ ```
+
+A passing `helm test` doesn't prove that the release can mint keys. Minting needs the service's control plane. After you install the service, mint a key as its deploy guide shows, or as described in [Mint an agent key](/content/operate/iris/identity-service/operations.md#mint-an-agent-key).
+
+## Next steps
+
+- Install the service and connect its data plane to `http://ids-iris-identity-service:9200`, or to the Identity Service's TLS endpoint.
+- [Register more services](/content/operate/iris/identity-service/configuration.md#register-services) on the same release.
+- [Let operators sign in with your identity provider](/content/operate/iris/identity-service/authentication.md#operator-sign-in-with-your-identity-provider), so they don't share the control token.
diff --git a/content/operate/iris/identity-service/operations.md b/content/operate/iris/identity-service/operations.md
new file mode 100644
index 0000000000..1e6049b86f
--- /dev/null
+++ b/content/operate/iris/identity-service/operations.md
@@ -0,0 +1,287 @@
+---
+Title: Operate the Identity Service
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Mint, list, rotate, and revoke agent keys, rotate credentials, audit changes, upgrade, back up, and troubleshoot the Identity Service.
+linkTitle: Operations
+weight: 90
+hideListLinks: true
+---
+
+This page covers the daily work on an Identity Service release: managing agent keys for every service, rotating credentials, and finding who changed what. It also covers upgrades, backups of the metadata Redis, uninstalling, and troubleshooting.
+
+The examples use release `ids` and a port-forward to its Service:
+
+```bash
+kubectl -n port-forward svc/ids-iris-identity-service 9200:9200
+```
+
+```bash
+export IRIS_IDENTITY_URL='http://localhost:9200'
+export IRIS_IDENTITY_TOKEN=''
+```
+
+When operator sign-in is on, use your own access token instead of the control token, so the audit log names you. See [Operator sign-in](/content/operate/iris/identity-service/authentication.md#operator-sign-in-with-your-identity-provider).
+
+## Check health
+
+The health routes need no credential:
+
+```bash
+curl -sS "$IRIS_IDENTITY_URL/health/readiness"
+```
+
+Readiness returns `503` while the Identity Service can't reach the metadata Redis. `helm test ids -n ` runs the same check in the cluster.
+
+## Manage agent keys
+
+The control API manages the keys of every service. The `iris` command-line interface (CLI) reads `IRIS_IDENTITY_URL` and `IRIS_IDENTITY_TOKEN`. To set it up, see [Set up on a self-managed deployment](/content/develop/ai/context-engine/sdk-and-cli.md#set-up-on-a-self-managed-deployment).
+
+### Mint an agent key
+
+Find the resource ID in the service's control plane first, for example an Agent Memory store ID. Then mint the key:
+
+```bash
+curl -sS -X POST "$IRIS_IDENTITY_URL/v1/api-keys" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "name": "support-agent",
+ "grants": [{
+ "tenant": "default",
+ "product": "memory",
+ "resourceType": "mem-store",
+ "resourceId": "",
+ "actions": ["read", "write"]
+ }]
+ }'
+```
+
+The response returns `keyId` and `token`. The `token` is the agent key, and it's shown only once: give it to the agent through your secret store, and record only the `keyId`.
+
+Optional fields:
+
+- `expiresAt`: when the key stops working, in Unix seconds. Omitted or `0` means never.
+- `userId`: the user that owns the key. It needs `apiKeys.userBinding.enabled: true`.
+
+For the grant of each service, see [Agent keys and grants](/content/operate/iris/identity-service/authentication.md#agent-keys-and-grants). With the CLI, each service's own command mints its keys, because it knows the grant the service needs. For example, `iris intent-router service key` mints a key for a Router.
+
+Before the Identity Service stores the key, it asks the service's control plane to validate the grant. A `400` means the resource doesn't exist in the tenant or an action isn't valid. A `424` means the Identity Service can't reach the control plane or its internal token is wrong.
+
+### List and inspect keys
+
+```bash
+curl -sS -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ "$IRIS_IDENTITY_URL/v1/api-keys?product=memory&resourceId="
+curl -sS -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ "$IRIS_IDENTITY_URL/v1/api-keys/"
+```
+
+With the CLI:
+
+```bash
+iris identity keys list --product memory --resource-id
+iris identity keys show
+```
+
+`iris identity keys list` also filters by `--resource-type`. Neither the API nor the CLI ever returns a key's token after it's minted.
+
+The list is paginated. Over HTTP, pass `maxResults` and then each response's `nextToken`. The CLI takes `--limit`, and `--cursor` with the `nextCursor` value it prints; `--all` reads every page.
+
+### Update, rotate, or revoke a key
+
+```bash
+# Change the grants, the name, or expiresAt. The token stays the same.
+curl -sS -X PATCH "$IRIS_IDENTITY_URL/v1/api-keys/" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ -d '{"grants": [{"product": "memory", "resourceType": "mem-store", "resourceId": "", "actions": ["read"]}]}'
+```
+
+```bash
+# Rotate: get a new key; the old one keeps working for graceSeconds.
+curl -sS -X POST "$IRIS_IDENTITY_URL/v1/api-keys//rotate?graceSeconds=3600" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN"
+```
+
+```bash
+# Revoke: delete the key.
+curl -sS -X DELETE "$IRIS_IDENTITY_URL/v1/api-keys/" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN"
+```
+
+With the CLI:
+
+```bash
+iris identity keys rotate --grace 1h --write .env --env
+iris identity keys revoke
+```
+
+`rotate` writes the new key to the dotenv file with mode `0600` and never prints it. `revoke` asks for confirmation unless you pass `--yes`, and `--product ` refuses keys that grant another service.
+
+| Operation | Use it when | What happens to the token | When the agent notices |
+| --- | --- | --- | --- |
+| Update | The agent needs other resources or actions, a new name, or a new expiry. | It doesn't change. | After the data plane's cache refreshes, within `runtime.cache.hardTtlSeconds` (300 seconds by default). |
+| Rotate | Someone else might know the token, or your rotation schedule is due. | You get a new `keyId` and token with the same grants. The old token works for `graceSeconds` more (default 3600, at most `apiKeys.maxRotateGraceSeconds`), but never after its own `expiresAt`. The response's `oldExpiresAt` says when it stops. | The agent must switch to the new token before `oldExpiresAt`. |
+| Revoke | Someone else has the token, or the agent no longer needs access. | The key is deleted. A second revoke returns `404`. | Within `runtime.cache.hardTtlSeconds`. |
+
+## Rotate credentials
+
+The Identity Service reads the control token, the runtime credentials, and the internal tokens from their mounted files on each request. A changed Secret takes effect after Kubernetes updates the mounted file, in about a minute, without a restart. While the files update, some calls can fail.
+
+| Credential | How to rotate |
+| --- | --- |
+| Control token | Put a new value in your Secret. For a generated token, delete its Secret and run `helm upgrade`. |
+| Runtime credential | Update the Secret that the Identity Service and the data plane share, then change `existingSecretChecksum` on both releases and run `helm upgrade` on both. To avoid failed calls, follow [Rotate a runtime credential without failed calls](#rotate-a-runtime-credential-without-failed-calls). |
+| Internal token | Update the Secret that the Identity Service and the control plane share, then change `productValidation.products..credential.existingSecretChecksum` and the service's matching checksum, and run `helm upgrade` on both. |
+| Policy overlays | The Identity Service reads them only at startup. Change `secrets.checksum` and run `helm upgrade`. |
+| Metadata Redis credential | Follow [Rotate the metadata Redis credential](#rotate-the-metadata-redis-credential). |
+| Agent key | [Rotate it](#update-rotate-or-revoke-a-key) through the control API. |
+
+Make every new value unique. The Identity Service doesn't start when two credentials have the same value.
+
+### Rotate a runtime credential without failed calls
+
+The Identity Service accepts more than one entry for the same `subject`, so it can accept the old and the new value for a while. This example rotates the Agent Memory credential:
+
+1. Create a Secret with a new value:
+
+ ```bash
+ kubectl -n create secret generic memory-dp-credential-v2 \
+ --from-literal=token="$(openssl rand -hex 32)"
+ ```
+
+1. Add a second entry with the same `subject` and a new `name`, and keep the old entry:
+
+ ```yaml
+ runtime:
+ serviceCredentials:
+ - name: memory-dp
+ subject: memory-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [memory]
+ existingSecret: memory-dp-credential
+ - name: memory-dp-v2
+ subject: memory-dp
+ allowedOperations: [api-key-introspect]
+ allowedProducts: [memory]
+ existingSecret: memory-dp-credential-v2
+ ```
+
+1. Run `helm upgrade` for the Identity Service release.
+1. Point the data plane at the new Secret. For Agent Memory, set `identityService.credential.existingSecret: memory-dp-credential-v2` and run `helm upgrade` for Agent Memory.
+1. Wait until every data-plane pod uses the new Secret, and check that agent calls work.
+1. Remove the old entry from `values-ids.yaml` and run `helm upgrade` for the Identity Service release.
+1. Delete the `memory-dp-credential` Secret.
+
+## Find who did what
+
+The Identity Service writes one log line with the message `audit event` for each control operation. It has no audit database, so collect the pod logs with your log system. To search the logs Kubernetes still keeps:
+
+```bash
+kubectl -n logs -l app.kubernetes.io/instance=ids --tail=-1 \
+ | grep '"audit event"' | grep ''
+```
+
+| Field | Meaning |
+| --- | --- |
+| `action` | The operation, for example `api_key.create`, `api_key.revoke`, or `subject_grant.patch`. |
+| `result` | `allowed`, `denied`, or `failed`. |
+| `subject`, `user_id`, `issuer` | The caller. |
+| `auth_type` | `admin_token` for the control token. |
+| `authorized_by` | The role that allowed the operation, for example `suite_admin`. |
+| `key_id`, `target_subject` | The key or subject that the operation changed. |
+
+The log never contains tokens. A request rejected before it reaches the service, such as one with a malformed body, has no audit line.
+
+## Upgrade
+
+1. Read the release notes for the chart version.
+1. Upgrade each service's control plane first. A newer Identity Service can send grant fields that an older control plane doesn't know.
+1. Upgrade the Identity Service release with the same values file:
+
+ ```bash
+ helm upgrade ids redis-ai/iris-identity-service \
+ --version \
+ --namespace \
+ -f values-ids.yaml
+ ```
+
+1. Run `helm test ids -n `, then mint and revoke a test key for each service.
+
+`helm rollback` restores the workload and its values. It doesn't change generated Secrets or the keys and grants in the metadata Redis.
+
+
+
+## Back up and restore
+
+The metadata Redis holds every agent key, grant, and subject grant. Back up database 0 of that Redis on a schedule, with persistence turned on. Also export the Secrets you created for the release, such as the control token, the runtime credentials, and the internal tokens, and store the export as you store database passwords.
+
+A restore brings back the keys and grants as they were at backup time:
+
+- Keys minted after the backup don't work. Mint them again and give them to their agents.
+- Keys revoked after the backup work again. Revoke them again.
+
+### Move the metadata Redis
+
+Stop the Identity Service during the move. If it keeps running after the copy, it changes only the old Redis.
+
+1. Set `replicaCount` to `0` and run `helm upgrade`.
+1. Copy the data to the new Redis.
+1. Put the new host in `metadata.urls` in the metadata Secret.
+1. Set `replicaCount` to its earlier value and run `helm upgrade`.
+
+### Rotate the metadata Redis credential
+
+The Identity Service reads the metadata Redis connection only at startup.
+
+1. In Redis, add the new user or password, and keep the old one valid.
+1. Update the metadata Secret, and every service Secret that uses the same Redis.
+1. Restart the Identity Service, and wait until it's ready:
+
+ ```bash
+ kubectl -n rollout restart deployment/ids-iris-identity-service
+ kubectl -n rollout status deployment/ids-iris-identity-service
+ ```
+
+1. Restart the service control planes, then their data planes and workers, if they use the same Redis.
+1. Run `helm test ids -n `.
+1. Remove the old credential from Redis.
+
+### Planned outage of the metadata Redis
+
+While the metadata Redis is down, the Identity Service turns unready, and no agent key can be checked, minted, or changed. Kubernetes doesn't restart the pod. When Redis returns, readiness recovers without a restart.
+
+## Uninstall
+
+```bash
+helm uninstall ids --namespace
+```
+
+Uninstalling keeps the Secrets that the chart generated, such as the control token, and keeps every key in the metadata Redis. Services can't check agent keys while the Identity Service is gone. To remove everything, delete the generated Secrets, the Secrets you created, and the metadata Redis data.
+
+## Troubleshooting
+
+The Identity Service returns errors as RFC 7807 problem documents. The `type` field names the error.
+
+{{< table-scrollable >}}
+| Symptom | Possible cause | What to do |
+| --- | --- | --- |
+| Readiness returns `503` | The Identity Service can't reach the metadata Redis. | Check the URL, user, password, and Transport Layer Security (TLS) settings in the metadata Secret. |
+| The pod doesn't start | Two credentials share a value, or a value isn't valid. | Read the first error line in the pod log. It names the field. |
+| `401` on the control API | Wrong control token, or the operator token has the wrong issuer, audience, or signature, or expired. | Compare the token's `iss` and `aud` claims with `controlAuth.oidc`. |
+| `403` on the control API | The caller has no role for this operation or service. | Check `controlAuth.roleBindings` and the groups in the token. |
+| `503` on the control API | The Identity Service can't read its token file or reach the JSON Web Key Set (JWKS) URI. | Check the Secret mount and the network path to your identity provider (IdP). |
+| `404` for a key that exists | The key is in another tenant. | Check the caller's tenant. |
+| `400` that names the tenant | The grant names a tenant other than `singleTenantID`. | Omit `tenant`, or set it to `singleTenantID`. |
+| `400` from grant validation | The resource doesn't exist in the tenant, or an action isn't valid. | Check the resource ID in the service's control plane, and that the service's `tenantId` equals `singleTenantID`. |
+| `424` when minting | The Identity Service can't call the validator: the control plane is down, the address is wrong, or the internal token doesn't match. | Check `productValidation.products.` and the control-plane logs. |
+| Agents get `403` with a valid key | The key's tenant isn't the service's tenant, or the key has no grant for the resource or action. | Compare `singleTenantID` with the service's `tenantId`, and check the key's grants. |
+| Agents get `503`, and the data-plane log shows `service-credential-rejected` | The data plane's runtime credential doesn't match the Identity Service entry. | Compare the data plane's Secret with the Identity Service entry's Secret. |
+| Agents get `503`, and the data-plane log shows `service-credential-insufficient-permissions` | The runtime credential lacks the operation or service. | Add it to the entry's `allowedOperations` or `allowedProducts`. |
+| A user with a subject grant gets `403` | The issuer or subject differs from the token, or the shape isn't in `subjectGrants.allowed`. | Compare the token's `iss` and `sub` claims with the grant. |
+| A revoked key still works | The data plane's key cache. | Wait up to `runtime.cache.hardTtlSeconds`. |
+{{< /table-scrollable >}}
diff --git a/content/operate/iris/intent-router/_index.md b/content/operate/iris/intent-router/_index.md
index 2f6d370274..09555105fd 100644
--- a/content/operate/iris/intent-router/_index.md
+++ b/content/operate/iris/intent-router/_index.md
@@ -1,6 +1,6 @@
---
title: Redis Intent Router
-description: Deploy and operate Redis Intent Router on your own infrastructure.
+description: Deploy and operate Redis Intent Router on Redis Cloud or your own infrastructure.
linkTitle: Intent Router
alwaysopen: false
categories:
@@ -11,10 +11,20 @@ weight: 24
hideListLinks: true
---
-Deploy Redis Intent Router on Kubernetes to give applications a service that classifies text into intents and returns the target to dispatch to.
+Redis Intent Router classifies text into the intents you define and returns the target to dispatch to.
-## Self-managed
+## Deployment options
-[Start with the self-managed deployment guide](/content/operate/iris/intent-router/self-managed/_index.md).
+### Redis Cloud
+
+Use Redis Intent Router as a managed service on Redis Cloud.
+
+
+
+After setup, use the [developer quickstart](/content/develop/ai/context-engine/intent-router/quickstart.md) to define your first intents and match queries.
-After setup, use the [developer quickstart](/content/develop/ai/context-engine/intent-router/quickstart.md) to define your first intents and match queries. The [developer guides](/content/develop/ai/context-engine/intent-router/_index.md) cover Router administration, intent authoring, and matching.
+### Self-managed
+
+Deploy Redis Intent Router on Kubernetes to run it on your own infrastructure.
+
+[Start with the self-managed deployment guide](/content/operate/iris/intent-router/self-managed/_index.md).
diff --git a/content/operate/iris/intent-router/self-managed/_index.md b/content/operate/iris/intent-router/self-managed/_index.md
index 6e8af8b8d3..31091f2b58 100644
--- a/content/operate/iris/intent-router/self-managed/_index.md
+++ b/content/operate/iris/intent-router/self-managed/_index.md
@@ -19,8 +19,7 @@ The `redis-intent-router` Helm chart deploys one tenant's Intent Router control
Applications call the data plane to author intents and match queries, as described in the [data-plane API reference](/content/develop/ai/context-engine/intent-router/api-reference.md). The [control-plane API reference](/content/operate/iris/intent-router/self-managed/control-plane-api-reference.md) documents the administration endpoints for Routers.
-
-Set the chart version and image tags from the release manifest for your deployment.
+These guides use `redis-intent-router` chart `0.1.0`. Set the image tags from the release manifest for your deployment.
## What you deploy
diff --git a/content/operate/iris/intent-router/self-managed/authentication.md b/content/operate/iris/intent-router/self-managed/authentication.md
index 7261dae29d..668cac998a 100644
--- a/content/operate/iris/intent-router/self-managed/authentication.md
+++ b/content/operate/iris/intent-router/self-managed/authentication.md
@@ -22,7 +22,7 @@ This page lists each credential and what it unlocks. It also shows how to load t
| Control-plane admin token | Operator → control plane (`:9400`) | The Secret in `controlplane.adminToken` | Yes, by default | Router administration: `/iris/v1/intent/routers` and `/iris/v1/intent/models` |
| Control-plane internal token | Identity Service → control plane | The Secret in `controlplane.internalToken` | Yes, by default | Checking that the Router in a grant exists |
| Identity Service control token | Operator → Identity Service (`:9200`) | Set on the Identity Service release with `control.*`. That chart generates `-control-token` by default | Yes, by the Identity Service release | Creating, listing, rotating, and revoking agent keys |
-| Identity Service runtime token | Data plane → Identity Service | The Secret in `identityService.runtimeToken` | Yes, by default | Checking agent keys for `intent` |
+| Identity Service runtime token | Data plane → Identity Service | The Secret in `identityService.credential` / `token` | No. Register it on the Identity Service release | Checking agent keys for `intent` |
| Agent key | Application → data plane (`:9401`) | None. Returned once when minted or rotated | No | Authoring and matching on the Routers its grants name |
`controlplane.adminToken` and `controlplane.internalToken` default to `autoGenerate: true`: without `existingSecret`, the chart creates a random Secret named `-redis-intent-router-controlplane-admin-token` or `-internal-token`, with the key `token`, keeps it across upgrades, and never rotates it. For a release named `intent`, the admin token is in `intent-redis-intent-router-controlplane-admin-token`. The chart never generates `identityService.credential`. Set `existingSecret` to supply your own, and set the matching `existingSecretChecksum` so the pods roll when the Secret changes. Two credentials can't reference the same Secret key, and rendering fails if they do.
@@ -33,13 +33,13 @@ An agent key gets `401` from the control plane. A key without a grant on a Route
Every Router operation needs the admin token in `Authorization: Bearer `, and every agent-key operation needs the Identity Service control token. The health routes need no credential.
-Load both from their Secrets before you call the control plane or the Identity Service. The admin token uses the Secret name from [Deploy](/content/operate/iris/intent-router/self-managed/deploy.md#2-create-secrets). The control token example assumes an Identity Service release named `iris-identity-service` that generates its control token; with `control.existingSecret`, read that Secret instead:
+Load both from their Secrets before you call the control plane or the Identity Service. The admin token uses the Secret name from [Deploy](/content/operate/iris/intent-router/self-managed/deploy.md#2-create-secrets). The control token example assumes an Identity Service release named `ids` that generates its control token; with `control.existingSecret`, read that Secret instead:
```bash
export IRIS_INTENT_ROUTER_SERVICE_TOKEN="$(kubectl -n get secret \
intent-controlplane-admin -o jsonpath='{.data.token}' | base64 --decode)"
export IRIS_IDENTITY_TOKEN="$(kubectl -n get secret \
- iris-identity-service-control-token -o jsonpath='{.data.token}' | base64 --decode)"
+ ids-iris-identity-service-control-token -o jsonpath='{.data.token}' | base64 --decode)"
```
## Router authorization and grants
diff --git a/content/operate/iris/intent-router/self-managed/configuration.md b/content/operate/iris/intent-router/self-managed/configuration.md
index 165208a878..c66f67b3fd 100644
--- a/content/operate/iris/intent-router/self-managed/configuration.md
+++ b/content/operate/iris/intent-router/self-managed/configuration.md
@@ -49,7 +49,7 @@ dataplane:
image:
repository: redislabs/iris-intent-router-data
tag:
- identityServiceBaseURL: http://iris-identity-service:9200
+ identityServiceBaseURL: http://ids-iris-identity-service:9200
identityService:
allowInsecureTransport: true
diff --git a/content/operate/iris/intent-router/self-managed/deploy.md b/content/operate/iris/intent-router/self-managed/deploy.md
index 0ad0a83017..113f158a4a 100644
--- a/content/operate/iris/intent-router/self-managed/deploy.md
+++ b/content/operate/iris/intent-router/self-managed/deploy.md
@@ -27,7 +27,9 @@ kubectl create namespace
### Configure the Identity Service release first
-The chart deploys no Identity Service. Set these values on your Identity Service release so that it checks Router grants and accepts the data plane's runtime credential. The examples assume this chart is installed as release `intent` in the same namespace as an Identity Service release named `iris-identity-service`.
+For every Identity Service setting, and for running one release that serves several products, see the [Identity Service guide](/content/operate/iris/identity-service/_index.md).
+
+The chart deploys no Identity Service. Set these values on your Identity Service release so that it checks Router grants and accepts the data plane's runtime credential. The examples assume this chart is installed as release `intent` in the same namespace as an Identity Service release named `ids`.
| Identity Service value | Setting |
| --- | --- |
@@ -94,7 +96,7 @@ Check each value before you install. If one is wrong, you see the symptom in its
helm repo add redis-ai https://helm.redis.io/ai
helm repo update redis-ai
helm install intent redis-ai/redis-intent-router \
- --version \
+ --version 0.1.0 \
--namespace \
-f intent-values.yaml \
--wait --timeout 5m
@@ -120,7 +122,7 @@ kubectl -n port-forward svc/intent-redis-intent-router-dataplan
```
```bash
-kubectl -n port-forward svc/iris-identity-service 9200:9200
+kubectl -n port-forward svc/ids-iris-identity-service 9200:9200
```
Then check readiness on every service:
diff --git a/content/operate/iris/lens/_index.md b/content/operate/iris/lens/_index.md
index 7098837745..be7bdd9ae6 100644
--- a/content/operate/iris/lens/_index.md
+++ b/content/operate/iris/lens/_index.md
@@ -1,6 +1,6 @@
---
title: Lens
-description: Create and operate Lens on Redis Cloud.
+description: Create and operate Lens on Redis Cloud or your own infrastructure.
linkTitle: Lens
alwaysopen: false
categories:
@@ -24,3 +24,9 @@ Use Lens as a managed service on Redis Cloud.
[Create Lens](/content/operate/iris/lens/create-lens.md), connect your agent, and open Lens in the Redis Cloud console.
After setup, use the [developer quickstart](/content/develop/ai/context-engine/lens/quickstart.md) to trace your first turn.
+
+### Self-managed
+
+Deploy Lens on Kubernetes to run it on your own infrastructure.
+
+[Start with the self-managed deployment guide](/content/operate/iris/lens/self-managed/_index.md).
diff --git a/content/operate/iris/lens/self-managed/_index.md b/content/operate/iris/lens/self-managed/_index.md
new file mode 100644
index 0000000000..3c5cf5d801
--- /dev/null
+++ b/content/operate/iris/lens/self-managed/_index.md
@@ -0,0 +1,76 @@
+---
+Title: Self-managed Lens
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Deploy, configure, secure, and operate Lens on a self-managed Kubernetes cluster.
+linkTitle: Self-managed
+weight: 40
+hideListLinks: true
+---
+
+Lens traces your AI agent turns, so developers can see what each source returned, what entered the prompt, and how each step went. Before developers can send turns, a platform administrator deploys Lens, connects it to an Identity Service, and gives each application an endpoint and API keys.
+
+This guide is for that administrator. It covers deploying Lens on your own Kubernetes cluster with the `redis-lens` Helm chart, then configuring, securing, and operating it. To install, start with the [prerequisites](/content/operate/iris/lens/self-managed/prerequisites.md).
+
+> [!NOTE]
+> You need a license key to deploy self-managed Lens. Contact your Redis representative or
+> [contact sales](https://redis.io/contact/).
+
+These guides use `redis-lens` chart `0.2.1`.
+
+
+## What you deploy
+
+One release of the `redis-lens` chart runs three workloads. It deploys no Identity Service: it connects to a separate `iris-identity-service` release.
+
+| Component | Purpose | Service port |
+| --- | --- | --- |
+| Data plane | Receives turns from agents over OpenTelemetry Protocol (OTLP) and serves the read application programming interface (API). | `9000` |
+| Worker | Assembles received steps into turns. Runs the data-plane image, with no Service. | None |
+| Control plane | Holds the single Lens instance record and validates key grants for the Identity Service. | `9300` |
+| Identity Service | Mints Lens API keys and checks them for the data plane. Installed as its own release. | `9200` |
+| Records database | Turn streams and search indexes. | Customer-provided |
+| Content database | Captured prompts, responses, and tool payloads. | Customer-provided |
+| Metadata Redis | The Lens instance record. | Customer-provided |
+
+One installation serves one Lens instance, `default` unless you set `instance.id`. The control plane creates it at startup, so there is no create call.
+
+### How the components work together
+
+| Flow | Caller | Service |
+| --- | --- | --- |
+| Send turns | Agent, with an `ingest` key | Data plane |
+| Read sessions and turns | Lens UI or read client, with a `read` key | Data plane |
+| Mint and revoke API keys | Platform admin, with the Identity Service control token | Identity Service |
+| Validate a key's grant before it's stored | Identity Service, with the control-plane internal token | Control plane |
+| Check an API key on each request | Data plane, with its runtime credential | Identity Service |
+| Read or change the instance's retention | Platform admin, with the control-plane admin token | Control plane |
+
+The worker reads what the data plane receives from the records database and writes assembled turns back. It calls no other service.
+
+### API surfaces
+
+| API surface | Endpoint | Purpose |
+| --- | --- | --- |
+| Ingest | `POST /iris/data/v1beta1/lens/v1/traces` | OTLP over HTTP (protobuf) from agents. |
+| Read API | `/iris/data/v1beta1/lens/instances/{instanceId}/...` | Agents, sessions, turns, and captured content. See the [read API](/content/develop/ai/context-engine/lens/read-api.md). |
+| Control plane | `/iris/v1beta1/lens/instance` | Read and change the instance's retention. |
+| Health | `/health/liveness`, `/health/readiness` | Liveness and readiness on every workload. |
+| Identity Service | `/v1/api-keys` | Administration of API keys. |
+
+## Get started
+
+1. Review the [prerequisites](/content/operate/iris/lens/self-managed/prerequisites.md).
+1. Prepare the [configuration](/content/operate/iris/lens/self-managed/configuration.md).
+1. [Deploy the Identity Service and Lens](/content/operate/iris/lens/self-managed/deploy.md).
+1. [Create API keys](/content/operate/iris/lens/self-managed/authentication.md#create-api-keys).
+1. [Give developers their Lens settings](/content/operate/iris/lens/self-managed/deploy.md#hand-off-to-developers).
+
+## Manage the deployment
+
+- [Rotate credentials and revoke keys](/content/operate/iris/lens/self-managed/authentication.md#rotate-credentials).
+- [Check health, watch stream growth, change retention, and upgrade](/content/operate/iris/lens/self-managed/operations.md).
+- [Troubleshoot the deployment](/content/operate/iris/lens/self-managed/operations.md#troubleshooting).
diff --git a/content/operate/iris/lens/self-managed/authentication.md b/content/operate/iris/lens/self-managed/authentication.md
new file mode 100644
index 0000000000..d6595d0cf3
--- /dev/null
+++ b/content/operate/iris/lens/self-managed/authentication.md
@@ -0,0 +1,136 @@
+---
+Title: Authentication and authorization
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Understand the Lens credentials, create API keys with grants, turn on operator sign-in, and rotate credentials.
+linkTitle: Authentication and authorization
+weight: 60
+hideListLinks: true
+---
+
+Self-managed Lens uses three kinds of credentials. Service tokens authenticate operators and the components to each other. API keys, minted by the Identity Service, authenticate agents and readers to the data plane. Operator sign-in tokens from your identity provider (IdP) are optional and authenticate operators on the read API and the control plane.
+
+## Credentials
+
+| Credential | Who presents it to whom | Secret | What it unlocks |
+| --- | --- | --- | --- |
+| Control-plane admin token | Operator → control plane (`:9300`) | Generated as `-redis-lens-controlplane-admin-token`, or the Secret in `controlplane.adminToken.existingSecret` | `GET` and `PATCH /iris/v1beta1/lens/instance` |
+| Control-plane internal token | Identity Service → control plane | `controlplane.internalToken.existingSecret`, also the Identity Service's `productValidation.products.lens.credential` | Validating a key's grant before the Identity Service stores it |
+| Data-plane runtime credential | Data plane → Identity Service | `identityService.credential.existingSecret`, also the Identity Service's `runtime.serviceCredentials` entry `lens-dataplane` | Checking API keys for `lens` |
+| Identity Service control token | Operator → Identity Service (`:9200`) | The Identity Service release's `control` Secret | Creating, rotating, and revoking API keys |
+| API key | Agent or reader → data plane (`:9000`) | None. Returned once when minted | Ingest or reads on the instance its grant names |
+
+The generated admin token has the key `token`. The chart keeps it across upgrades (`helm.sh/resource-policy: keep`) and never rotates it. The chart refuses to mount one Secret key as two of its credentials.
+
+Load the two administration tokens before you call the control plane or the Identity Service. With the Secret names from [Deploy](/content/operate/iris/lens/self-managed/deploy.md#2-create-secrets):
+
+```bash
+export LENS_ADMIN_TOKEN="$(kubectl -n get secret \
+ lens-redis-lens-controlplane-admin-token -o jsonpath='{.data.token}' | base64 --decode)"
+export IRIS_IDENTITY_TOKEN="$(kubectl -n get secret \
+ ids-control-token -o jsonpath='{.data.token}' | base64 --decode)"
+```
+
+The health routes need no credential.
+
+## Grants and scopes
+
+Each API key carries a grant on the Lens instance:
+
+| Grant field | Value |
+| --- | --- |
+| `product` | `lens` |
+| `resourceType` | `lens-instance` |
+| `resourceId` | The `instance.id`, such as `default`. |
+| `actions` | One or more of `ingest`, `read`, and `full`. |
+
+| Action | What it allows |
+| --- | --- |
+| `ingest` | Send turns to `POST /iris/data/v1beta1/lens/v1/traces`. Gets `403` on the read API. |
+| `read` | Read agents, sessions, turns, and content. |
+| `full` | Both. |
+
+The Identity Service stamps the deployment's tenant on a grant that omits one. It asks the control plane to validate each grant before it stores the key, so a grant for another instance ID is refused.
+
+## Create API keys
+
+With the Identity Service port-forwarded to `localhost:9200`, create an ingest key for an agent:
+
+```bash
+export IRIS_IDENTITY_URL='http://localhost:9200'
+curl --fail-with-body --silent --show-error \
+ -X POST "$IRIS_IDENTITY_URL/v1/api-keys" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN" \
+ -H 'Content-Type: application/json' \
+ -d '{"name":"support-bot-ingest","grants":[{"product":"lens","resourceType":"lens-instance","resourceId":"default","actions":["ingest"]}]}' \
+ > ingest-key.json
+export IRIS_LENS_API_KEY="$(jq -er '.token' ingest-key.json)"
+jq '{keyId, createdAt}' ingest-key.json
+```
+
+Create a read key the same way, with `"actions":["read"]`, and save its `.token` in `LENS_API_KEY`.
+
+> [!WARNING]
+> The Identity Service returns each key's token only once. Save it to your secret store, then delete the JSON file.
+
+Agents send the key as `Authorization: Bearer ` or `X-Api-Key: `. The read client sends it as a bearer token.
+
+## Revoke API keys
+
+Revoke a key with its `keyId`:
+
+```bash
+curl --fail-with-body --silent --show-error \
+ -X DELETE "$IRIS_IDENTITY_URL/v1/api-keys/" \
+ -H "Authorization: Bearer $IRIS_IDENTITY_TOKEN"
+```
+
+The data plane caches each key check. A revoked key stops working when the Identity Service's runtime cache expires, set by its `runtime.cache` values (300 seconds by default).
+
+## Operator sign-in
+
+The data plane can accept access tokens from your IdP beside API keys, so operators signed in to the Iris console can read sessions and turns. Turn it on in `lens-values.yaml`:
+
+```yaml
+auth:
+ oidc:
+ audience: api://redis-iris
+dataplane:
+ oidc:
+ enabled: true
+ issuer:
+ jwksURI: https:///
+ tenantIDClaim: ""
+ roleMappings:
+ : viewer
+controlplane:
+ oidc:
+ enabled: true
+```
+
+| Value | Purpose |
+| --- | --- |
+| `auth.oidc.audience` | The audience the IdP puts in the token's `aud`. Use the same Iris API audience in every Iris chart. On Microsoft Entra ID v2, it's the API's Application (client) ID. Empty and wildcard values are refused. |
+| `dataplane.oidc.issuer` | Compared with the token's `iss`, and never fetched, so `http://` is allowed. On Active Directory Federation Services (AD FS), use the discovery document's `access_token_issuer`. |
+| `dataplane.oidc.jwksURI` | Fetched for signing keys. Must be `https://` unless `dataplane.oidc.allowInsecureTransport=true`. |
+| `dataplane.oidc.tenantIDClaim` | The claim that names the tenant. Empty treats every token as `tenantId`'s. |
+| `dataplane.oidc.roleClaims` | The claims that carry groups. Empty uses `roles` and `groups`. |
+| `dataplane.oidc.roleMappings` | Required. Maps IdP groups to Iris roles: `viewer`, `operator`, `product_admin`, or `suite_admin`. Unmapped groups are never accepted. |
+| `controlplane.oidc.enabled` | The control plane validates the same tokens with the same settings. Requires `dataplane.oidc.enabled`. |
+
+An operator token is accepted on the read API with `viewer` or a higher role. It always gets `403` on ingest, because ingest needs an API key. The admin token keeps working beside operator tokens.
+
+Revoking an API key doesn't affect operator tokens. Removing an operator's role in the IdP takes effect when their current token expires.
+
+## Rotate credentials
+
+To rotate a service token, update its Secret, update the matching `existingSecretChecksum`, and run `helm upgrade`, so the pods roll:
+
+- **Admin token**: Lens only.
+- **Internal token** and **runtime credential**: both releases mount them. Update the Secret, then upgrade both releases together.
+- **Identity Service control token**: the Identity Service release only.
+
+To replace an API key, create a new key, give it to the application, then revoke the old one.
diff --git a/content/operate/iris/lens/self-managed/configuration.md b/content/operate/iris/lens/self-managed/configuration.md
new file mode 100644
index 0000000000..cebab06748
--- /dev/null
+++ b/content/operate/iris/lens/self-managed/configuration.md
@@ -0,0 +1,151 @@
+---
+Title: Configure self-managed Lens
+alwaysopen: false
+categories:
+- docs
+- operate
+- iris
+description: Set the Helm values, storage Secret, retention, ingest, Identity Service connection, and TLS trust for Lens.
+linkTitle: Configuration
+weight: 30
+hideListLinks: true
+---
+
+You configure self-managed Lens with a Helm values file and the Secrets it references. The values file sets your tenant, instance, retention, and the Identity Service connection. The Secrets hold what shouldn't be in a values file: Redis URLs, tokens, and the license.
+
+## Helm values
+
+This values file is the starting point for [Deploy](/content/operate/iris/lens/self-managed/deploy.md). It assumes an Identity Service release named `ids` in the same namespace. Save it as `lens-values.yaml`:
+
+```yaml
+tenantId: default
+
+instance:
+ id: default
+
+ingest:
+ enabled: true
+
+storage:
+ existingSecret: lens-storage
+
+license:
+ existingSecret: lens-license
+
+dataplane:
+ # The Identity Service release's Service. In-cluster, it speaks plain HTTP.
+ identityServiceBaseURL: http://ids-iris-identity-service:9200
+
+identityService:
+ allowInsecureTransport: true
+ credential:
+ existingSecret: lens-dp-credential
+
+controlplane:
+ internalToken:
+ existingSecret: lens-internal-token
+
+tests:
+ enabled: true
+```
+
+| Value | Default | Purpose |
+| --- | --- | --- |
+| `tenantId` | `""` | Required. The tenant the instance belongs to. Must equal the Identity Service's `runtime.apiKeyTenant.singleTenantID`. |
+| `instance.id` | `default` | The one Lens instance this installation serves. Developers use it as their instance ID. |
+| `instance.retention.streamTrim` | `24h` | Recorded on the instance. See [Retention](#retention). |
+| `instance.retention.contentTTL` | `168h` | How long Lens keeps captured content. |
+| `instance.retention.indexRetention` | `720h` | How long Lens keeps turn structure, timing, scores, and outcomes. |
+| `ingest.enabled` | `false` | Accept turns. See [Ingest](#ingest). |
+| `ingest.region` | `onprem` | Scopes the stream keys. Use one value per installation. |
+| `storage.existingSecret` | `""` | Required. The [storage Secret](#storage-secret). |
+| `storage.keyPrefix` | `iris:lens` | The prefix of every key Lens writes. |
+| `license.existingSecret` | `""` | Required. The license Secret, with the key `license`. |
+| `dataplane.image.repository`, `dataplane.image.tag` | `redislabs/iris-lens-data` | The data-plane and worker image. |
+| `controlplane.image.repository`, `controlplane.image.tag` | `redislabs/iris-lens-control` | The control-plane image. |
+| `dataplane.identityServiceBaseURL` | `""` | Required. The Identity Service release's URL. Must be `https://` unless `identityService.allowInsecureTransport=true`. |
+| `identityService.allowInsecureTransport` | `false` | Accept an `http://` Identity Service URL, such as the in-cluster Service. |
+| `identityService.credential.existingSecret` | `""` | Required. The data plane's runtime credential, key `token`. |
+| `controlplane.internalToken.existingSecret` | `""` | The control plane's internal token, key `token`. Set it, because the Identity Service release must mount the same Secret. |
+| `controlplane.adminToken.existingSecret` | `""` | Supply your own admin token. Empty, the chart generates one. |
+| `dataplane.server.replicaCount`, `dataplane.worker.replicaCount`, `controlplane.replicaCount` | `1` | Replicas for each workload. |
+| `tls.caCertSecret` | `""` | A certificate authority (CA) bundle every workload trusts. See [TLS trust](#tls-trust). |
+| `security.profile` | `""` | `fips` runs the Federal Information Processing Standards (FIPS) profile. |
+| `imagePullSecrets` | `[]` | Pull Secrets for a private registry. |
+| `tests.enabled` | `false` | Add `helm test` readiness checks. |
+
+To pull images from a mirror, set each `repository` to your registry and each `tag` to the chart's version.
+
+
+
+Every Secret value also has an `existingSecretChecksum`. Set it when you change the Secret's content, so the pods roll. See [Rotate credentials](/content/operate/iris/lens/self-managed/authentication.md#rotate-credentials).
+
+## Storage Secret
+
+The storage Secret holds one configuration file per process. Each key is a file name:
+
+| Key | Process | Holds |
+| --- | --- | --- |
+| `lens-dataplane-storage.yaml` | Data plane and worker | `storage.streams`, `storage.index`, `storage.content`, and `storage.metadata` URLs. |
+| `lens-controlplane-storage.yaml` | Control plane | `storage.metadata` URLs, and optional `dram.urls`. |
+
+Save the data-plane file as `lens-dataplane-storage.yaml`. Here `streams` and `index` share the records database:
+
+```yaml
+storage:
+ streams:
+ urls:
+ - rediss://:@:
+ index:
+ urls:
+ - rediss://:@:
+ content:
+ urls:
+ - rediss://:@:
+ metadata:
+ urls:
+ - rediss://:@:
+```
+
+Save the control-plane file as `lens-controlplane-storage.yaml`:
+
+```yaml
+storage:
+ metadata:
+ urls:
+ - rediss://:@:
+# Optional. The control plane checks the records database for Redis Search,
+# Redis JSON, and noeviction at startup and on each retention change.
+dram:
+ urls:
+ - rediss://:@:
+```
+
+Use the same `metadata` URL in both files. See [Redis databases](/content/operate/iris/lens/self-managed/prerequisites.md#redis-databases) for what each role needs.
+
+## Retention
+
+Lens keeps turn structure, timing, scores, and outcomes for `instance.retention.indexRetention`, and captured content for `instance.retention.contentTTL`. The read API offers time ranges that fit these windows. The windows must satisfy `streamTrim` < `contentTTL` ≤ `indexRetention`.
+
+The control plane records these values on the instance at its first start. The data plane stamps each content expiry from `contentTTL` as rendered by Helm. To change retention after install, see [Change retention](/content/operate/iris/lens/self-managed/operations.md#change-retention).
+
+Nothing trims the span streams yet, whatever `streamTrim` is set to.
+
+## Ingest
+
+With `ingest.enabled=false`, the default, the data plane answers `POST /iris/data/v1beta1/lens/v1/traces` with `503`, and the read API still works. Set `ingest.enabled=true` when you're ready for agents to send turns, and watch the records database's memory from then on.
+
+## TLS trust
+
+No Lens workload terminates TLS. To use an `https://` Identity Service URL, put a TLS-terminating proxy, gateway, or service mesh in front of the Identity Service.
+
+When a certificate, for the Identity Service or a `rediss://` database, is signed by a private CA, create a Secret that holds the CA bundle and set `tls.caCertSecret` to its name. Every workload mounts it at `/etc/ssl/custom` and trusts it in addition to the image's system CAs. Set `tls.caCertSecretChecksum` to roll the workloads when the bundle changes.
+
+## Identity Service in another namespace
+
+The Identity Service release can run in another namespace. Then:
+
+1. Set `dataplane.identityServiceBaseURL` to its fully qualified Service, such as `http://ids-iris-identity-service..svc:9200`.
+1. Set the Identity Service's `productValidation.products.lens.baseURL` to `http://lens-redis-lens-controlplane.