This release is a pre-release and may not be stable for production use.
ghRavioli
An agent skill and command-line tool for writing Grasshopper Python components in code, verifying them, and copy-pasting them into Grasshopper. The components stay easy to modify and arrange.
Grasshopper keeps a script component's code inside the canvas, where a coding agent can't easily read, edit or diff it. ghRavioli keeps each component in two ordinary files instead:
component.pyholds the computation;component.tomldeclares the inputs and outputs, and how the component sits on the canvas.
An agent such as Claude Code or Codex edits those files like any other code.
ghravioli build turns them into a .ghclip archive, and you paste the
archive onto the Grasshopper canvas. To change a component, edit the files,
rebuild and paste again.
The skill in
skills/grasshopper-python-components
shows the agent how to write components that stay easy to work with: one job
per component, readable port names, a log output on every component, native
geometry on the wires and versioned JSON for anything more complex. The builder
handles the layout. A pasted component shows its full port names, a panel with
its log, and a slider or toggle on each input that can take one.
Try it with your agent
Paste this into a coding agent that can run commands on your machine, such as Claude Code, Codex or Cursor. It installs ghRavioli in a trial folder, writes a small component and puts it on your clipboard, ready to paste into Grasshopper.
Help me try ghRavioli (https://github.com/burman-work/ghravioli), a tool for
writing Grasshopper Python components in code and pasting them into Grasshopper.
1. Create a folder called ghravioli-trial in my home directory and work inside
it. Make a Python virtual environment there (Python 3.11 or newer; if there
isn't one, tell me how to install it before going further) and install the
tool with `python -m pip install ghravioli`. Check that `ghravioli --help`
runs.
2. Install the agent skill into that folder with
`npx skills add burman-work/ghravioli`. If npx isn't available, download
https://github.com/burman-work/ghravioli/archive/refs/heads/main.zip and
copy its skills/grasshopper-python-components folder into the folder
instead. Read the skill's SKILL.md and follow it from here on.
3. Write one small component as a Python file plus a TOML manifest. It takes a
list of points and a scale factor (a slider from 0 to 10, default 1) and
outputs the scaled points and a log.
4. Run `ghravioli validate`, `ghravioli build` and
`ghravioli inspect <archive> --source`, and show me the results.
5. Run `ghravioli copy` on the manifest to put the component on my clipboard,
then tell me how to paste it into Grasshopper in Rhino 8. If Rhino isn't on
this machine, tell me where the .ghclip file is so I can move it.
Don't change anything outside the ghravioli-trial folder, and tell me what you
installed.
Status
ghravioli 0.1.0a2 is an experimental alpha for Rhino 8 and its Python 3
Script component.
- A generated archive with a component, four sliders, four toggles and a log panel pastes onto the canvas in Rhino 8.31 on Windows 10. The test is recorded in Rhino acceptance.
- That test didn't check each slider's range and value, each toggle's state, or saving and reopening the definition. Those manual Rhino checks are still to do.
- Nobody has tested it in Rhino on macOS yet.
- CI runs the test suite on Linux, macOS and Windows with Python 3.11 to 3.14. That covers the builder, not Rhino.
The builder needs Python 3.11 or newer. Component code is checked against Python 3.9, the version Rhino 8's Python 3 component runs.
An archive can position several components, but ghRavioli doesn't wire them to each other; you connect them on the canvas. The only wires it creates run between a component and its own panels, sliders and toggles.
Install
python -m pip install ghravioli
ghravioli --help
The PyPI package contains the command-line tool and the Python library. The agent skill, examples and docs live in the repository, so clone it as well if you want those:
git clone https://github.com/burman-work/ghravioli.git
cd ghravioli
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
On Windows, activate with .venv\Scripts\activate.
Using the skill with an agent
Install the skill into Claude Code, Codex and other agents with skills:
npx skills add burman-work/ghravioli
Inside this repository, Claude Code finds the skill in
.claude/skills/grasshopper-python-components and Codex finds it in
.agents/skills/grasshopper-python-components. To use it in another project,
copy skills/grasshopper-python-components into that project's skill folder
and make sure the ghravioli command is installed where the agent can run it.
Then ask for a component in plain terms, for example: "Make a Grasshopper component that offsets a curve by a distance between 0 and 5, with a toggle to flip the side." The agent writes the Python file and the manifest, builds the archive and inspects it. You paste it.
A component
examples/scale_points/component.py is
ordinary Python. Grasshopper supplies the inputs as variables, and the script
sets the outputs:
scaled_points = []
log = "not started"
try:
input_points = [] if points is None else list(points)
scale_factor = 1.0 if factor is None else float(factor)
scaled_points = [point * scale_factor for point in input_points if point is not None]
skipped = len(input_points) - len(scaled_points)
log = f"scaled {len(scaled_points)} point(s) by {scale_factor:g}; skipped {skipped} null value(s)"
except (TypeError, ValueError) as error:
scaled_points = []
log = f"error: {type(error).__name__}: {error}"
examples/scale_points/component.toml
declares its interface. The min, max and default on factor give that
input a slider when the archive is pasted:
kind = "component"
schema_version = 1
target = "rhino8-python3"
target_python = "3.9"
id = "example-scale-points"
name = "Scale Points"
source = "component.py"
[[inputs]]
name = "points"
type = "point"
access = "list"
[[inputs]]
name = "factor"
type = "float"
access = "item"
optional = true
min = 0.0
max = 10.0
default = 1.0
[[outputs]]
name = "scaled_points"
type = "point"
access = "list"
[[outputs]]
name = "log"
type = "str"
access = "item"
Validate, build, inspect, then copy it to the clipboard:
ghravioli validate examples/scale_points/component.toml
ghravioli build examples/scale_points/component.toml --output scale-points.ghclip
ghravioli inspect scale-points.ghclip --json
ghravioli copy examples/scale_points/component.toml
Paste onto the Grasshopper canvas. copy accepts a manifest or a .ghclip
and builds first when given a manifest.
examples/json_config/component.toml
shows a component that passes its settings on as a versioned JSON string.
Arranging components on the canvas
A pasted archive lands at the position it was built with, not under the mouse.
Grasshopper only re-anchors a paste for its own clipboard format, and these
archives arrive as text. The default position is 200, 200. Pass --at X,Y
to build or copy to put a single component somewhere else, for example
--at 0,0.
To place several components in one paste, list them in a graph manifest with a
position for each, as in examples/pipeline.toml:
kind = "graph"
schema_version = 1
id = "example-pipeline"
name = "Example Pipeline"
[[components]]
manifest = "json_config/component.toml"
x = 200.0
y = 200.0
[[components]]
manifest = "scale_points/component.toml"
x = 440.0
y = 200.0
Four settings at the top of a component manifest control how it looks once
pasted. All four default to true:
legible_names = true # show full port names instead of nicknames
log_panel = true # add a panel wired to the log output
input_widgets = true # add a toggle or slider to inputs that can take one
standard_output = true # keep Grasshopper's own out console
A boolean input gets a toggle. A number input gets a slider only when the
manifest gives it a min and max, so no slider has a made-up range. Any
other output can ask for its own panel with panel = true. Keep the out
console while debugging: it shows tracebacks, which log can't. See
canvas presentation.
Passing data between components
- Keep Rhino geometry on native geometry wires.
- Send complex settings as a versioned JSON string, and check the schema and version where it's read.
- Don't put Python dictionaries or custom objects on a wire. Grasshopper can't display them, and they don't survive recomputes reliably.
- Give every component exactly one
logoutput: a short summary for a person to read, kept apart from the data.
Data flow and the component contract have the details.
Checking an archive before you paste it
A .ghclip contains executable Python. Base64 is encoding, not encryption, so
treat an archive from someone else like any code you're about to run:
ghravioli inspect archive.ghclip --source # readable source, control characters escaped
ghravioli inspect archive.ghclip --sha256 # a hash of each component's source
ghravioli extract archive.ghclip --output reviewed-source
inspect --source is the safe terminal view. ghravioli code is an exact
machine stream with nothing escaped, for redirecting to a file or another tool.
It refuses to write to a terminal when the source contains unsafe control
characters, unless you pass --unsafe-terminal. In a multi-component archive,
choose a component with --component N, counting from 1:
ghravioli code scale-points.ghclip > scale_points.py
ghravioli code pipeline.ghclip --component 2 > second.py
The inspector only accepts archives in the exact shape ghRavioli generates. That makes review easier, but it doesn't make the code safe to run. Embedded source keeps its own copyright and licence; building an archive doesn't grant the right to redistribute it. See security.
If the clipboard doesn't work
ghravioli copy writes the .ghclip file first, then tries pbcopy on macOS,
PowerShell on Windows, or wl-copy or xclip on Linux. If none is available,
move the file to the Rhino machine and run ghravioli copy scale-points.ghclip
there. As a last fallback, open the .ghclip as UTF-8 text, copy the whole XML
document and paste it onto the canvas. Don't double-click it; it isn't a
Grasshopper definition file.
Licence and support
ghRavioli is released under the MIT licence. You can use, change and redistribute it, including commercially, as long as the licence notice stays with copies. It is provided as is, with no support, warranty, or promise of fixes or updates.
Python API
The public API is load_manifest, build_bytes, build_file,
inspect_archive, ComponentManifest and GraphManifest. Everything else in
the package is internal and may change during the alpha. See
distribution for what a package install includes.
Development
PYTHONPATH=src python3 -m unittest discover -s tests -v
PYTHONPATH=src python3 -m compileall -q src scripts tests examples
PYTHONPATH=src python3 -m ghravioli --help
python3 scripts/sync_agent_skills.py --check
python3 scripts/audit_repository.py --tree
python3 -m build
python3 scripts/discover_artifacts.py --dist dist --json
python3 scripts/prepare_rhino_acceptance.py --output .audit/rhino-0.1.0a2
skills/grasshopper-python-components is the canonical skill. After editing
it, run python3 scripts/sync_agent_skills.py to update the copies in
.agents/skills/ and .claude/skills/. AGENTS.md and CLAUDE.md hold the
same repository instructions for agents working on ghRavioli itself.
Documentation
- Component contract
- Canvas presentation
- Data flow between components
- Compatibility
- Rhino acceptance
- Design
- Roadmap
- Security
- Distribution
- Release checklist
Rhino® and Grasshopper® are registered trademarks of TLM, Inc., doing business as Robert McNeel & Associates. ghRavioli is an independent project and is not affiliated with or endorsed by Robert McNeel & Associates. It bundles no Rhino or Grasshopper binaries.
Metadata
Release files for ghravioli 0.1.0a2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ghravioli-0.1.0a2.tar.gz | 113.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ghravioli-0.1.0a2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 159.5 kB
Release files / ghravioli-0.1.0a2.tar.gz
| Download URL | ghravioli-0.1.0a2.tar.gz |
|---|---|
| Size | 113.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d17ae9ad5927e5e1bf0ef1461e58cf8d8d5feef1a03f6a610085d4644a5ea37
|
|
BLAKE2b-256 checksum How to use checksums |
da6924b693263ceabfa4d7446f1643eeb6098ae9c3730ca76446b5dd3c3ab2e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency logRelease files / ghravioli-0.1.0a2-py3-none-any.whl
| Download URL | ghravioli-0.1.0a2-py3-none-any.whl |
|---|---|
| Size | 46.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
24171dae03c14c355ac506232ac2cf104e006fc942d6ff8a1548bbc8a4614fbc
|
|
BLAKE2b-256 checksum How to use checksums |
0c32a622bcbec8ee5a27f4f5475864ca16dfa33bf1e81f5f820b8b3c282021f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.
Transparency log