File size: 5,553 Bytes
988c7cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "id": "forge_client",
  "name": "FORGE Client",
  "version": "1.2.0",
  "description": "Bootstrap client that lets AI agents connect to FORGE, list available skills, and dynamically download & hot-load them at runtime. This is the first skill every agent should install.",
  "author": "Chris4K",
  "tags": ["meta", "core", "registry", "bootstrap"],
  "dependencies": ["requests"],
  "schema": {
    "input": {
      "base_url": "str — FORGE registry URL (default: https://chris4k-forge.hf.space)"
    },
    "output": {
      "client": "ForgeClient instance"
    }
  },
  "code": "import requests\nimport types\nimport importlib\nimport sys\nfrom typing import Optional\n\n\nclass ForgeClient:\n    \"\"\"FORGE registry client. Lets agents discover and dynamically load skills.\"\"\"\n\n    def __init__(self, base_url: str = \"https://chris4k-forge.hf.space\"):\n        self.base_url = base_url.rstrip(\"/\")\n        self._cache: dict = {}\n\n    # ── Discovery ────────────────────────────────────────────\n\n    def list(self, tag: Optional[str] = None, query: Optional[str] = None) -> list[dict]:\n        \"\"\"List all available skills. Optionally filter by tag or search query.\"\"\"\n        params = {}\n        if tag:\n            params[\"tag\"] = tag\n        if query:\n            params[\"q\"] = query\n        r = requests.get(f\"{self.base_url}/api/v1/skills\", params=params, timeout=10)\n        r.raise_for_status()\n        return r.json()[\"skills\"]\n\n    def search(self, query: str) -> list[dict]:\n        \"\"\"Search skills by name, description, or tags.\"\"\"\n        return self.list(query=query)\n\n    def info(self, skill_id: str) -> dict:\n        \"\"\"Get metadata for a specific skill (without code).\"\"\"\n        r = requests.get(f\"{self.base_url}/api/v1/skills/{skill_id}\", timeout=10)\n        r.raise_for_status()\n        return r.json()\n\n    def manifest(self) -> dict:\n        \"\"\"Download the full manifest (all skills + code). Good for offline caching.\"\"\"\n        r = requests.get(f\"{self.base_url}/api/v1/manifest\", timeout=30)\n        r.raise_for_status()\n        return r.json()\n\n    # ── Loading ──────────────────────────────────────────────\n\n    def load(self, skill_id: str, force_reload: bool = False) -> types.ModuleType:\n        \"\"\"\n        Download a skill and return it as a live Python module.\n        The module will have an execute() function ready to call.\n\n        Example:\n            calc = forge.load(\"calculator\")\n            result = calc.execute(expression=\"sqrt(144) + 2**8\")\n        \"\"\"\n        if skill_id in self._cache and not force_reload:\n            return self._cache[skill_id]\n\n        r = requests.get(f\"{self.base_url}/api/v1/skills/{skill_id}/code\", timeout=10)\n        r.raise_for_status()\n        payload = r.json()\n\n        module = types.ModuleType(f\"forge_skill_{skill_id}\")\n        module.__forge_meta__ = {\n            \"id\": payload[\"id\"],\n            \"version\": payload[\"version\"],\n            \"schema\": payload.get(\"schema\", {}),\n        }\n        exec(compile(payload[\"code\"], f\"<forge:{skill_id}>\", \"exec\"), module.__dict__)\n\n        if not hasattr(module, \"execute\"):\n            raise ImportError(f\"Skill '{skill_id}' has no execute() function\")\n\n        self._cache[skill_id] = module\n        sys.modules[f\"forge_skill_{skill_id}\"] = module\n        return module\n\n    def load_many(self, skill_ids: list[str]) -> dict[str, types.ModuleType]:\n        \"\"\"Load multiple skills at once. Returns {skill_id: module}.\"\"\"\n        return {sid: self.load(sid) for sid in skill_ids}\n\n    # ── Publishing ───────────────────────────────────────────\n\n    def publish(self, skill_dict: dict, api_key: Optional[str] = None) -> dict:\n        \"\"\"Publish a new skill to the FORGE registry.\"\"\"\n        headers = {\"Content-Type\": \"application/json\"}\n        if api_key:\n            headers[\"X-Forge-Key\"] = api_key\n        r = requests.post(\n            f\"{self.base_url}/api/v1/skills\",\n            json=skill_dict,\n            headers=headers,\n            timeout=15,\n        )\n        return r.json()\n\n    # ── Utilities ────────────────────────────────────────────\n\n    def cached_skill_ids(self) -> list[str]:\n        \"\"\"List skill IDs that are loaded and cached in memory.\"\"\"\n        return list(self._cache.keys())\n\n    def __repr__(self) -> str:\n        return f\"ForgeClient(url={self.base_url!r}, cached={len(self._cache)} skills)\"\n\n\n# Standard FORGE entry point\ndef execute(base_url: str = \"https://chris4k-forge.hf.space\") -> dict:\n    \"\"\"Bootstrap a ForgeClient. The result['client'] is ready to use.\"\"\"\n    client = ForgeClient(base_url=base_url)\n    stats = requests.get(f\"{base_url}/api/v1/stats\", timeout=5).json()\n    return {\n        \"client\": client,\n        \"registry_url\": base_url,\n        \"available_skills\": stats.get(\"total_skills\", \"?\"),\n        \"message\": f\"Connected to FORGE. {stats.get('total_skills', '?')} skills available.\",\n    }\n",
  "downloads": 0,
  "created_at": 1710000000
}