Skills Marketplace¶
This notebook demonstrates discovering and using a third-party skill from the Skills Marketplace, a community-curated catalog of reusable agent skills.
We will:
- Install the
slack-gif-creatorskill from its GitHub source into.agents/skills/ - Run an
LLMAgentthat activates the skill to generate an animated GIF
The skill bundles PIL animation utilities and Slack-specific knowledge for creating optimised GIFs. It is sourced from Anthropic's public skills repository and illustrates the core value of a marketplace: a skill authored once by anyone is instantly usable by any agent, anywhere.
Note: Run this notebook from within
more-examples/ch06/so the installed skill is discovered automatically as a project-scoped skill.
Setup Instructions¶
To ensure you have the required dependencies to run this notebook, you'll need to have our llm-agents-from-scratch framework installed on the running Jupyter kernel. To do this, you can launch this notebook with the following command while within the project's root directory:
uv run --with jupyter jupyter lab
Alternatively, if you just want to use the published version of llm-agents-from-scratch without local development, you can install it from PyPI by uncommenting the cell below.
Setting up the LLM¶
I recommend running these notebooks on Ollama Cloud. It serves much larger models than most laptops can run. The default cloud model is picked by benchmarking candidates on these notebooks, and an automated run checks every notebook against it each week. The notebook status page shows the current model and results.
- Create an API key at https://ollama.com/settings/keys.
- Export it before launching Jupyter:
export OLLAMA_API_KEY=<your key>. - That's all. When a notebook builds its LLM, it detects the key and uses Ollama Cloud.
Prefer to run locally? Install Ollama from https://ollama.com/download
and pull the model with ollama pull qwen3:14b. If no key is set, the
notebook starts the Ollama service for you, so there is no need to run
ollama serve. Local models are smaller, so your outputs will differ from
the recorded ones.
Prefer OpenAI or Anthropic?
- Install the extra:
uv sync --extra openaioruv sync --extra anthropic. - Export
OPENAI_API_KEYorANTHROPIC_API_KEYbefore launching Jupyter. If you forget, you will be prompted for it, which keeps the key out of the saved notebook. - Set
LLM_PROVIDER=openai(oranthropic), or passprovider="openai"tomake_llm(). A key on its own never switches providers, so one exported for unrelated work cannot reroute you.
The switch applies wherever a notebook builds its LLM with make_llm().
A notebook that constructs OllamaLLM directly stays on Ollama. Output on
gpt-5 or Claude will differ from the recorded outputs, and prompt-sensitive
examples (the ch09 evaluator pattern, ch08 supervised trajectories) may
behave noticeably differently.
# Uncomment the line below to install `llm-agents-from-scratch` from PyPI
# !pip install llm-agents-from-scratch
import urllib.request
from llm_agents_from_scratch.notebook_utils import make_llm
Skill Dependencies¶
The slack-gif-creator skill uses Python's PIL library and a few imaging helpers to generate animated GIFs. Install them into the running Jupyter kernel before executing the agent cells.
!uv pip install pillow imageio imageio-ffmpeg numpy
Using Python 3.13.5 environment at: /home/nerdai/Projects/llm-agents-from-scratch/.venv ⠋ Resolving dependencies... ⠋ Resolving dependencies... ⠙ Resolving dependencies... ⠙ pillow==12.3.0 ⠙ imageio==2.38.0 ⠙ imageio-ffmpeg==0.6.0 ⠙ numpy==2.4.4 ⠙ Resolved 4 packages in 91ms ⠋ Preparing packages... (0/0) ⠋ Preparing packages... (0/1) ⠙ Preparing packages... (0/1) ⠙ Preparing packages... (0/1) imageio ------------------------------ 0 B/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 16.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 32.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 48.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 64.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 80.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 96.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 112.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 128.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 144.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 160.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 176.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 192.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 208.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 224.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 240.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) imageio ------------------------------ 256.00 KiB/320.37 KiB ⠙ Preparing packages... (0/1) Prepared 1 package in 34ms ░░░░░░░░░░░░░░░░░░░░ [0/0] Installing wheels... ░░░░░░░░░░░░░░░░░░░░ [0/2] Installing wheels... ░░░░░░░░░░░░░░░░░░░░ [0/2] imageio-ffmpeg==0.6.0 ██████████░░░░░░░░░░ [1/2] imageio-ffmpeg==0.6.0 ██████████░░░░░░░░░░ [1/2] imageio==2.38.0 ████████████████████ [2/2] imageio==2.38.0 Installed 2 packages in 7ms + imageio==2.38.0 + imageio-ffmpeg==0.6.0
The Skill¶
The slack-gif-creator skill is listed on the Skills Marketplace. It originates from Anthropic's skills repository and has been widely forked across the community. We will install whichever copy is currently ranked highest by stars.
The skill bundles:
SKILL.md— instructions and animation knowledge for the agentcore/— Python modules (GIFBuilder, easing functions, validators, frame helpers)
Searching the Marketplace¶
The SkillsMP REST API lets you search the catalog programmatically. The query below shows how widely a single skill can spread across the community — dozens of repos have forked or mirrored slack-gif-creator.
import json
from urllib.parse import urlparse
SKILLSMP_API = "https://skillsmp.com/api/v1"
with urllib.request.urlopen(
f"{SKILLSMP_API}/skills/search?q=slack-gif-creator&limit=5&sortBy=stars",
) as resp:
data = json.loads(resp.read())
total = data["data"]["pagination"]["total"]
print(f"Found {total} results for 'slack-gif-creator'. Top 5:\n")
for s in data["data"]["skills"]:
print(f" {s['name']} ({s['stars']} ⭐️) — {s['githubUrl']}")
Found 6 results for 'slack-gif-creator'. Top 5: slack-gif-creator (177502 ⭐️) — https://github.com/anthropics/skills/tree/main/skills/slack-gif-creator slack-gif-creator (97471 ⭐️) — https://github.com/nexu-io/open-design/tree/main/skills/slack-gif-creator slack-gif-creator (59734 ⭐️) — https://github.com/BerriAI/litellm/tree/main/tests/llm_translation/test_skills_data/slack-gif-creator slack-gif-creator (3512 ⭐️) — https://github.com/davepoon/buildwithclaude/tree/main/plugins/all-skills/skills/slack-gif-creator slack-gif-creator (3045 ⭐️) — https://github.com/MiniMax-AI/Mini-Agent/tree/main/mini_agent/skills/slack-gif-creator
# Use the top-starred result as the install source
top_skill = data["data"]["skills"][0]
parts = urlparse(top_skill["githubUrl"]).path.lstrip("/").split("/")
# path format: {owner}/{repo}/tree/{branch}/{skill/path...}
REPO = f"{parts[0]}/{parts[1]}"
BRANCH = parts[3]
SKILL_PATH = "/".join(parts[4:])
print(f"\nInstalling from: {top_skill['githubUrl']}")
Installing from: https://github.com/anthropics/skills/tree/main/skills/slack-gif-creator
Installing the Skill¶
We use the GitHub contents API to fetch only the skill's subdirectory i.e. no need to download the entire repository. The files will land in .agents/skills/slack-gif-creator/, which LLMAgent discovers automatically as a project-scoped skill.
from pathlib import Path
skill_dir = Path(".agents/skills/slack-gif-creator")
skill_dir.mkdir(parents=True, exist_ok=True)
def _install(api_path: str, local_dest: Path) -> None:
url = (
f"https://api.github.com/repos/{REPO}/contents/{api_path}?ref={BRANCH}"
)
with urllib.request.urlopen(url) as resp:
items = json.loads(resp.read())
for item in items:
dest = local_dest / item["name"]
if item["type"] == "file":
with urllib.request.urlopen(item["download_url"]) as resp:
dest.write_bytes(resp.read())
print(f" {dest.relative_to(skill_dir)}")
elif item["type"] == "dir":
dest.mkdir(exist_ok=True)
_install(item["path"], dest)
_install(SKILL_PATH, skill_dir)
print(f"\nInstalled to: {skill_dir.resolve()}")
LICENSE.txt SKILL.md core/easing.py core/frame_composer.py core/gif_builder.py core/validators.py requirements.txt Installed to: /home/nerdai/Projects/llm-agents-from-scratch/more-examples/ch06/.agents/skills/slack-gif-creator
Inspecting the Skill¶
Before running the agent, let's confirm the skill was discovered and take a look at its SKILL.md.
import logging
from llm_agents_from_scratch import TOOLS_FOR_SKILL_RESOURCES, LLMAgent
from llm_agents_from_scratch.data_structures import Task
from llm_agents_from_scratch.logger import enable_console_logging
enable_console_logging(logging.INFO)
llm = make_llm()
agent = LLMAgent(llm=llm, tools=TOOLS_FOR_SKILL_RESOURCES)
task = Task(instruction="placeholder")
handler = LLMAgent.TaskHandler(llm_agent=agent, task=task)
skill = handler.skills_registry["slack-gif-creator"]
print(f"Name: {skill.frontmatter.name}")
print(f"Scope: {skill.scope}")
print(f"Skill dir: {skill_dir.resolve()}")
print("\nResources:")
for r in skill.resources:
print(f" - {r}")
print()
print("--- Body ---")
print(skill.read_body()[:500])
print("--- TRUNCATED ---")
✓ Using Ollama Cloud (kimi-k2.7-code:cloud) Name: slack-gif-creator Scope: SkillScope.PROJECT Skill dir: /home/nerdai/Projects/llm-agents-from-scratch/more-examples/ch06/.agents/skills/slack-gif-creator Resources: --- Body --- # Slack GIF Creator A toolkit providing utilities and knowledge for creating animated GIFs optimized for Slack. ## Slack Requirements **Dimensions:** - Emoji GIFs: 128x128 (recommended) - Message GIFs: 480x480 **Parameters:** - FPS: 10-30 (lower is smaller file size) - Colors: 48-128 (fewer = smaller file size) - Duration: Keep under 3 seconds for emoji GIFs ## Core Workflow ```python from core.gif_builder import GIFBuilder from PIL import Image, ImageDraw # 1. Create builder builder = GI --- TRUNCATED ---
Generating a GIF¶
Now we run the agent with the slack-gif-creator skill. The agent will:
- Activate the skill via
UseSkillToolto read its instructions - Write PIL animation code based on the prompt
- Execute it with
PythonInterpreterToolusingcode=andcwd=skill_dirso the bundledcore/modules are importable - Save the result as
output.gifinside the skill directory
OUTPUT_GIF = Path.cwd().resolve() / "output.gif"
result = await agent.run_with_skill(
"slack-gif-creator",
prompt=(
"Create a spinning star emoji GIF (128x128 px, optimized for Slack)."
f" Save the output to {OUTPUT_GIF}."
" After reading the skill instructions, write the animation code and"
" execute it immediately using the from_scratch__python_interpreter"
" tool with your code as the 'code' parameter and"
f" cwd='{skill_dir.resolve()}'.",
),
max_steps=10,
)
print(result)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: This is a user-explicit skill activation. Call the from_scratch__use_skill tool with name='slack-gif-creator'. Use exactly this name ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: This is a user-explicit skill activation. Call the from_scratch__use_skill tool with name='slack-gif-creator'. Use exactly this na...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__use_skill
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: <skill_content name="slack-gif-creator">
# Slack GIF Creator
A toolkit providing utilities and knowledge for creating animate...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "cc3bc8e9-4bd9-481d-bfa1-7ddfdc3df95f",
"tool_name": "from_scratch__python_in...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the planned from_scratch__python_interpreter tool call using the provided code to generate the 128x128 spinning star emoji GIF and...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the planned from_scratch__python_interpreter tool call using the provided code to generate the 128x128 spinning star emoji...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__python_interpreter
INFO (llm_agents_fs.TaskHandler) : ❌ Tool Call Failure: {"error_type": "RuntimeError", "message": "Traceback (most recent call last):\n File \u001b[35m\"/home/nerdai/Projects/llm-agent...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "ace09f1d-149c-48d1-83ba-117db108cceb",
"tool_name": "from_scratch__read_file...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Read /home/nerdai/Projects/llm-agents-from-scratch/more-examples/ch06/.agents/skills/slack-gif-creator/core/frame_composer.py to inspect t...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Read /home/nerdai/Projects/llm-agents-from-scratch/more-examples/ch06/.agents/skills/slack-gif-creator/core/frame_composer.py to i...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__read_file
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: #!/usr/bin/env python3
"""
Frame Composer - Utilities for composing visual elements into frames.
Provides functions for drawi...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: I need to make the following tool-calls:
{
"id_": "4ef09e10-651b-4efd-9913-3f7bd36dbe2c",
"tool_name": "from_scratch__python_in...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🧠 New Step: Execute the planned from_scratch__python_interpreter tool call using the corrected draw_star parameters (size instead of radius, fill_colo...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Execute the planned from_scratch__python_interpreter tool call using the corrected draw_star parameters (size instead of radius, f...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: from_scratch__python_interpreter
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: Reducing frames from 37 to ~12 for emoji size
✓ GIF created successfully!
Path: /home/nerdai/Projects/llm-agents-from-scr...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: The GIF was generated successfully.
**Summary:**
- Created a 128x128 spinning gold-star emoji GIF with a glowing purple gradient backg...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : No new step required.
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: The GIF was generated successfully.
**Summary:**
- Created a 128x128 spinning gold-star emoji GIF with a glowing purple gradient ba...[TRUNCATED]
The GIF was generated successfully.
**Summary:**
- Created a 128x128 spinning gold-star emoji GIF with a glowing purple gradient background.
- Saved to `/home/nerdai/Projects/llm-agents-from-scratch/more-examples/ch06/output.gif`.
- Animation uses the corrected `draw_star` signature (`size`, `fill_color`, `outline_color`, `outline_width`) and rotates each frame for a smooth spin plus a subtle pulse.
- Final output was optimized by the GIFBuilder for Slack emoji:
- **Dimensions:** 128×128
- **File size:** 55.8 KB
- **Frames:** 13
- **Duration:** ~0.8 s
- **Colors:** 48
- Validation passed as Slack-ready emoji GIF.
Result¶
import base64
from IPython.display import HTML
with open(OUTPUT_GIF, "rb") as f:
data = base64.b64encode(f.read()).decode()
HTML(f'<img src="data:image/gif;base64,{data}">')
Note on Third-Party Skills¶
The slack-gif-creator skill was authored for Claude Code, which has native file-write and execution tools. Our framework's execution model is different — the agent uses PythonInterpreterTool with an inline code parameter — so we had to augment the prompt with explicit instructions about which tool to use and how.
This is expected when pulling skills from a marketplace: the skill encodes domain knowledge and logic, but the execution conventions may differ across agent frameworks. A small prompt addition is usually enough to bridge the gap.