Rhylthyme Importers
Import plugins for converting external data sources into Rhylthyme programs.
Installation
pip install rhylthyme-importers # TheMealDB, Spoonacular, recipe sites, CookLang, protocols.io, Opentrons, Benchling
Python 3.12 or newer. From a checkout: pip install -e ./rhylthyme-importers.
Importers read a URL, an id, or text you pass them. import_from_url()
refuses a local path unless the importer was built with
allow_local_files=True; the command-line tools do that, a server should not.
Quickstart: a recipe page to a picture and a live timeline
pip install rhylthyme # this package plus the rhylthyme command and the renderer
rhylthyme import https://www.bbcgoodfood.com/recipes/classic-lasagne
# Importing with recipe-scrapers…
# Saved easy_classic_lasagne.json
rhylthyme render easy_classic_lasagne.json -o lasagne.png --style web --palette vivid --color-by task # needs Node.js
rhylthyme publish easy_classic_lasagne.json --open # live timeline with timers
The same from Python:
from rhylthyme_importers import ImporterRegistry
from rhylthyme_timeline import render
url = "https://www.bbcgoodfood.com/recipes/classic-lasagne"
result = ImporterRegistry.find_for_url(url).import_from_url(url)
assert result.success, result.error
program = result.program # Rhylthyme program JSON
svg = render(program, style="web", colorBy="task")
open("lasagne.svg", "w").write(svg)
Run rhylthyme validate (or the validate_program MCP tool) on anything an
importer produces before you rely on the timings: an importer reads what the
source says, and sources are vague about time.
What is here
Each importer turns one kind of source into a Rhylthyme program: parallel
tracks of timed steps with shared-equipment limits, ready for
rhylthyme validate, rhylthyme publish or the web app. An importer reads
structure, not meaning, so what it produces is faithful to the source and
mostly sequential; see Enrichment
for how tracks and cross-track triggers are added afterwards.
| Importer | Source | Input | Needs |
|---|---|---|---|
themealdb |
TheMealDB, a free recipe API | meal id or URL | nothing |
spoonacular |
Spoonacular recipe API | recipe id or URL | SPOONACULAR_API_KEY |
recipe-scrapers |
several hundred recipe websites | recipe page URL | nothing |
cooklang |
CookLang .cook files |
raw or GitHub URL, or a file | nothing |
protocolsio |
protocols.io | protocol URL or id | PROTOCOLS_IO_TOKEN |
opentrons |
Opentrons Protocol API v2 .py |
file or pasted source | nothing |
benchling |
Benchling protocols, workflow tasks, notebook entries | protocol URL or id | a Benchling API token |
slidedeck |
PowerPoint .pptx |
file | nothing |
rhylthyme importers prints the registered importers; rhylthyme import <url>
picks one by URL, validates the program, writes <programId>.json and with
--publish prints a live-timeline URL; rhylthyme search <query> -i <importer>
finds things to import. (pip install rhylthyme gives you that command with
this package.)
TheMealDB
Recipes from TheMealDB. No key needed.
rhylthyme search "chicken curry" -i themealdb
rhylthyme import https://www.themealdb.com/meal/52772 -o curry.json
rhylthyme import 52772 -i themealdb --publish
from rhylthyme_importers import TheMealDBImporter
result = TheMealDBImporter().import_from_url("52772")
Spoonacular
Recipes from Spoonacular, with
structured ingredients, equipment and nutrition. Set SPOONACULAR_API_KEY
(free tier available); without it, search returns nothing and imports fail
with a message saying so.
export SPOONACULAR_API_KEY=...
rhylthyme search "pad thai" -i spoonacular
rhylthyme import https://spoonacular.com/recipes/pad-thai-716429 -o pad_thai.json
from rhylthyme_importers import SpoonacularImporter
SpoonacularImporter(api_key="...").import_from_url("716429")
Recipe sites (recipe-scrapers)
Any of the several hundred recipe websites that recipe-scrapers understands (Serious Eats, BBC Good Food, AllRecipes, NYT Cooking, ...). Pass the page URL; the importer is chosen automatically when the host is supported.
rhylthyme import https://www.seriouseats.com/the-best-chili-recipe -o chili.json
rhylthyme-sweep-supported-sites checks which of those sites still parse
(for catalogue maintenance).
CookLang
Individual CookLang .cook files, from a raw URL,
a GitHub blob URL (converted to raw automatically) or a local file.
rhylthyme import "https://github.com/cooklang/cookcli/blob/main/seed/Neapolitan%20Pizza.cook" -o pizza.json
rhylthyme import "Neapolitan Pizza.cook" -i cooklang # a .cook file on disk
from rhylthyme_importers import CooklangImporter
CooklangImporter().import_from_url("https://raw.githubusercontent.com/cooklang/cookcli/main/seed/Neapolitan%20Pizza.cook")
CooklangImporter(allow_local_files=True).import_from_url("Pizza.cook")
CooklangImporter().import_from_content(open("Pizza.cook").read(), source_name="Pizza")
Timers (~{10%minutes}) become step durations; ingredients and cookware
land in metadata.
CookLang Federation (bulk)
Scrape every recipe in the Cooklang Federation, about 76 GitHub repositories, and filter out placeholders. Reproducible and idempotent on re-run.
rhylthyme-import-cooklang-federation --discover # 1. list source repos
rhylthyme-import-cooklang-federation --import-all --staged-out /tmp/staged.json # 2. scrape + filter
rhylthyme-import-cooklang-federation --review /tmp/staged.json # 3. what passed, what was dropped
rhylthyme-import-cooklang-federation --refilter /tmp/staged.json # 4. re-apply edited rules, no re-download
The staged file is a list of programs; --upload sends it to a Rhylthyme
catalogue.
The filter rejects placeholder names (recipe, untitled, template,
test, Copy of ...), hash-like or all-digit names, and programs with no
ingredients or no steps. Short real names (Roux, Filo, Dahl, Toum) are kept.
protocols.io
Laboratory protocols from protocols.io. Needs
PROTOCOLS_IO_TOKEN (from https://www.protocols.io/developers). Each
protocol step keeps its source sentence on the step, so enrichment can say
which words a step came from.
export PROTOCOLS_IO_TOKEN=...
rhylthyme search "western blot" -i protocolsio
rhylthyme import "https://www.protocols.io/view/western-blot-..." -o blot.json
from rhylthyme_importers import ProtocolsIOImporter
ProtocolsIOImporter(access_token="...").import_from_url("https://www.protocols.io/view/...")
Opentrons
An Opentrons Protocol API v2 .py file (OT-2 or Flex) becomes a program with
one track per pipette mount or module; durations come from a static lookup
table. Nothing to configure. Full feature matrix in
docs/opentrons.md.
rhylthyme import https://raw.githubusercontent.com/Opentrons/Protocols/develop/protocols/007992/rna_isolation.ot2.apiv2.py
rhylthyme import path/to/protocol.py -o program.json
cat protocol.py | rhylthyme import - -i opentrons --stdout # pasted source
from rhylthyme_importers import OpentronsImporter
OpentronsImporter().import_from_source(open("protocol.py").read())
Covers OT-2 and Flex pipettes (1-, 8- and 96-channel), the Flex gripper, and
the heater-shaker, magnetic, temperature, thermocycler and absorbance
modules. transfer, distribute and consolidate expand into the same
low-level events the Opentrons run log emits. A protocol the stubbed
simulator cannot execute falls back to a static AST parse and carries a
WARNING event, which the web app shows as a banner.
Benchling
A Benchling Protocol, Workflow Task or Notebook Entry becomes a program with
an instrument-aware track split. Live import needs a Benchling API token for
the tenant; the web app stores one per user (encrypted) after a one-time
connect, and the MCP server's import_from_source with source: "benchling"
searches your library and imports by id or URL. Details, field mapping and
the roadmap: docs/benchling.md,
docs/benchling-field-mapping.md.
from rhylthyme_importers.benchling import BenchlingImporter
importer = BenchlingImporter()
importer.search_live(tenant="acme", token="...", query="PCR")
importer.import_from_url("https://acme.benchling.com/acme/protocols/prt_abc123", token="...")
Offline, a saved Benchling API response converts too, which is how the importer is tested:
BenchlingImporter().import_from_file("protocol_response.json", tenant="acme")
Slide decks
A PowerPoint .pptx becomes a presentation timeline: one step per slide,
timed from speaker-notes cues where present.
from rhylthyme_importers import SlideDeckImporter
SlideDeckImporter().import_from_url("talk.pptx")
Other commands
The remaining rhylthyme-* commands (rhylthyme-backfill-taxonomy,
rhylthyme-clean-titles, rhylthyme-backfill-language,
rhylthyme-embed-recipes, rhylthyme-detect-text-thumbs,
rhylthyme-replace-broken-thumbs, rhylthyme-import-recipe-scrapers,
rhylthyme-sweep-supported-sites) maintain the public catalogue on
rhylthyme.com and are not needed to import anything. Their extra
dependencies are the catalog extra.
Enrichment is not part of BaseImporter
An importer reads structure, not meaning, so it produces one track of
steps chained head-to-tail. Splitting that into parallel tracks with
cross-track triggers takes a language model, and that lives in
rhylthyme-server, not here:
rhylthyme_server._prompting.enrich_program runs turn 4 of the
plan_schedule prompt over the program an importer has already returned,
exposed as enrich: true on POST /api/import and on the MCP
import_from_source tool.
Nothing in this package changes for it. BaseImporter has no enrich
hook, no Anthropic dependency and no network requirement beyond the
source API it already talks to; importers stay deterministic, offline-
testable and free to run without an ANTHROPIC_API_KEY. Enrichment is a
post-processor over ImportResult.program, opt-in per request and
rate-limited, and a failed enrichment returns the importer's program
unchanged.
Two conventions make an importer enrich well:
- Keep the source sentence on the step.
enrichreadsstep["description"](falling back tostep["notes"]) as the step'smetadata.sourceSpan.quote, so the enriched program can say which words each step came from. protocols.io's importer already does this. - Keep
stepIds stable. Enrichment preserves every importedstepId, and marks any step it adds withmetadata.inferred = true; the diff between the two is how the UI tells read-from-source apart from inferred.
Python API
from rhylthyme_importers import TheMealDBImporter, ProtocolsIOImporter, ImporterRegistry
# TheMealDB
mealdb = TheMealDBImporter()
results = mealdb.search("pasta")
result = mealdb.import_from_url("52771")
if result.success:
program = result.program
print(f"Imported: {program['name']}")
# Protocols.io
protocolsio = ProtocolsIOImporter(access_token="your_token")
result = protocolsio.import_from_url("https://www.protocols.io/view/...")
# Auto-detect importer from URL
importer = ImporterRegistry.find_for_url("https://www.themealdb.com/meal/52771")
if importer:
result = importer.import_from_url("https://www.themealdb.com/meal/52771")
Creating Custom Importers
Extend the BaseImporter class to create new importers:
from rhylthyme_importers import BaseImporter, ImportResult, ImporterRegistry
class MyCustomImporter(BaseImporter):
name = "myimporter"
description = "Import from my custom source"
supported_domains = ["example.com"]
def can_import(self, url_or_query: str) -> bool:
return "example.com" in url_or_query
def search(self, query: str) -> list:
# Return list of {name, url, description}
return []
def import_from_url(self, url: str) -> ImportResult:
# Fetch data and convert to Rhylthyme program
program = self.create_base_program(
name="My Program",
description="Description",
environment_type="kitchen",
source_url=url,
source_type="myimporter"
)
# Add tracks, steps, etc.
return ImportResult(success=True, program=program)
# Register the importer
ImporterRegistry.register(MyCustomImporter())
License
Apache License 2.0
Metadata
Release files for rhylthyme-importers 0.4.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rhylthyme_importers-0.4.5.tar.gz | 175.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rhylthyme_importers-0.4.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 340.4 kB
Release files / rhylthyme_importers-0.4.5.tar.gz
| Download URL | rhylthyme_importers-0.4.5.tar.gz |
|---|---|
| Size | 175.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c7a5d5a140cdce589d6759102543cdf8a9eff46b90f120d686092db36efca214
|
|
BLAKE2b-256 checksum How to use checksums |
f00a4aa3ee28adb8446f3706039914604c066e61f1960202d5b2c163d01f12d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.9
|
Release files / rhylthyme_importers-0.4.5-py3-none-any.whl
| Download URL | rhylthyme_importers-0.4.5-py3-none-any.whl |
|---|---|
| Size | 164.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3bf65d9a0a01fd491ca520b0257d5d674726399d641c5f736bb2640b313da2cf
|
|
BLAKE2b-256 checksum How to use checksums |
6d310989e43a78e3b6cbd188e9ba8a5245bdb725fce5ce62da96a90efb565910
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.9
|