Skip to main content
After Wrangler (or you) finalizes a Skill Collection in the dashboard, your coding agent loads skills from files on disk. Use client.skills.pull() to fetch the collection, then write the files to your project.
You can generate these exact snippets for your own collection from the dashboard: open a Skill Collection and click Pull via SDK.

Prerequisites

Set your API key in the environment:
export PROMPTLAYER_API_KEY="your_promptlayer_api_key"

Pull as a folder of files

skills.pull() returns a response with a files map (path → text content). For provider-specific collections, those paths already include the provider prefix (.claude/..., .agents/..., or .openclaw/...), so the simplest thing to do is write each file at its returned path from your project root. Everything lands where your agent expects it.
# pip install -U promptlayer
import os
from pathlib import Path

from promptlayer import PromptLayer

client = PromptLayer(api_key=os.environ["PROMPTLAYER_API_KEY"])

result = client.skills.pull("my-collection")
if result is None:
    raise ValueError("No skill collection returned.")

for relative_path, content in result["files"].items():
    output_path = Path(relative_path)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    output_path.write_text(content, encoding="utf-8")
For a Claude Code collection, this produces .claude/CLAUDE.md, .claude/skills/<name>/SKILL.md, etc. For Codex, you get .agents/AGENTS.md, and for OpenClaw you get .openclaw/.... Universal collections have no prefix and land in your project root as-is.

Writing to a custom directory

If you want to rename the output directory (for example, write a Claude Code collection under .agents instead of .claude), strip the known provider prefix from each path and join the remainder to your target directory:
output_dir = Path("custom-dir")
prefix = ".claude/"  # your collection's provider prefix

for relative_path, content in result["files"].items():
    target = relative_path[len(prefix):] if relative_path.startswith(prefix) else relative_path
    output_path = output_dir / target
    output_path.parent.mkdir(parents=True, exist_ok=True)
    output_path.write_text(content, encoding="utf-8")
ProviderPrefix in response paths
Claude Code.claude/
OpenAI / Codex.agents/
OpenClaw.openclaw/
Universal(no prefix)

Pin a version or release label

Pass version= or label= to pull an immutable snapshot instead of latest.
client.skills.pull("my-collection", version=12)
client.skills.pull("my-collection", label="production")

Pull as a zip archive

Pass format="zip" to get a binary archive instead of a JSON file map. The archive already contains the provider’s on-disk layout, so unzip it at your project root.
import os
from pathlib import Path

from promptlayer import PromptLayer

client = PromptLayer(api_key=os.environ["PROMPTLAYER_API_KEY"])

zip_archive = client.skills.pull("my-collection", format="zip")
if not isinstance(zip_archive, bytes):
    raise ValueError("Expected a zip archive.")

Path("skills.zip").write_bytes(zip_archive)

Raw REST API

Use GET against the public API when you are not using an SDK:
GET https://api.promptlayer.com/api/public/v2/skill-collections/<identifier>
Optional query parameters:
ParameterPurpose
format=zipReturn a zip archive instead of JSON
version=<n>Pin to a specific version number
label=<name>Pin to a release label
File paths in the JSON response follow the same convention as the SDK: provider-specific collections include the .claude/, .agents/, or .openclaw/ prefix; universal collections are root-relative. Zip exports always include the provider layout.

Skill Collection webhooks

Skill Collections emit a skill_collection_files_changed event when a collection is created, saved, deleted, or restored. To subscribe and verify signatures, see Webhooks.

CI pattern

Run skills.pull in your build or deploy pipeline with a pinned label (for example production) so your agent loads a stable snapshot instead of whatever was latest when the job last ran.
For more on labels and review, see Tune skills for your team.