Learn how playbooks, entries, versions, publication, and proposals work
Redis Agent Playbooks
Create playbooks of reusable skills and answers that agents can discover and load for a task.
What are Redis Agent Playbooks?
Redis Agent Playbooks let you create and manage playbooks of curated answers and procedures for AI agents. Each playbook is a registry of entries with its own access grants and retrieval settings.
Publish an entry version, retrieve it for a task, and prepare revisions while agents use the current publication.
A FAQ gives an agent a validated answer, such as where a customer can find their refund status. A skill (Agent Skill) guides the agent through drafting a reply from that status using a template.
Publish and retrieve your first FAQ
Connect Redis Agent Playbooks to OpenAI Agents SDK or LangGraph
Why use Redis Agent Playbooks?
- Reusable agent knowledge: Manage approved FAQs and skills once, then use them across agents and applications.
- Controlled updates: Publish a specific entry version while authors prepare and review the next revision.
- Relevant retrieval: Match an agent's task with FAQ answers and skill previews using semantic discovery.
- Progressive skill loading: Let agents inspect skill previews before loading full instructions and supporting files.
- Governed collaboration: Separate reading, writing, publishing, and proposing with playbook access grants.
- Flexible integration: Retrieve entries through Python, HTTP, or Model Context Protocol (MCP).
Concepts
A playbook holds two kinds of entries:
| Entry | Use it for | What the agent receives |
|---|---|---|
| Skill | Procedures for completing a task, with optional scripts, references, or templates. | A name and description first; full instructions and files on demand. |
| FAQ | A validated answer to a recurring question. | The question and answer in the retrieval result. |
A publisher selects the version of each entry agents receive. Your application controls how retrieved content enters the model's context and which actions the agent can take.
See Redis Agent Playbooks concepts for versions, publication, and review.
Quick example
-
Set up a playbook:
- Redis Cloud: Create a playbook.
- Self-managed: Deploy Agent Playbooks on Kubernetes.
-
Install the Redis Iris Python package, which includes the
irisCLI:pip install 'redis-iris>=1.0.0' -
With
IRIS_AGENT_PLAYBOOKS_URL,IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID, andIRIS_AGENT_PLAYBOOKS_API_KEYin your environment, find the published entries that match an agent's task:
from redis_iris.agent_playbooks import AgentPlaybooks
playbook = AgentPlaybooks.from_env()
print(playbook.client.get_playbook_health())
from redis_iris.agent_playbooks import AgentPlaybooks
playbook = AgentPlaybooks.from_env()
print(playbook.client.get_playbook_health())
faq_content = {
"intents": ["Check a refund", "Find an existing refund"],
"attributes": {"locale": "en-US", "topic": "refund"},
"payload": {
"faq": {
"question": "How do I check the status of a refund?",
"answer": (
"Open the order in your order history and select Refund status. "
"If no refund is listed, contact support with your order number."
),
}
},
}
draft = playbook.client.create_faq(content=faq_content)
faq_id = draft.entry.entry_id
version = draft.version.version
print(faq_id, version, draft.entry.publication)
stored = playbook.client.get_faq_version(faq_id=faq_id, version=version)
print(stored.content)
playbook.client.publish_faq(faq_id=faq_id, version=version)
results = playbook.client.search_faqs(
query="Where can I see how my refund is progressing?",
filter_={"eq": {"name": "locale", "value": "en-US"}},
limit=5,
)
for match in results.items:
if match.faq is not None:
print(match.entry_id, match.version, match.score, match.faq.answer)
discovery = playbook.discover(
"Help a customer find their refund status",
filter_={"eq": {"name": "topic", "value": "refund"}},
)
print(discovery.as_prompt())
from copy import deepcopy
updated_content = deepcopy(faq_content)
updated_content["payload"]["faq"]["answer"] += (
" Support can check the current stage but cannot guarantee a bank posting date."
)
updated = playbook.client.append_faq_version(faq_id=faq_id, content=updated_content)
print("Review this version:", updated.version.version, updated.version.content)
playbook.client.publish_faq(faq_id=faq_id, version=updated.version.version)
updated_results = playbook.client.search_faqs(
query="Where can I see how my refund is progressing?",
filter_={"eq": {"name": "locale", "value": "en-US"}},
limit=5,
)
for match in updated_results.items:
if match.entry_id == faq_id and match.faq is not None:
print("Published answer:", match.version, match.faq.answer)
set -euo pipefail
iris agent-playbooks health
set -euo pipefail
iris agent-playbooks health
cat > faq.json <<'JSON'
{
"entryKey": "refund-status",
"question": "How do I check the status of a refund?",
"answer": "Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number.",
"intents": ["Check a refund", "Find an existing refund"],
"attributes": {"locale": "en-US", "topic": "refund"}
}
JSON
iris agent-playbooks faqs validate faq.json
iris --json agent-playbooks faqs push faq.json > faq-draft.json
FAQ_ID=$(jq -er '.results[0].entryId' faq-draft.json)
VERSION=$(jq -er '.results[0].version' faq-draft.json)
jq . faq-draft.json
iris --json agent-playbooks faqs show "$FAQ_ID" --version "$VERSION" | jq .content
iris agent-playbooks faqs publish "$FAQ_ID" --version "$VERSION"
cat > search.json <<'JSON'
{
"query": "Where can I see how my refund is progressing?",
"filter": {"eq": {"name": "locale", "value": "en-US"}},
"limit": 5
}
JSON
iris --json agent-playbooks faqs search --input search.json | jq .items
cat > discover.json <<'JSON'
{
"query": "Help a customer find their refund status",
"filter": {"eq": {"name": "topic", "value": "refund"}},
"limit": 5
}
JSON
iris --json agent-playbooks discover --input discover.json | jq .
jq '.answer += " Support can check the current stage but cannot guarantee a bank posting date."' \
faq.json > faq-update.json
iris --json agent-playbooks faqs push faq-update.json > faq-updated.json
UPDATED_VERSION=$(jq -er '.results[0].version' faq-updated.json)
iris --json agent-playbooks faqs show "$FAQ_ID" --version "$UPDATED_VERSION" | jq .content
iris agent-playbooks faqs publish "$FAQ_ID" --version "$UPDATED_VERSION"
iris --json agent-playbooks faqs search --input search.json | jq .items
set -euo pipefail
PLAYBOOK_API="${IRIS_AGENT_PLAYBOOKS_URL%/}/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID"
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/health" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .
set -euo pipefail
set -euo pipefail
PLAYBOOK_API="${IRIS_AGENT_PLAYBOOKS_URL%/}/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID"
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/health" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .
cat > faq.json <<'JSON'
{
"content": {
"intents": ["Check a refund", "Find an existing refund"],
"attributes": {"locale": "en-US", "topic": "refund"},
"payload": {"faq": {
"question": "How do I check the status of a refund?",
"answer": "Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number."
}}
}
}
JSON
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' --data-binary @faq.json > draft.json
FAQ_ID=$(jq -er '.entry.entryId' draft.json)
VERSION=$(jq -er '.version.version' draft.json)
jq '{entryId: .entry.entryId, version: .version.version, publication: .entry.publication}' draft.json
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/faqs/$FAQ_ID/versions/$VERSION" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .content
curl --fail-with-body --silent --show-error \
-X PUT "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data "$(jq -n --argjson version "$VERSION" '{version: $version}')" | jq .publication
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where can I see how my refund is progressing?","filter":{"eq":{"name":"locale","value":"en-US"}},"limit":5}' \
| jq '.items[] | {entryId, version, score, answer: .faq.answer}'
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Help a customer find their refund status","filter":{"eq":{"name":"topic","value":"refund"}},"limit":5}' | jq .
jq '.content.payload.faq.answer += " Support can check the current stage but cannot guarantee a bank posting date."' \
faq.json > faq-update.json
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/$FAQ_ID/versions" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' --data-binary @faq-update.json > updated.json
jq .version updated.json
curl --fail-with-body --silent --show-error \
-X PUT "$PLAYBOOK_API/faqs/$FAQ_ID/publication" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data "$(jq '{version: .version.version}' updated.json)" | jq .publication
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where can I see how my refund is progressing?","filter":{"eq":{"name":"locale","value":"en-US"}},"limit":5}' \
| jq --arg id "$FAQ_ID" '.items[] | select(.entryId == $id) | {version, answer: .faq.answer}'
discovery = playbook.discover(
"Help a customer find their refund status",
filter_={"eq": {"name": "topic", "value": "refund"}},
)
print(discovery.as_prompt())
cat > discover.json <<'JSON'
{
"query": "Help a customer find their refund status",
"filter": {"eq": {"name": "topic", "value": "refund"}},
"limit": 5
}
JSON
iris --json agent-playbooks discover --input discover.json | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Help a customer find their refund status","filter":{"eq":{"name":"topic","value":"refund"}},"limit":5}' | jq .
Follow the quickstart to publish your first FAQ and retrieve it.
Manage playbook entries
- Manage FAQs: write, publish, and update FAQs.
- Manage skills: package Agent Skills and load their instructions and files on demand.
- Review proposals: check proposed entries and accumulated evidence before accepting them.
Serve playbook entries at runtime
- Retrieve relevant FAQs or Agent Skills on demand.
- Integrate with an agent using OpenAI Agents SDK or LangGraph.
- Connect with MCP.
Use the API reference for operations and schemas, and service limits and errors for constraints and recovery guidance.