Skip to main content

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. enrich reads step["description"] (falling back to step["notes"]) as the step's metadata.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 imported stepId, and marks any step it adds with metadata.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)

Source distribution for rhylthyme-importers 0.4.5
File Size Uploaded
rhylthyme_importers-0.4.5.tar.gz 175.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rhylthyme-importers 0.4.5
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

0.4.7

2 release files

0.4.6

2 release files

This release

0.4.5 This release

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page