Decorator tracking
Turn any Python function into a tracked run.
The @hub_run decorator turns any plain Python function into a tracked Hub
run. Add the decorator, accept a context as the first argument, and you
immediately get:
- A logging client — record parameters, metrics, and artifacts to the Hub.
- Devices — access to any connected hardware.
- Artifact directories — timestamped, run-scoped folders on the local machine and on each connected device, for full traceability.
If you want to hand off a result to a built-in profiling or invocation component, that works too — see Handing off to built-in components.
Prerequisites
Before following this guide, make sure you have completed the setup guide to:
- Create an Embedl Hub account
- Install the
embedl-hubPython library - Configure an API key
Setting up a context
HubContext is the object you pass to every hub run function. At minimum,
all you need is a project name:
Wrapping a function
Add @hub_run above your function and declare ctx: HubContext as its
first parameter. Call the function from inside a with ctx: block:
The decorator handles the run lifecycle automatically — it opens a tracking
session when the function is called and closes it (or marks it failed) when
the function returns or raises. Returning ctx.run_log is recommended so
that downstream runs can be linked to this one (see Chaining runs).
The run type
The first argument to @hub_run is the run type. It tells the Hub which
category of work this run represents.
Use a built-in type from RunType to map onto a known Hub category:
Use a custom string for any domain-specific step:
You can also pass an optional name to override the display name shown on
the Hub (the function name is used by default):
The context block
The with ctx: block is where your runs execute. Entering it prepares
artifact directories for the coming runs and connects any devices you added
to the context. Exiting it disconnects them and cleans up. All decorated
function calls must happen inside this block.
What the context gives you
The client
ctx.client lets you log parameters, metrics, and artifacts to the Hub:
All logged data appears on your Hub run page alongside the run’s status, duration, and lineage.
Run logs
For every run, all logged parameters, metrics, artifacts, and device info are recorded into a run log — along with metadata like the run type and name.
ctx.run_log gives you access to the log of the currently executing run.
Returning it from your function is what enables chaining and lineage tracking,
as described below.
Devices
Devices are optional — skip this if your script runs entirely on the host
machine. To connect remote hardware, create a device with DeviceManager.get_ssh_device and pass it to the context:
The name is how you refer to the device inside your functions — ctx.devices["pi"] — and how it appears in run logs on the Hub. Choose
something that identifies the hardware clearly, especially when working
with multiple devices at once.
SSH devices come with a command runner (device.runner) that lets you
execute shell commands on the remote machine over the established
connection. This is how you trigger inference, run benchmarks, or invoke
any script that needs to run on the target hardware.
Artifact directories
Each run gets its own timestamped directories — one on the local machine and one on each connected device. You don’t have to use them, but if you want your outputs to be traceable and reproducible across runs, writing into these directories is the way to go.
Local: ctx.artifact_dir — write model files, reports, or any other
output that lives on the host:
Per device: ctx.devices["pi"].artifact_dir — a corresponding
directory on the device itself, useful when the device produces its own
output files:
Always write outputs into the provided artifact directories rather than hard-coded paths. Directories are unique per run, so re-running your script never overwrites previous results.
Chaining runs
Passing a RunLog from a previous run into another hub run function will
automatically link them in the Hub’s lineage view. The same applies to ComponentOutput — the result type that pre-made components produce and
consume. For run linkage to work, the passed value must be one of these types:
Validating run inputs
When a function receives a RunLog, you can inspect its contents to verify
it is compatible before proceeding — checking the run type, name, or any
logged parameters, metrics, or artifacts:
This is useful for catching mismatched pipelines early, especially when functions are reused across different run sequences.
Handing off to built-in components
Your script can produce output that feeds directly into a built-in profiling
or invocation component. To do this, return a typed ComponentOutput subtype
instead of ctx.run_log.
The key is to log your artifacts with the field names the output type
expects, then call OutputType.from_run_log(ctx.run_log) to build the
typed result:
Once you have a TFLiteCompiledModel, pass it straight to the profiler:
The profiler receives a fully typed result and the two runs are linked in the Hub’s lineage view. See the Your hardware guides for how to configure devices for profiling.
Complete example
The following script shows a three-step pipeline: data preparation, training, and evaluation. The last step produces a compiled model that is handed off to a built-in profiler.