{
  "schema_version": 2,
  "id": "develop/ai/context-engine/agent-playbooks/quickstart",
  "title": "Redis Agent Playbooks quickstart",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/quickstart/",
  "summary": "Publish an FAQ, retrieve it for an agent, and update the answer with Python, HTTP, or the Iris CLI.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-03T15:26:57-08:00",
  "page_type": "content",
  "content_hash": "614a2847b95ad1977f819999189d2cf7c25bb1f83f3611e70bf7fba30c8f94f3",
  "sections": [
    {
      "id": "code-examples",
      "title": "Code examples",
      "role": "example",
      "text": "These examples connect to Iris services using SDKs or HTTP requests with curl. Follow one language throughout each walkthrough.\n\n\nUse Redis Agent Playbooks to publish a FAQ, retrieve its answer to “Where can I see how my refund is progressing?”, and update the answer agents receive."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "[Create a playbook](https://redis.io/docs/latest/operate/iris/agent-playbook/create-playbook) and wait until it is **Ready**. [Create an authoring key](https://redis.io/docs/latest/operate/iris/agent-playbook/create-playbook#give-an-agent-access) with `write` and `publish` permissions. Both include `read`.\n\nThis walkthrough needs no agent framework or model-provider key.\n\nFollow one tab throughout the page. The Python SDK and command-line interface (CLI) require Python 3.11 or later. The cURL and CLI examples use Bash and jq."
    },
    {
      "id": "connect-to-the-playbook",
      "title": "Connect to the playbook",
      "role": "content",
      "text": "1. For Python or CLI examples, install the unified package:\n\n    [code example]\n\n1. Copy the **Endpoint** and **Playbook ID** from the console's [Connect dialog](https://redis.io/docs/latest/operate/iris/agent-playbook/create-playbook#give-an-agent-access). Save them with your authoring key in `.env`. Replace the placeholders in this file. Use the endpoint's base address, including `https://`, without the `/iris/data/v1/agent-playbooks/...` path.\n\n    [code example]\n\n1. Load the file in the shell where you run the examples:\n\n    [code example]\n\n1. Expand an example to copy the complete program. Save it as `quickstart.py`, `quickstart.cli.sh`, or `quickstart.sh` (cURL), then run `python quickstart.py`, `bash quickstart.cli.sh`, or `bash quickstart.sh`.\n\nKeep `.env` out of source control and keys out of skill files and model prompts. Use [`iris.toml` profiles](https://redis.io/docs/latest/develop/ai/context-engine/sdk-and-cli) for several deployments. All three clients use the authoring key in `.env` for this walkthrough.\n\n`AgentPlaybooks.from_env()` reads the connection values. Its public `.client` property exposes authoring, search, and review operations. The CLI reads the same environment variables and uses `--json` when saving or processing responses.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nKeep the printed identifier for cleanup. SDK and cURL examples create another entry when rerun. The CLI uses `refund-status` as a stable entry key: `faqs push` creates missing content, appends changed content, and skips unchanged content. Start with an unused key for this walkthrough. After an uncertain write, inspect entry state before retrying."
    },
    {
      "id": "create-an-faq",
      "title": "Create an FAQ",
      "role": "content",
      "text": "Create one answer with a locale and topic for retrieval filters. Save the returned entry identifier and version.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe first version is `1`, and `publication` is absent or empty. You can review the entry, but search and discovery cannot return it yet.\n\nThe CLI prepares a flat FAQ JSON file and validates it locally before pushing it. Its result is an action report containing the entry identifier and version, rather than the HTTP creation response. `push` leaves the version unpublished unless you request publication."
    },
    {
      "id": "review-and-publish-the-answer",
      "title": "Review and publish the answer",
      "role": "content",
      "text": "Read the exact version you created.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nReview the question and answer. Then publish the version you read.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe publication response identifies the version that agents can retrieve."
    },
    {
      "id": "search-with-a-different-question",
      "title": "Search with a different question",
      "role": "content",
      "text": "Search with a paraphrase of the stored question.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nCheck for your entry identifier, version `1`, and the answer about order history. Scores and rankings vary with the embedding model and other entries. If no match appears, repeat only the search after a short wait, then check the locale filter and [similarity threshold](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/retrieval#control-relevance-and-result-count)."
    },
    {
      "id": "discover-faqs-for-an-agent",
      "title": "Discover FAQs for an agent",
      "role": "content",
      "text": "Discovery returns FAQ answers and skill previews in one request. This example filters for refund guidance to add to the agent's context.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nWith no pins, `pinnedEntries` is empty. Matching published entries appear in `discoveredEntries`. Python exposes these collections as `discovery.pinned` and `discovery.discovered`; `as_prompt()` formats them for agent context. When you add skills later, discovery returns their previews without loading all their instructions."
    },
    {
      "id": "publish-an-updated-answer",
      "title": "Publish an updated answer",
      "role": "content",
      "text": "Append a complete replacement version to the same entry. Include the attributes and intents you want to retain.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe identifier stays the same, and search still serves the first publication. Review and publish the new version, then search again.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]\n\n\n\nThe result for your FAQ should now identify version `2` and include the added sentence about bank posting dates. If it still shows version `1` or is absent, repeat only the search."
    },
    {
      "id": "clean-up",
      "title": "Clean up",
      "role": "content",
      "text": "Keep the sample published while testing [an agent](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/agent-integration). Complete-program copies retain the FAQ. When you finish, set `PLAYBOOK_FAQ_ID` to the printed entry identifier and run the deletion example with the same connection values. [Withdraw it](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs#withdraw-or-delete-an-faq) instead to retain history.\n\n**Available in:** Python (Iris), cURL (Iris), CLI (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n##### cURL (Iris)\n\n[code example]\n\n##### CLI (Iris)\n\n[code example]"
    },
    {
      "id": "use-python-asynchronously",
      "title": "Use Python asynchronously",
      "role": "content",
      "text": "Unified Python helpers use names such as `adiscover` and `askill`. Generated operations on `.client` use an `_async` suffix. This standalone example uses `async with` to close connections after the search. Save it as `async_search.py` and run `python async_search.py` with the same environment variables and a reader key. Keep an FAQ published to test matching.\n\n**Available in:** Python (Iris)\n\n##### Python (Iris)\n\n[code example]\n\n\n\n`AgentPlaybooksSettings.timeout` sets the request timeout in seconds. Generated `.client` operations accept `timeout_ms` in milliseconds. For custom transport settings, construct a generated client and pass it to `AgentPlaybooks(client=...)`. See the [generated client's custom HTTP client documentation](https://pypi.org/project/redis-agent-playbook/#custom-http-client) for ownership and configuration details."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "- [Manage FAQs](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs) to roll back or withdraw an answer.\n- [Manage skills](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-skills) to publish a procedure and load supporting files.\n- [Review proposals](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/proposals) to accept suggested answers before publishing them.\n- [Integrate with an agent](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/agent-integration) to retrieve context before a turn and load skills through MCP."
    }
  ],
  "examples": [
    {
      "id": "connect-to-the-playbook-ex0",
      "language": "bash",
      "code": "python -m venv .venv\n    source .venv/bin/activate\n    python -m pip install 'redis-iris>=1.0.0'",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "connect-to-the-playbook-ex1",
      "language": "dotenv",
      "code": "IRIS_AGENT_PLAYBOOKS_URL='<data-plane-endpoint>'\n    IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID='<playbook-id>'\n    IRIS_AGENT_PLAYBOOKS_API_KEY='<playbook-api-key>'",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "connect-to-the-playbook-ex2",
      "language": "bash",
      "code": "set -a; source .env; set +a",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "connect-to-the-playbook-ex3",
      "language": "python",
      "code": "from redis_iris.agent_playbooks import AgentPlaybooks\n\nplaybook = AgentPlaybooks.from_env()\nprint(playbook.client.get_playbook_health())",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "connect-to-the-playbook-ex4",
      "language": "bash",
      "code": "set -euo pipefail\nPLAYBOOK_API=\"${IRIS_AGENT_PLAYBOOKS_URL%/}/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID\"\ncurl --fail-with-body --silent --show-error \\\n  \"$PLAYBOOK_API/health\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" | jq .",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "connect-to-the-playbook-ex5",
      "language": "bash",
      "code": "set -euo pipefail\n\niris agent-playbooks health",
      "section_id": "connect-to-the-playbook"
    },
    {
      "id": "create-an-faq-ex0",
      "language": "python",
      "code": "faq_content = {\n    \"intents\": [\"Check a refund\", \"Find an existing refund\"],\n    \"attributes\": {\"locale\": \"en-US\", \"topic\": \"refund\"},\n    \"payload\": {\n        \"faq\": {\n            \"question\": \"How do I check the status of a refund?\",\n            \"answer\": (\n                \"Open the order in your order history and select Refund status. \"\n                \"If no refund is listed, contact support with your order number.\"\n            ),\n        }\n    },\n}\ndraft = playbook.client.create_faq(content=faq_content)\nfaq_id = draft.entry.entry_id\nversion = draft.version.version\nprint(faq_id, version, draft.entry.publication)",
      "section_id": "create-an-faq"
    },
    {
      "id": "create-an-faq-ex1",
      "language": "bash",
      "code": "cat > faq.json <<'JSON'\n{\n  \"content\": {\n    \"intents\": [\"Check a refund\", \"Find an existing refund\"],\n    \"attributes\": {\"locale\": \"en-US\", \"topic\": \"refund\"},\n    \"payload\": {\"faq\": {\n      \"question\": \"How do I check the status of a refund?\",\n      \"answer\": \"Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number.\"\n    }}\n  }\n}\nJSON\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/faqs\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' --data-binary @faq.json > draft.json\nFAQ_ID=$(jq -er '.entry.entryId' draft.json)\nVERSION=$(jq -er '.version.version' draft.json)\njq '{entryId: .entry.entryId, version: .version.version, publication: .entry.publication}' draft.json",
      "section_id": "create-an-faq"
    },
    {
      "id": "create-an-faq-ex2",
      "language": "bash",
      "code": "cat > faq.json <<'JSON'\n{\n  \"entryKey\": \"refund-status\",\n  \"question\": \"How do I check the status of a refund?\",\n  \"answer\": \"Open the order in your order history and select Refund status. If no refund is listed, contact support with your order number.\",\n  \"intents\": [\"Check a refund\", \"Find an existing refund\"],\n  \"attributes\": {\"locale\": \"en-US\", \"topic\": \"refund\"}\n}\nJSON\niris agent-playbooks faqs validate faq.json\niris --json agent-playbooks faqs push faq.json > faq-draft.json\nFAQ_ID=$(jq -er '.results[0].entryId' faq-draft.json)\nVERSION=$(jq -er '.results[0].version' faq-draft.json)\njq . faq-draft.json",
      "section_id": "create-an-faq"
    },
    {
      "id": "review-and-publish-the-answer-ex0",
      "language": "python",
      "code": "stored = playbook.client.get_faq_version(faq_id=faq_id, version=version)\nprint(stored.content)",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "review-and-publish-the-answer-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  \"$PLAYBOOK_API/faqs/$FAQ_ID/versions/$VERSION\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" | jq .content",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "review-and-publish-the-answer-ex2",
      "language": "bash",
      "code": "iris --json agent-playbooks faqs show \"$FAQ_ID\" --version \"$VERSION\" | jq .content",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "review-and-publish-the-answer-ex3",
      "language": "python",
      "code": "playbook.client.publish_faq(faq_id=faq_id, version=version)",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "review-and-publish-the-answer-ex4",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PUT \"$PLAYBOOK_API/faqs/$FAQ_ID/publication\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data \"$(jq -n --argjson version \"$VERSION\" '{version: $version}')\" | jq .publication",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "review-and-publish-the-answer-ex5",
      "language": "bash",
      "code": "iris agent-playbooks faqs publish \"$FAQ_ID\" --version \"$VERSION\"",
      "section_id": "review-and-publish-the-answer"
    },
    {
      "id": "search-with-a-different-question-ex0",
      "language": "python",
      "code": "results = playbook.client.search_faqs(\n    query=\"Where can I see how my refund is progressing?\",\n    filter_={\"eq\": {\"name\": \"locale\", \"value\": \"en-US\"}},\n    limit=5,\n)\nfor match in results.items:\n    if match.faq is not None:\n        print(match.entry_id, match.version, match.score, match.faq.answer)",
      "section_id": "search-with-a-different-question"
    },
    {
      "id": "search-with-a-different-question-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/faqs/search\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"query\":\"Where can I see how my refund is progressing?\",\"filter\":{\"eq\":{\"name\":\"locale\",\"value\":\"en-US\"}},\"limit\":5}' \\\n  | jq '.items[] | {entryId, version, score, answer: .faq.answer}'",
      "section_id": "search-with-a-different-question"
    },
    {
      "id": "search-with-a-different-question-ex2",
      "language": "bash",
      "code": "cat > search.json <<'JSON'\n{\n  \"query\": \"Where can I see how my refund is progressing?\",\n  \"filter\": {\"eq\": {\"name\": \"locale\", \"value\": \"en-US\"}},\n  \"limit\": 5\n}\nJSON\niris --json agent-playbooks faqs search --input search.json | jq .items",
      "section_id": "search-with-a-different-question"
    },
    {
      "id": "discover-faqs-for-an-agent-ex0",
      "language": "python",
      "code": "discovery = playbook.discover(\n    \"Help a customer find their refund status\",\n    filter_={\"eq\": {\"name\": \"topic\", \"value\": \"refund\"}},\n)\nprint(discovery.as_prompt())",
      "section_id": "discover-faqs-for-an-agent"
    },
    {
      "id": "discover-faqs-for-an-agent-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/entries/discover\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"query\":\"Help a customer find their refund status\",\"filter\":{\"eq\":{\"name\":\"topic\",\"value\":\"refund\"}},\"limit\":5}' | jq .",
      "section_id": "discover-faqs-for-an-agent"
    },
    {
      "id": "discover-faqs-for-an-agent-ex2",
      "language": "bash",
      "code": "cat > discover.json <<'JSON'\n{\n  \"query\": \"Help a customer find their refund status\",\n  \"filter\": {\"eq\": {\"name\": \"topic\", \"value\": \"refund\"}},\n  \"limit\": 5\n}\nJSON\niris --json agent-playbooks discover --input discover.json | jq .",
      "section_id": "discover-faqs-for-an-agent"
    },
    {
      "id": "publish-an-updated-answer-ex0",
      "language": "python",
      "code": "from copy import deepcopy\n\nupdated_content = deepcopy(faq_content)\nupdated_content[\"payload\"][\"faq\"][\"answer\"] += (\n    \" Support can check the current stage but cannot guarantee a bank posting date.\"\n)\nupdated = playbook.client.append_faq_version(faq_id=faq_id, content=updated_content)\nprint(\"Review this version:\", updated.version.version, updated.version.content)",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "publish-an-updated-answer-ex1",
      "language": "bash",
      "code": "jq '.content.payload.faq.answer += \" Support can check the current stage but cannot guarantee a bank posting date.\"' \\\n  faq.json > faq-update.json\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/faqs/$FAQ_ID/versions\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' --data-binary @faq-update.json > updated.json\njq .version updated.json",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "publish-an-updated-answer-ex2",
      "language": "bash",
      "code": "jq '.answer += \" Support can check the current stage but cannot guarantee a bank posting date.\"' \\\n  faq.json > faq-update.json\niris --json agent-playbooks faqs push faq-update.json > faq-updated.json\nUPDATED_VERSION=$(jq -er '.results[0].version' faq-updated.json)\niris --json agent-playbooks faqs show \"$FAQ_ID\" --version \"$UPDATED_VERSION\" | jq .content",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "publish-an-updated-answer-ex3",
      "language": "python",
      "code": "playbook.client.publish_faq(faq_id=faq_id, version=updated.version.version)\nupdated_results = playbook.client.search_faqs(\n    query=\"Where can I see how my refund is progressing?\",\n    filter_={\"eq\": {\"name\": \"locale\", \"value\": \"en-US\"}},\n    limit=5,\n)\nfor match in updated_results.items:\n    if match.entry_id == faq_id and match.faq is not None:\n        print(\"Published answer:\", match.version, match.faq.answer)",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "publish-an-updated-answer-ex4",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PUT \"$PLAYBOOK_API/faqs/$FAQ_ID/publication\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data \"$(jq '{version: .version.version}' updated.json)\" | jq .publication\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/faqs/search\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data '{\"query\":\"Where can I see how my refund is progressing?\",\"filter\":{\"eq\":{\"name\":\"locale\",\"value\":\"en-US\"}},\"limit\":5}' \\\n  | jq --arg id \"$FAQ_ID\" '.items[] | select(.entryId == $id) | {version, answer: .faq.answer}'",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "publish-an-updated-answer-ex5",
      "language": "bash",
      "code": "iris agent-playbooks faqs publish \"$FAQ_ID\" --version \"$UPDATED_VERSION\"\niris --json agent-playbooks faqs search --input search.json | jq .items",
      "section_id": "publish-an-updated-answer"
    },
    {
      "id": "clean-up-ex0",
      "language": "python",
      "code": "playbook.client.delete_faq(faq_id=faq_id)",
      "section_id": "clean-up"
    },
    {
      "id": "clean-up-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X DELETE \"$PLAYBOOK_API/faqs/$FAQ_ID\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\"",
      "section_id": "clean-up"
    },
    {
      "id": "clean-up-ex2",
      "language": "bash",
      "code": "iris agent-playbooks faqs delete \"$PLAYBOOK_FAQ_ID\" --yes",
      "section_id": "clean-up"
    },
    {
      "id": "use-python-asynchronously-ex0",
      "language": "python",
      "code": "import asyncio\nfrom redis_iris.agent_playbooks import AgentPlaybooks\n\n\nasync def main():\n    async with AgentPlaybooks.from_env() as playbook:\n        results = await playbook.client.search_faqs_async(\n            query=\"Where can I see how my refund is progressing?\",\n            limit=5,\n        )\n        for match in results.items:\n            if match.faq is not None:\n                print(match.faq.answer)\n\n\nasyncio.run(main())",
      "section_id": "use-python-asynchronously"
    }
  ]
}
