Run nanoodle visual AI workflows from Python — zero-dependency executor for saved noodle-graph.json files
Project description
nanoodle (Python)
Run visual AI workflows from Python. Design them in the
nanoodle editor, save as noodle-graph.json, then load
and re-run them here — same graph, same NanoGPT API,
your own key.
Zero runtime dependencies (stdlib only). Library + CLI in one install.
Looking for JavaScript / Node? → nanoodle-js
At a glance
Build once, run anywhere. The browser app is for designing and testing. This package is for automating the same workflows in scripts, servers, and agents.
| Package | nanoodle on PyPI |
| Runtime | Python ≥ 3.9 · stdlib only · no deps |
| Sibling | JavaScript package (same graphs, same semantics) |
| Editor | nanoodle.io — wire nodes, hit 💾, download the graph |
Install
pip install nanoodle
export NANOGPT_API_KEY=... # nano-gpt.com API key (or OAuth access token)
Quickstart (library)
from nanoodle import Workflow
wf = Workflow.load("noodle-graph.json")
result = wf.run({"Text": "a cozy ramen shop on a rainy night"})
result["Image"].save("ramen.png") # media: MediaRef (url + bytes()/save())
print(result.cost_usd, result.remaining_balance)
With the app’s starter graph (text → LLM prompt-writer → image), that’s the whole program.
Discover a workflow’s interface
wf.inputs # [InputSpec(key="Text", node_id="n1", field="text", kind="textarea", ...)]
wf.outputs # [OutputSpec(key="Image", node_id="n3", type="image", ports=["image"])]
wf.settings # [SettingSpec(key="n3.size", kind="select", default="1k", ...)]
Input keys are flexible (case-insensitive): the node’s custom name, nodeId.field
("n2.system"), or the input’s label when unique. A workflow with exactly one
required input also accepts a bare value: wf.run("hello").
Media inputs
from nanoodle import media_from_file
wf.run({"Image": media_from_file("photo.jpg")}) # local file
wf.run({"Image": "https://example.com/photo.jpg"}) # hosted or data: URL
wf.run({"Image": raw_bytes}) # raw bytes (MIME sniffed)
Media is sent inline as base64 (NanoGPT has no upload endpoint). Files over ~4.4 MB (~3.5 MB for transcription) are refused locally with a clear error before any paid call.
Settings, progress, errors
result = wf.run(
{"Text": "sunset harbor"},
settings={"n3.model": "flux-dev", "n3.size": "1k"},
timeout=600,
on_progress=lambda evt: print(evt["type"], evt.get("name", "")),
)
run() raises RunError when an output (sink) node fails — error.result
still has partial results, per-node statuses, and cost so far. Failures in
lanes no output depends on only appear in result.errors. Unknown/unsupported
node types, missing required inputs, bad keys, and a missing API key all fail
before anything is spent.
CLI
Installed as nanoodle-py (and python -m nanoodle always works):
nanoodle-py inspect graph.json
nanoodle-py run graph.json --input Text="a cozy ramen shop" --set n3.size=1k --out ./out
nanoodle-py run graph.json --input n2.system=@style.txt --json
nanoodle-py run graph.json --env-file .env --input Text="hello" # NANOGPT_API_KEY from a .env file
--out DIR— save media outputs to files--json— machine-readable result--env-file PATH— load.env-styleKEY=VALUElines (existing env vars win)
Supported nodes
| runs | node types |
|---|---|
| local | text, upload (image/audio/video), choice, join, comment |
| NanoGPT | llm (incl. vision + audio input), image, draw, edit, inpaint*, vision, tvideo, ivideo, vedit, lipsync, music, remix, tts, transcribe |
| not supported (browser-only media processing) | resize, vframes, combine, soundtrack, trim, extractaudio |
Workflows with unsupported node types load with a warning and fail fast at
run() with UnsupportedNodeError — before any network call.
* inpaint: the browser app composites the mask onto black at the source pixel size; this library passes your mask through verbatim. Supply a black/white mask matching the source dimensions.
Use it as an agent skill
A saved workflow plus a short SKILL.md playbook is a skill any coding agent
can run — Claude Code (.claude/skills/<name>/SKILL.md) or anything that
reads markdown and runs shell. Recipe and template:
docs/agent-skills.md. Full example:
examples/agent-skill/poster-generator/.
Cost
Bring your own NanoGPT API key; NanoGPT bills your balance per generation and reports the price on each response.
result.cost_usd— total of prices returnedresult.cost_exact—Falseif any call omitted a price (total is then a floor)result.remaining_balance— freshest balance the API reported
A price of 0 means known-included (subscription), not unknown. No telemetry,
no analytics; the API key is never logged.
Testing
Tests run fully offline against a mock NanoGPT server (tests/harness/):
python -m unittest discover -s tests -t .
Opt-in live probe (spends a fraction of a cent):
python3 scripts/live-spot-check.py (add --image to also run the starter
graph’s image step).
Docs
Design contract and format/engine/io specs live in docs/:
DESIGN.md, SPEC-format.md, SPEC-engine.md, SPEC-io.md.
Same contract as the JavaScript package.
License
MIT — see LICENSE. Not affiliated with NanoGPT. Build workflows at nanoodle.io.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nanoodle-0.1.1.tar.gz.
File metadata
- Download URL: nanoodle-0.1.1.tar.gz
- Upload date:
- Size: 48.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11cc3447fc4b3be4b33ba51c862a6aab7e51ff98d43e4b1cd94a5627ea9fa9a4
|
|
| MD5 |
7c369a252f902f6b48b27156986d54cd
|
|
| BLAKE2b-256 |
32aeebbd8b8cc9181802bb607077e29c77ca1a45e4660a24139e3f6b622aab73
|
File details
Details for the file nanoodle-0.1.1-py3-none-any.whl.
File metadata
- Download URL: nanoodle-0.1.1-py3-none-any.whl
- Upload date:
- Size: 36.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77212b4955cc8b940642892d209c09dd43a8cfbf4de5db629bdcdb272cae3e57
|
|
| MD5 |
9cbdc3a2bf6af354566dbf69f78f792b
|
|
| BLAKE2b-256 |
0445b80a1156e44db8c939565158de883617b632e0646a0ed3c175ed4f889caf
|