import_github_core
Download MIT-licensed GitHub repositories and add them to the local IP core registry for immediate use in FPGA development workflows.
Instructions
Download an MIT-licensed GitHub repository and add it to the local IP core registry. Automatically uses FuseSoC CAPI2 metadata (.core file) if one exists in the repo. After import, the core is immediately available via get_ip_core and generate_ip.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| repo | Yes | GitHub repo in 'owner/repo' format, e.g. 'ultraembedded/core_uart' | |
| subdir | No | Subdirectory within the repo to scope HDL search (for monorepos) | |
| ref | No | Branch, tag, or commit SHA (default: repo's default branch) |
Implementation Reference
- registry/github.py:152-270 (handler)Core implementation of import_core function that downloads a GitHub repo, validates license, fetches HDL files, optionally uses FuseSoC metadata, and writes the core manifest to the local registry.
def import_core( owner_repo: str, subdir: str = "", ref: str = "", dest_parent: Path = Path(__file__).parent.parent / "cores", ) -> dict: """Download a GitHub repo and write it into dest_parent/<core_name>/. Automatically uses FuseSoC CAPI2 metadata if a .core file is found. Returns the manifest dict on success or an error dict. """ parts = owner_repo.strip("/").split("/") if len(parts) != 2: return {"error": "repo must be 'owner/repo', e.g. 'ultraembedded/core_uart'"} owner, repo = parts subdir_norm = subdir.strip("/") # Repo metadata try: meta = _get(f"{GITHUB_API}/repos/{owner}/{repo}") except httpx.HTTPStatusError as e: return {"error": f"GitHub API {e.response.status_code}: {e.response.text}"} except Exception as e: return {"error": str(e)} license_id = (meta.get("license") or {}).get("spdx_id", "unknown") allowed = _allowed_licenses() if license_id not in allowed: return { "error": ( f"Repository license '{license_id}' is not in the allowed list: " f"{', '.join(sorted(allowed))}. " "Set FPGAZERO_ALLOWED_LICENSES to override." ) } if not ref: ref = meta.get("default_branch", "main") # File tree try: tree = _fetch_tree(owner, repo, ref) except Exception as e: return {"error": f"Could not fetch file tree: {e}"} hdl_paths, core_paths = _filter_files(tree, subdir_norm) if not hdl_paths: scope = f"{owner_repo}/{subdir_norm}" if subdir_norm else owner_repo return {"error": f"No HDL files (.v/.sv/.vhd) found in {scope}"} # Try FuseSoC .core file for richer metadata fuse_manifest: dict | None = None if core_paths: try: raw = _download_raw(owner, repo, core_paths[0], ref) from registry.fusesoc import capi2_to_manifest_dict fuse_manifest = capi2_to_manifest_dict(raw, source=f"https://github.com/{owner_repo}") except Exception: pass # non-fatal # Download HDL files (preserve relative paths) core_name = repo.lower().replace("-", "_").replace(".", "_") dest_dir = dest_parent / core_name dest_dir.mkdir(parents=True, exist_ok=True) downloaded: list[str] = [] for path in hdl_paths: try: content = _download_raw(owner, repo, path, ref) rel_path = Path(path) if subdir_norm: rel_path = rel_path.relative_to(subdir_norm) target = dest_dir / rel_path target.parent.mkdir(parents=True, exist_ok=True) target.write_text(content, encoding="utf-8") downloaded.append(rel_path.as_posix()) except Exception as e: # Write a stub so the manifest isn't broken rel_path = Path(path) if subdir_norm: rel_path = rel_path.relative_to(subdir_norm) target = dest_dir / rel_path target.parent.mkdir(parents=True, exist_ok=True) target.write_text(f"// Download failed: {e}\n", encoding="utf-8") downloaded.append(rel_path.as_posix()) # Build manifest (FuseSoC wins if available) description = meta.get("description") or f"Imported from github.com/{owner_repo}" topics = meta.get("topics", []) manifest = fuse_manifest or { "name": core_name, "version": ref, "description": description, "author": owner, "license": license_id, "language": _dominant_language(hdl_paths), "category": _infer_category(" ".join(topics) + " " + repo + " " + description), "tags": topics[:8], "parameters": {}, "ports": {}, "files": downloaded, } # Always update files list to what was actually downloaded manifest["files"] = downloaded manifest["source"] = f"https://github.com/{owner_repo}" (dest_dir / "core.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8") return { "imported": True, "core_name": core_name, "source": f"https://github.com/{owner_repo}", "ref": ref, "license": license_id, "files_fetched": downloaded, "fusesoc_used": fuse_manifest is not None, "manifest": manifest, } - registry/resolver.py:122-138 (handler)CoreRegistry.import_github_core method that wraps the import_core function, passing the destination directory and reloading the cache after successful import.
def import_github_core( self, owner_repo: str, subdir: str = "", ref: str = "", ) -> dict: """Download a GitHub repo and register it as a local core.""" from registry.github import import_core result = import_core( owner_repo=owner_repo, subdir=subdir, ref=ref, dest_parent=self._dir, ) if result.get("imported"): self._load_all() return result - server.py:209-234 (schema)Tool registration defining the 'import_github_core' tool with inputSchema specifying repo (required), subdir (optional), and ref (optional) parameters.
types.Tool( name="import_github_core", description=( "Download an MIT-licensed GitHub repository and add it to the local IP core registry. " "Automatically uses FuseSoC CAPI2 metadata (.core file) if one exists in the repo. " "After import, the core is immediately available via get_ip_core and generate_ip." ), inputSchema={ "type": "object", "properties": { "repo": { "type": "string", "description": "GitHub repo in 'owner/repo' format, e.g. 'ultraembedded/core_uart'", }, "subdir": { "type": "string", "description": "Subdirectory within the repo to scope HDL search (for monorepos)", }, "ref": { "type": "string", "description": "Branch, tag, or commit SHA (default: repo's default branch)", }, }, "required": ["repo"], }, ), - server.py:456-462 (registration)Dispatch handler case for 'import_github_core' that calls registry.import_github_core with the arguments from the tool invocation.
case "import_github_core": result = await asyncio.to_thread( registry.import_github_core, owner_repo=arguments["repo"], subdir=arguments.get("subdir", ""), ref=arguments.get("ref", ""), )