#!/usr/bin/env python3
"""End-to-end demo: task description -> SkillHub -> skill -> agent prompt.
SkillHub serves the corpus over three tiers, cheapest first:
1. GET /openapi/v1/skills?q=... metadata only, no body (cheap)
2. GET /openapi/v1/skills/{ref} adds skill_md + subscores (cheap)
3. GET /openapi/v1/skills/{ref}/download zip with scripts/assets (only if needed)
Most skills are pure instructions — tier 2 is enough, and its `skill_md` is what
you inject into the agent prompt. Only download when a skill ships scripts you
actually intend to execute.
Usage:
# search + read the bodies (no install, no API key)
python examples/skillhub_demo.py "extract tables from a scanned PDF invoice"
# run the task with the skill bodies injected — any OpenAI-compatible endpoint
export OPENAI_API_KEY=... # your provider's key
python examples/skillhub_demo.py --ask "extract tables from a scanned PDF invoice"
# e.g. OpenRouter (or a local vLLM / Together / …): set the base URL + model
export OPENAI_BASE_URL=https://openrouter.ai/api/v1
python examples/skillhub_demo.py --ask --model openai/gpt-4o-mini "…"
# fetch the bundled scripts of the top hit into ./skills/
python examples/skillhub_demo.py --install ./skills "convert a PDF to images"
Environment:
SKILLHUB_URL base URL (default: https://skillhub.evermind.ai)
SKILLHUB_TOKEN bearer token (optional; public skills need none)
OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL only for --ask; any
OpenAI-compatible provider works (OpenAI, OpenRouter, a local vLLM, …)
Stdlib only — no dependency on the skillcorpus package.
"""
from __future__ import annotations
import argparse
import json
import os
import sys
import textwrap
import urllib.error
import urllib.parse
import urllib.request
import zipfile
BASE = os.environ.get("SKILLHUB_URL", "https://skillhub.evermind.ai").rstrip("/")
API = "/openapi/v1"
# status codes carried inside the JSON envelope (HTTP status mirrors them)
_STATUS_TEXT = {
60001: "skill not found",
60002: "invalid parameter",
60003: "download failed",
60005: "rate limited — search/detail allow 120/min, download 30/min per IP",
20001: "internal error",
}
def _get(path: str, params: dict | None = None, raw: bool = False):
"""GET . Unwraps the JSON envelope unless ``raw`` (zip bytes)."""
url = f"{BASE}{path}"
if params:
url += "?" + urllib.parse.urlencode({k: v for k, v in params.items() if v is not None})
headers = {"Accept": "*/*"}
token = os.environ.get("SKILLHUB_TOKEN")
if token:
headers["Authorization"] = f"Bearer {token}"
try:
with urllib.request.urlopen(urllib.request.Request(url, headers=headers),
timeout=30) as resp:
payload = resp.read()
except urllib.error.HTTPError as e:
body = e.read()
try: # errors still come back enveloped
env = json.loads(body)
code = env.get("status")
sys.exit(f"SkillHub error {code}: {_STATUS_TEXT.get(code, env.get('error'))}")
except json.JSONDecodeError:
sys.exit(f"SkillHub returned HTTP {e.code}: {body[:200]!r}")
except (urllib.error.URLError, OSError) as e:
sys.exit(f"Could not reach SkillHub at {BASE}: {e}\n"
f"Override with: export SKILLHUB_URL=https://your-host")
if raw:
return payload
env = json.loads(payload)
if env.get("status") != 0: # status == 0 means success
code = env.get("status")
sys.exit(f"SkillHub error {code}: {_STATUS_TEXT.get(code, env.get('error'))}")
return env["result"]
def search(query: str, *, limit: int = 3) -> list[dict]:
"""Tier 1 — metadata only, no body. The query is embedded, matched by
vector ANN, then reranked by the cross-encoder; the endpoint decides how
many hits come back, so ``limit`` trims them client-side."""
result = _get(f"{API}/skills", {"q": query})
return result.get("items", [])[:limit]
def get_skill(ref: str) -> dict:
"""Tier 2 — full record including ``skill_md`` (the body you inject),
``files``, ``subscores`` and ``safety_flags``. ``ref`` is the UUID ``id``
or the raw ``skill_id``."""
return _get(f"{API}/skills/{urllib.parse.quote(ref, safe='')}")
def download(ref: str, out_dir: str, source: str = "cli") -> list[str]:
"""Tier 3 — zip with scripts/assets. Only for skills you will execute.
``source`` must be one of raven | everme | cli | web (it records an
install event); anything else is rejected with 60002."""
blob = _get(f"{API}/skills/{urllib.parse.quote(ref, safe='')}/download",
{"source": source}, raw=True)
tmp = os.path.join(out_dir, ".skillhub-download.zip")
os.makedirs(out_dir, exist_ok=True)
with open(tmp, "wb") as fh:
fh.write(blob)
written = []
with zipfile.ZipFile(tmp) as zf:
for member in zf.namelist():
# The archive wraps everything in a / dir, but never
# trust the paths inside it — reject absolute / traversing entries.
dest = os.path.normpath(os.path.join(out_dir, member))
if not dest.startswith(os.path.abspath(out_dir) + os.sep) and \
not dest.startswith(os.path.normpath(out_dir) + os.sep):
print(f" !! skipped unsafe zip entry: {member}", file=sys.stderr)
continue
zf.extract(member, out_dir)
written.append(member)
os.remove(tmp)
return written
def build_prompt(task: str, skills: list[dict]) -> str:
"""The whole integration step: prepend the skill bodies to the task.
Any harness that can edit a system prompt can do exactly this."""
blocks = "\n\n".join(
f'\n{s["skill_md"]}\n' for s in skills
)
return ("You have been given the following skills. Follow them when they apply.\n\n"
f"{blocks}\n\nTask: {task}")
def ask_llm(prompt: str, model: str | None = None) -> str:
"""Run the prompt through any OpenAI-compatible chat endpoint — OpenAI,
OpenRouter, Together, a local vLLM, etc. Pick the provider with
OPENAI_BASE_URL, the model with --model / OPENAI_MODEL, and authenticate
with OPENAI_API_KEY."""
key = os.environ.get("OPENAI_API_KEY")
if not key:
sys.exit("--ask needs OPENAI_API_KEY (+ OPENAI_BASE_URL for a non-OpenAI "
"provider, e.g. OpenRouter: https://openrouter.ai/api/v1)")
try:
from openai import OpenAI
except ImportError:
sys.exit("--ask needs the openai package: pip install openai")
base_url = os.environ.get("OPENAI_BASE_URL")
model = model or os.environ.get("OPENAI_MODEL", "gpt-4o-mini")
print(f" (llm: {model} @ {base_url or 'api.openai.com'})", file=sys.stderr)
client = OpenAI(base_url=base_url, api_key=key)
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content or ""
def main() -> int:
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
ap.add_argument("task", help="what you want the agent to do, in plain language")
ap.add_argument("--top-k", type=int, default=3, help="how many of the hits to keep")
ap.add_argument("--ask", action="store_true",
help="run the task through an LLM with the skill bodies injected")
ap.add_argument("--model",
help="model id for --ask (default: $OPENAI_MODEL or gpt-4o-mini); "
"for OpenRouter set OPENAI_BASE_URL and use e.g. "
"openai/gpt-4o-mini or anthropic/claude-3.5-sonnet")
ap.add_argument("--install", metavar="DIR",
help="download the top hit's bundle (scripts/assets) into DIR")
args = ap.parse_args()
print(f"task: {args.task}\n")
hits = search(args.task, limit=args.top_k)
if not hits:
print("SkillHub returned no skills for this task.")
return 1
print(f"[1/2] search → {len(hits)} hit(s), metadata only")
for i, h in enumerate(hits, 1):
print(f" {i}. {h['name']} q={h['quality_score']} {h['category']}"
f" {h.get('license') or 'license: ?'}")
print(textwrap.fill(h["description"], 78,
initial_indent=" ", subsequent_indent=" "))
print(f"\n[2/2] detail → fetching skill_md for {len(hits)} skill(s)")
full = [get_skill(h["id"]) for h in hits]
for s in full:
sub = s.get("subscores") or {}
print(f" {s['name']}: {len(s['skill_md'])} chars"
f" u={sub.get('utility')} r={sub.get('robustness')} s={sub.get('safety')}"
f" files={len(s.get('files') or [])}"
+ (f" flags={s['safety_flags']}" if s.get("safety_flags") else ""))
if args.install:
top = full[0]
print(f"\n[3] download → {top['name']} bundle into {args.install}")
for m in download(top["id"], args.install):
print(f" {m}")
prompt = build_prompt(args.task, full)
print(f"\n→ built a prompt of {len(prompt)} chars with the skill bodies injected")
if args.ask:
print("\n--- agent output ---")
print(ask_llm(prompt, args.model))
else:
print(" (re-run with --ask to actually execute the task)")
return 0
if __name__ == "__main__":
sys.exit(main())