Repository explainer · generated 13 May 2026
This repository is a thin Agent Finder registry adapter over Hugging Face Spaces. It turns Hugging Face semantic Space search into Agent Finder catalog entries, a CLI, a REST API, and generated SKILL.md artifacts.
The core of the project is an adapter pipeline: query Hugging Face’s agent-oriented semantic search, keep only running Spaces, and project each Space into Agent Finder’s value-or-reference catalog envelope.
POST /search with query text and optional media type.application/ai-skill, application/mcp-server+json, raw Space JSON, or all./api/spaces/semantic-search with agents=true; MCP adds filter=mcp-server.RUNNING are emitted.The README frames the repository as a small adapter, but it already exposes the same core search through multiple surfaces.
Calls Hugging Face’s semantic Spaces API with agents=true, optional SDK/tag filters, and optional request-scoped token forwarding.
POST /search accepts the Agent Finder-ish search envelope and returns SearchResponse models with compact JSON output.
GET /skills/huggingface/{owner}/{space}/SKILL.md wraps a Space’s agents.md with skill frontmatter and source metadata.
Spaces tagged mcp-server can be returned as application/mcp-server+json entries pointing at the Gradio MCP endpoint.
agentfinder spaces search and the top-level agentfinder search command share the same search core and can print tables or JSON.
CI and release scripts run locked sync, Ruff format/lint, ty, pytest, package build checks, and deployment hooks for a Hugging Face Space.
The source package is intentionally small. The best reading path is models → HF transport → conversion core → API/CLI wrappers.
| File | Primary role | Important structures |
|---|---|---|
src/agentfinder/models.py | Protocol-shaped Pydantic models. | CatalogEntry, SearchQuery, SearchRequest, SearchResult, SearchResponse |
src/agentfinder/hf_search.py | Low-level Hugging Face HTTP client and JSON normalization. | HfSemanticSpaceSearcher, SpaceSearchResult, SpaceRuntime |
src/agentfinder/hf_spaces.py | Core domain adapter: URLs, identifiers, filtering, result conversion, skill generation. | search_hf_spaces, space_to_*_result, build_space_skill_markdown |
src/agentfinder/server.py | FastAPI wrapper over the core adapter. | create_app, search_agent_finder, token helpers, skill/agents routes |
src/agentfinder/cli.py | Typer commands and Rich table formatting. | search_alias, spaces_search, serve, _search_response |
tests/test_hf_spaces.py | Behavioral coverage with stubs and a local HTTP server. | Conversion tests, search filtering, token precedence, OpenAPI examples, generated skill frontmatter |
The models mirror the Agent Finder draft: every catalog entry must have identity fields and exactly one content delivery mechanism, either url or data.
CatalogEntry.validate_value_or_reference rejects entries with both url and data, or neither. This keeps REST results predictable for clients.
if (self.url is None) == (self.data is None):
raise ValueError("exactly one of url or data must be present")| Kind | Media type | Delivery |
|---|---|---|
| Generated skill | application/ai-skill | url to generated SKILL.md |
| MCP server | application/mcp-server+json | Inline data with HTTP transport and MCP URL |
| Raw HF Space | application/vnd.huggingface.space+json | Inline data with Space metadata |
| Legacy Space alias | application/huggingface-space+json | Accepted by HTTP routing as raw Space output |
The CLI builds a SearchResponse through _search_response, then prints either JSON or a Rich table with score, type, name, SDK, stage, endpoint, and description.
uv run agentfinder spaces search "generate image" --limit 5 uv run agentfinder spaces search "image generation" --kind mcp --json uv run agentfinder serve --port 8080
search_agent_finder maps request media type to a result kind. Unsupported media types intentionally return an empty result set rather than attempting a best-effort conversion.
{
"query": {
"text": "remove background from image",
"mediaType": "application/ai-skill"
},
"pageSize": 5
}hf_search.py owns the semantic search HTTP request. server.py owns fetching remote agents.md and runs it in a threadpool so blocking urllib calls do not block the async route.
The server checks X-HF-Authorization, then Authorization, then HF_TOKEN. Header values override configured tokens and are only forwarded downstream.
Even when the search call includes non-running Spaces, search_hf_spaces emits only results with runtime stage RUNNING.
When Hugging Face runtime metadata includes a domain, generated app and MCP URLs use it. Otherwise code falls back to the standard {owner}-{space}.hf.space slug.
The single test file covers the meaningful behavior of the adapter without requiring live Hugging Face calls for most cases.
| Behavior | Evidence in tests | Why it matters |
|---|---|---|
| Skill, Space, and MCP conversions | test_space_to_search_result_*, MCP URL tests | Ensures entries satisfy Agent Finder artifact shapes. |
| Running-only filtering | test_search_hf_spaces_only_returns_running_spaces | Prevents dead or building Spaces from being advertised. |
| HF query construction | Local HTTPServer captures path and Authorization header | Verifies agents=true, filters, non-running flag, and token forwarding. |
| HTTP media-type routing | test_agent_finder_search_* | Documents empty unsupported-media behavior and MCP routing. |
| Token precedence | hf_token_from_headers and route forwarding tests | Supports the README’s request-scoped HF_TOKEN requirement. |
| OpenAPI clarity | Examples and auth header documentation tests | Makes the HTTP surface discoverable for clients. |
Start in hf_spaces.py with a converter and media type, then update server._result_kind, CLI _result_type, docs, and tests.
Edit _space_metadata and the relevant space_to_*_result function. Watch the value-or-reference invariant in CatalogEntry.
Update search_hf_spaces for filtering/limiting semantics, or HfSemanticSpaceSearcher.search_spaces for Hugging Face query parameters.
Modify build_space_skill_markdown. Tests already assert required frontmatter and source instruction inclusion.
Use create_app and search_agent_finder in server.py. Keep CLI and HTTP wrapping the same core logic.
Use scripts/check-release.sh, GitHub Actions, and deploy/huggingface-space/. README documents the release flow.
include_non_running is not an output policy. It is passed to Hugging Face search, but emitted results are still filtered to RUNNING.search_hf_spaces defaults to skill; CLI and HTTP omitted media type default to all.mcp-server.