| title | Reachy Mini API |
|---|---|
| emoji | 🤖 |
| colorFrom | blue |
| colorTo | purple |
| sdk | docker |
| app_port | 7860 |
| pinned | false |
| short_description | Backend API for the Reachy Mini app store |
Backend service for the Reachy Mini app store. Split out of the showcase website so the mobile app's backend can be deployed independently of the marketing site.
| Route | Purpose | Consumer |
|---|---|---|
GET /api/js-apps |
JS app catalog (categorized + moderated) | mobile app |
GET /api/apps |
full catalog (Python + JS) | website |
GET /api/mcp-tools |
MCP tool catalog (Spaces tagged reachy-mini-tool, with resolved mcpUrl), moderated fail-closed |
mobile app |
GET /api/moves |
community move catalog: one entry per recorded move across the HF datasets tagged reachy_mini_community_moves, plus per-dataset summaries |
gallery, clients |
GET /api/{apps,js-apps,mcp-tools,moves}?q=&limit= |
semantic search: multilingual-embedding top-limit over that catalog (lexical fallback when the index is cold); response carries query + ranking |
all clients |
GET /api/categories |
category taxonomy | clients |
POST /api/openai/ephemeral |
mint short-lived OpenAI Realtime keys | mobile app |
GET /api/oauth-config |
public OAuth client id | website (fallback) |
GET /api/health |
health probe | monitoring |
POST /api/refresh / refresh-categories / refresh-moderation |
admin triggers | ops |
POST /api/mcp-tools/refresh-moderation |
admin trigger for the tool sweep | ops |
Set these in the Space's Settings -> Variables and secrets (see .env.example):
HF_TOKEN(required, write access toSTORE_DATASET) - LLM categorization + moderation (and persisting their caches), plus the search embeddings via HF Inference.OPENAI_API_KEY(required) - master key used server-side only to mint ephemeral Realtime session keys.STORE_DATASET- single dataset holdingapp-list.json,block-list.json,categories.json,moderation.json. Defaults topollen-robotics/reachy-mini-official-app-store.EMBEDDING_MODEL- feature-extraction model powering catalog search. Defaults tointfloat/multilingual-e5-small.
The four catalog routes accept ?q=<free text>&limit=<n> and return the
top limit entries by relevance instead of the full catalog. Ranking is
multilingual (query in any language against English metadata): one
embedding vector per entry (name + description + tags - deliberately not
the README, which measurably diluted cross-lingual matching),
computed at catalog refresh through the HF Inference router and cached by
content hash, plus small popularity / exact-name boosts and a penalty for
placeholder descriptions. Without HF_TOKEN, or while the index warms
up, ranking degrades to lexical scoring (the response's ranking field
says which one answered), and search is always applied after moderation
filtering, so it can never surface a hidden Space.
/api/moves indexes the recorded-move libraries shared on the Hub: HF
datasets tagged reachy_mini_community_moves (the tag Marionette and
the Blender add-on stamp on every share). The unit is the individual
move, not the repo: each data/<stem>.json trajectory becomes one
entry (fileUrl, optional audioUrl, its dataset attached), and its
embedding passage is the stem words plus the library's display name, so
?q=un mouvement triste returns sad_nod-style moves directly.
Trajectory files are never downloaded server-side; per-dataset file
listings are cached on lastModified, so a steady-state refresh costs
one hub call. The shared config/blocked-app-list.json killswitch
applies (a dataset id there drops the whole library). There is no LLM
moderation pass on this catalog: a move is trajectory data plus a slug,
a much smaller blast radius than an app or an MCP tool.
/api/js-apps and /api/mcp-tools are both fail-closed: an entry is
served only when it is on an official list or carries an explicit allow
moderation verdict. A block, a review, a block-list hit or a missing
verdict all keep it hidden (App Store guideline 1.2). Use
?includeHidden=true to inspect what is being filtered.
The block-list is deliberately shared between both catalogs, so blocking a
Space in config/blocked-app-list.json is a global killswitch that needs
no code deploy.
MCP tool Spaces get the same gate as apps because their descriptions are fed to the model and the tools can be invoked through the robot, which is a wider blast radius than a sandboxed app the user opens and watches.
To vouch for a first-party tool Space (skipping moderation, as for
official apps), add its slug to config/official-tool-list.json:
[
"pollen-robotics/reachy-mini-search-tool",
"pollen-robotics/reachy-mini-weather-tool",
"pollen-robotics/reachy-mini-time-tool"
]That file is optional and unioned with official-app-list.json; a 404
simply means "no official tools", in which case first-party tools stay
hidden until the LLM sweep clears them.
The mobile app targets a frozen API base URL. In production this Space
must answer on that stable host (pollen-robotics-reachy-mini.hf.space)
via the existing redirect, so moving/rebuilding the backend never
requires an App Store resubmission.
npm install
HF_TOKEN=hf_xxx OPENAI_API_KEY=sk-xxx PORT=3001 npm start