{
  "schema_version": 2,
  "id": "develop/ai/context-engine/agent-playbooks/manage-skills",
  "title": "Manage skills",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-skills/",
  "summary": "Package, validate, upload, version, and publish reusable agent skills.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-02T15:54:35-08:00",
  "page_type": "content",
  "content_hash": "66dcc18ef7d3879467710d3c2c46c2e6aff8d39e35b4b0fac912c735f2d8adc8",
  "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\nA skill tells an agent how to complete a task: what inputs or tools to use, which decisions to make, and what to return. This example drafts a customer reply by choosing and filling a refund template."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "Use an existing playbook and an API key with `write` permission to upload and maintain skills. Publishing and withdrawing require `publish`.\n\nFollow the quickstart to [install a client and configure it](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/quickstart#before-you-begin). You also need Bash and the `zip` utility for the sample package.\n\nExpand an example to copy the complete program. Run the package-preparation step before using a Python or CLI copy."
    },
    {
      "id": "prepare-a-skill-package",
      "title": "Prepare a skill package",
      "role": "content",
      "text": "Package skills using the [Agent Skills specification](https://agentskills.io/specification). Each directory contains `SKILL.md` with frontmatter and Markdown instructions. The required `name` matches the directory name; the required `description` explains the task and when to use the skill.\n\nMake the task and its conditions explicit in the description: semantic matching uses the skill's name and description. In the instructions, specify inputs, decisions, and expected output. Put tool requirements in `compatibility`. Reference supporting files by paths relative to the skill root, with a reason to read each one.\n\n“Help with refunds” is too broad: it overlaps refund requests and status questions. “Draft a customer reply from a reported refund stage or a missing refund” identifies the task and its inputs.\n\nTo prepare an upload:\n\n1. Validate the directory against the Agent Skills specification.\n2. Check that every referenced file is included and each path is relative to the skill root.\n3. Create a ZIP archive containing exactly one skill directory.\n4. Encode the archive as base64 for the upload request.\n\nRedis Agent Playbooks also enforce [package and content limits](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/limits#content-limits).\n\nRun these commands in a new directory. The sample uses customer-provided information without accessing an order system. Adapt its guidance to your policy.\n\n**Available in:** cURL (Iris)\n\n##### cURL (Iris)\n\n[code example]\n\n\n\nRun this Bash preparation step for every language. SDK and cURL examples upload the ZIP. The CLI reads the `refund-support-reply` directory and packages it for you. Its `.iris-playbook.json` sidecar supplies intents, attributes, and metadata without changing `SKILL.md`."
    },
    {
      "id": "upload-and-validate-a-skill",
      "title": "Upload and validate a skill",
      "role": "content",
      "text": "Create an entry with `create_skill`. Supply the base64-encoded archive with intents, attributes, and metadata.\n\nUpload validation rejects invalid frontmatter, a mismatched root name, unsafe or duplicate paths, symbolic links, special files such as device files, and content exceeding its limits. Regular text and binary files are supported. Include only the skill directory in the archive.\n\nSave the returned entry identifier so later uploads update the same skill.\n\nValidation checks structure and limits, not whether the procedure suits its audience. Review its accuracy before publishing. Your application controls script execution and tool permissions.\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 CLI uses the skill name as its stable entry key. `skills push` creates missing content, appends changed content, and skips unchanged content. It leaves publication unchanged unless you request publication."
    },
    {
      "id": "review-and-publish-a-version",
      "title": "Review and publish a version",
      "role": "content",
      "text": "1. Retrieve the exact version returned by the upload.\n2. Review its name, description, instructions, and resource descriptors.\n3. Read the supporting files needed to assess the procedure.\n4. Publish the reviewed version with `publish_skill`.\n5. Test retrieval with a reader key, then test the agent's use of the skill.\n\nUploading a valid package does not publish it automatically. To review a suggestion before creating an entry, use a [skill proposal](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/proposals#review-skill-proposals).\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\nPublish after review. The [agent-integration examples](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/agent-integration) ask an agent to draft a reply for the stage “Processing.” Check that it loads this skill and template, preserves the stage, and leaves no placeholders or invented payment date. Also test a missing refund and missing input.\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": "update-a-skill",
      "title": "Update a skill",
      "role": "content",
      "text": "Use `append_skill_version` to update the existing entry. Supply the complete package and the intents, attributes, and metadata you want to retain.\n\nThe identifier stays the same. Agents use the previous publication until you review and publish the new version.\n\nTo roll back, publish an earlier version. Concurrent publication changes are last-write-wins, so coordinate publishers.\n\nThis example adds a `channel` attribute for chat retrieval and keeps the same instructions. To change the instructions or files, edit the directory and create a fresh ZIP archive before uploading.\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\nLeave the update unpublished here so the loading example uses the first version. Publishing the update makes its new attributes available to filters."
    },
    {
      "id": "load-instructions-and-files",
      "title": "Load instructions and files",
      "role": "content",
      "text": "Search and discovery return previews: a name, description, entry identifier, version, and file address. Select a relevant skill before loading its instructions. Fetch supporting files when the instructions or task call for them.\n\nKeep the returned identifier and version together, and use the returned resource addresses. If the skill is republished or withdrawn between discovery and loading, rediscover and reassess it. See [Retrieve knowledge](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/retrieval) and [Connect with MCP](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/mcp).\n\nResource descriptors identify the file's media type, size, and digest. Decode known text files as UTF-8 (Unicode Transformation Format, 8-bit); keep binary files as bytes. Python's unified helper reads the stream and exposes `data`, `mime_type`, and optional decoded `text`.\n\nThis example loads the first published version and reads its reply template.\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\nThis guide's CLI reads use the authoring key. The published CLI resolves the entry through management lookup, so these commands require `write` or `publish` even for a published version. For reader-only loading, use the [retrieval examples](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/retrieval#load-skills-with-progressive-disclosure).\n\nTo verify file content, compare the descriptor's SHA-256 (Secure Hash Algorithm 256-bit) digest with the downloaded bytes. It uses `sha256:<hex>`; the HTTP `Content-Digest` header represents the same hash as `sha-256=:<base64>:`. This differs from the normalized entry digest in [entry lookup](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs#look-up-entry-state)."
    },
    {
      "id": "list-skills-and-inspect-history",
      "title": "List skills and inspect history",
      "role": "content",
      "text": "Use `list_skills` to inventory entries and `get_skill` to inspect one entry's summary. These operations require `read`; draft content and full version history require `write` or `publish`. To resolve a skill by its entry key or compare latest and published content digests, use the shared [entry lookup operation](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/manage-faqs#look-up-entry-state).\n\nFollow cursors even after empty pages, and keep filters and ordering unchanged. Responses return `items` and `nextCursor` and don't include a total count. See [pagination behavior](https://redis.io/docs/latest/develop/ai/context-engine/agent-playbooks/limits#retrieval-limits).\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\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\nRead the complete versions newest first. Use a returned version number when reviewing or rolling back a publication:\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\nCLI lists and history follow cursors automatically. Use `--page` and `--cursor` to inspect individual pages. CLI version JSON currently omits `contentDigest`; use an SDK or cURL tab to inspect digests."
    },
    {
      "id": "withdraw-or-delete-a-skill",
      "title": "Withdraw or delete a skill",
      "role": "content",
      "text": "Withdraw the publication with `withdraw_skill` to stop serving the procedure while keeping its history. Delete the entry with `delete_skill` when you want to remove all its versions and files permanently.\n\nComplete-program copies retain the skill. For withdrawal or deletion, set `PLAYBOOK_SKILL_ID` to the printed identifier and run the selected example with the same connection values.\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\nTo remove the sample and its files permanently:\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]"
    }
  ],
  "examples": [
    {
      "id": "prepare-a-skill-package-ex0",
      "language": "bash",
      "code": "mkdir -p refund-support-reply/references\ncat > refund-support-reply/SKILL.md <<'SKILL'\n---\nname: refund-support-reply\ndescription: Draft a customer reply for an existing refund using a reported refund stage or a report that no refund is listed. Use the matching reply template. Do not use to request a new refund.\n---\n\n# Draft a refund support reply\n\n1. Check whether the customer supplied a displayed refund stage or said no refund is listed. If neither is known, ask what their order history shows before drafting a reply.\n2. Read references/reply-template.md for the listed and missing refund templates.\n3. If a stage is supplied, choose the listed refund template and replace <displayed-stage> with that exact stage.\n4. If no refund is listed, choose the missing refund template. Do not invent a stage.\n5. Return only the completed customer reply. Do not leave placeholders in it.\n\nDo not claim to have accessed the order system, claim a refund was issued, or promise a bank posting date.\nSKILL\ncat > refund-support-reply/references/reply-template.md <<'TEMPLATE'\nRefund listed: Your order history shows \"<displayed-stage>\". Support can help if you need more information about that stage.\n\nRefund missing: Contact support with your order number and explain that no refund appears in your order history.\nTEMPLATE\nzip -r refund-support-reply.zip refund-support-reply",
      "section_id": "prepare-a-skill-package"
    },
    {
      "id": "upload-and-validate-a-skill-ex0",
      "language": "python",
      "code": "import base64\nfrom pathlib import Path\n\npackage_base64 = base64.b64encode(Path(\"refund-support-reply.zip\").read_bytes()).decode(\"ascii\")\nskill_context = {\n    \"intents\": [\"Draft a refund support reply\", \"Choose a refund reply template\"],\n    \"attributes\": {\"locale\": \"en-US\", \"topic\": \"refund\"},\n}\nskill_draft = playbook.client.create_skill(package_base64=package_base64, content=skill_context)\nskill_id = skill_draft.entry.entry_id\nskill_version = skill_draft.version.version\nprint(skill_id, skill_version)",
      "section_id": "upload-and-validate-a-skill"
    },
    {
      "id": "upload-and-validate-a-skill-ex1",
      "language": "bash",
      "code": "base64 < refund-support-reply.zip | tr -d '\\r\\n' > package.b64\njq -n --rawfile package package.b64 '{\n  packageBase64: $package,\n  content: {\n    intents: [\"Draft a refund support reply\", \"Choose a refund reply template\"],\n    attributes: {locale: \"en-US\", topic: \"refund\"}\n  }\n}' > skill.json\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/skills\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' --data-binary @skill.json > skill-draft.json\nSKILL_ID=$(jq -er '.entry.entryId' skill-draft.json)\nSKILL_VERSION=$(jq -er '.version.version' skill-draft.json)\njq .version skill-draft.json",
      "section_id": "upload-and-validate-a-skill"
    },
    {
      "id": "upload-and-validate-a-skill-ex2",
      "language": "bash",
      "code": "cat > refund-support-reply/.iris-playbook.json <<'JSON'\n{\n  \"intents\": [\"Draft a refund support reply\", \"Choose a refund reply template\"],\n  \"attributes\": {\"locale\": \"en-US\", \"topic\": \"refund\"}\n}\nJSON\niris agent-playbooks skills validate refund-support-reply\niris --json agent-playbooks skills push refund-support-reply > skill-draft.json\nSKILL_ID=$(jq -er '.results[0].entryId' skill-draft.json)\nSKILL_VERSION=$(jq -er '.results[0].version' skill-draft.json)\njq . skill-draft.json",
      "section_id": "upload-and-validate-a-skill"
    },
    {
      "id": "review-and-publish-a-version-ex0",
      "language": "python",
      "code": "stored_skill = playbook.client.get_skill_version(skill_id=skill_id, version=skill_version)\nprint(stored_skill.content)",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "review-and-publish-a-version-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  \"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" | jq .content",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "review-and-publish-a-version-ex2",
      "language": "bash",
      "code": "iris --json agent-playbooks skills show \"$SKILL_ID\" --version \"$SKILL_VERSION\" | jq .content",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "review-and-publish-a-version-ex3",
      "language": "python",
      "code": "playbook.client.publish_skill(skill_id=skill_id, version=skill_version)",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "review-and-publish-a-version-ex4",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X PUT \"$PLAYBOOK_API/skills/$SKILL_ID/publication\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  --data \"$(jq -n --argjson version \"$SKILL_VERSION\" '{version: $version}')\" | jq .publication",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "review-and-publish-a-version-ex5",
      "language": "bash",
      "code": "iris agent-playbooks skills publish \"$SKILL_ID\" --version \"$SKILL_VERSION\"",
      "section_id": "review-and-publish-a-version"
    },
    {
      "id": "update-a-skill-ex0",
      "language": "python",
      "code": "from copy import deepcopy\n\nupdated_context = deepcopy(skill_context)\nupdated_context[\"attributes\"][\"channel\"] = \"chat\"\nreplacement = base64.b64encode(Path(\"refund-support-reply.zip\").read_bytes()).decode(\"ascii\")\nskill_update = playbook.client.append_skill_version(\n    skill_id=skill_id,\n    package_base64=replacement,\n    content=updated_context,\n)\nprint(\"Review before publishing:\", skill_update.version)",
      "section_id": "update-a-skill"
    },
    {
      "id": "update-a-skill-ex1",
      "language": "bash",
      "code": "base64 < refund-support-reply.zip | tr -d '\\r\\n' > package.b64\njq --rawfile package package.b64 \\\n  '.packageBase64 = $package | .content.attributes.channel = \"chat\"' \\\n  skill.json > skill-update.json\ncurl --fail-with-body --silent --show-error \\\n  -X POST \"$PLAYBOOK_API/skills/$SKILL_ID/versions\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \\\n  -H 'Content-Type: application/json' --data-binary @skill-update.json | jq .version",
      "section_id": "update-a-skill"
    },
    {
      "id": "update-a-skill-ex2",
      "language": "bash",
      "code": "jq '.attributes.channel = \"chat\"' refund-support-reply/.iris-playbook.json > skill-context.json\nmv skill-context.json refund-support-reply/.iris-playbook.json\niris --json agent-playbooks skills push refund-support-reply > skill-updated.json\nUPDATED_VERSION=$(jq -er '.results[0].version' skill-updated.json)\niris --json agent-playbooks skills show \"$SKILL_ID\" --version \"$UPDATED_VERSION\" | jq .content",
      "section_id": "update-a-skill"
    },
    {
      "id": "load-instructions-and-files-ex0",
      "language": "python",
      "code": "skill = playbook.skill(skill_id, version=skill_version)\nprint(skill.instructions)\nresource = next((r for r in skill.resources if r.path == \"references/reply-template.md\"), None)\nif resource is None:\n    raise ValueError(\"Reply template is missing\")\nresponse = playbook.skill_resource(\n    skill_id, resource.resource_id, version=skill_version\n)\nprint(response.text)",
      "section_id": "load-instructions-and-files"
    },
    {
      "id": "load-instructions-and-files-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  \"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" > selected-skill.json\njq -r '.content.payload.skill.instructions' selected-skill.json\nRESOURCE_ID=$(jq -er '.content.payload.skill.resources[] | select(.path == \"references/reply-template.md\") | .resourceId' selected-skill.json)\ncurl --fail-with-body --silent --show-error \\\n  \"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION/resources/$RESOURCE_ID\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\"",
      "section_id": "load-instructions-and-files"
    },
    {
      "id": "load-instructions-and-files-ex2",
      "language": "bash",
      "code": "iris --json agent-playbooks skills show \"$SKILL_ID\" --version \"$SKILL_VERSION\" > selected-skill.json\njq -r '.content.payload.skill.instructions' selected-skill.json\niris agent-playbooks skills resource get \"$SKILL_ID\" references/reply-template.md \\\n  --version \"$SKILL_VERSION\" --output reply-template.txt --force\ncat reply-template.txt",
      "section_id": "load-instructions-and-files"
    },
    {
      "id": "list-skills-and-inspect-history-ex0",
      "language": "python",
      "code": "cursor = None\nwhile True:\n    page = playbook.client.list_skills(sort_by=\"updatedAt\", sort_order=\"DESC\", limit=50, cursor=cursor)\n    for entry in page.items:\n        print(entry.entry_id, entry.latest_version, entry.publication)\n    cursor = page.next_cursor\n    if cursor is None:\n        break",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex1",
      "language": "bash",
      "code": "CURSOR=''\nwhile true; do\n  PAGE_ARGS=(--data-urlencode sortBy=updatedAt --data-urlencode sortOrder=DESC --data-urlencode limit=50)\n  if [[ -n \"$CURSOR\" ]]; then PAGE_ARGS+=(--data-urlencode \"cursor=$CURSOR\"); fi\n  curl --fail-with-body --silent --show-error --get \"$PLAYBOOK_API/skills\" \\\n    -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \"${PAGE_ARGS[@]}\" > skill-page.json\n  jq '.items[] | {entryId, latestVersion, publication}' skill-page.json\n  CURSOR=$(jq -r '.nextCursor // empty' skill-page.json)\n  [[ -n \"$CURSOR\" ]] || break\ndone",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex2",
      "language": "bash",
      "code": "iris --json agent-playbooks skills list --sort-by updatedAt --sort-order desc --page-size 50 | jq .",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex3",
      "language": "python",
      "code": "entry = playbook.client.get_skill(skill_id=skill_id)\nprint(entry.latest_version, entry.publication)",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex4",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \"$PLAYBOOK_API/skills/$SKILL_ID\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" | jq '{latestVersion, publication}'",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex5",
      "language": "bash",
      "code": "iris --json agent-playbooks skills list --sort-by updatedAt --sort-order desc --page-size 50 \\\n  | jq --arg id \"$SKILL_ID\" '.[] | select(.entryId == $id)'",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex6",
      "language": "python",
      "code": "cursor = None\nwhile True:\n    page = playbook.client.list_skill_versions(skill_id=skill_id, limit=50, cursor=cursor)\n    for item in page.items:\n        print(item.version, item.content_digest, item.content)\n    cursor = page.next_cursor\n    if cursor is None:\n        break",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex7",
      "language": "bash",
      "code": "CURSOR=''\nwhile true; do\n  PAGE_ARGS=(--data-urlencode limit=50)\n  if [[ -n \"$CURSOR\" ]]; then PAGE_ARGS+=(--data-urlencode \"cursor=$CURSOR\"); fi\n  curl --fail-with-body --silent --show-error --get \"$PLAYBOOK_API/skills/$SKILL_ID/versions\" \\\n    -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" \"${PAGE_ARGS[@]}\" > skill-versions.json\n  jq '.items[] | {version, contentDigest, content}' skill-versions.json\n  CURSOR=$(jq -r '.nextCursor // empty' skill-versions.json)\n  [[ -n \"$CURSOR\" ]] || break\ndone",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "list-skills-and-inspect-history-ex8",
      "language": "bash",
      "code": "iris --json agent-playbooks skills versions \"$SKILL_ID\" --page-size 50 | jq .",
      "section_id": "list-skills-and-inspect-history"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex0",
      "language": "python",
      "code": "playbook.client.withdraw_skill(skill_id=skill_id)",
      "section_id": "withdraw-or-delete-a-skill"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex1",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X DELETE \"$PLAYBOOK_API/skills/$SKILL_ID/publication\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\" | jq .",
      "section_id": "withdraw-or-delete-a-skill"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex2",
      "language": "bash",
      "code": "iris agent-playbooks skills withdraw \"$PLAYBOOK_SKILL_ID\"",
      "section_id": "withdraw-or-delete-a-skill"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex3",
      "language": "python",
      "code": "playbook.client.delete_skill(skill_id=skill_id)",
      "section_id": "withdraw-or-delete-a-skill"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex4",
      "language": "bash",
      "code": "curl --fail-with-body --silent --show-error \\\n  -X DELETE \"$PLAYBOOK_API/skills/$SKILL_ID\" \\\n  -H \"Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY\"",
      "section_id": "withdraw-or-delete-a-skill"
    },
    {
      "id": "withdraw-or-delete-a-skill-ex5",
      "language": "bash",
      "code": "iris agent-playbooks skills delete \"$PLAYBOOK_SKILL_ID\" --yes",
      "section_id": "withdraw-or-delete-a-skill"
    }
  ]
}
