tofupilot plug
Last updated on October 27, 2026
The plug command opens one of a procedure's plugs outside any run, so you can try an instrument driver before writing the phase that uses it. It uses the procedure's venv, building it first when there is none yet (as tofupilot run does, asking first on a terminal, never with --json; no phase runs), and the plug's with: and env: resolved as a local run resolves them (.env files, shell variables).
ls
Lists the procedure's plugs, with their class and with: values. Every subcommand reads the procedure in the current directory, or the one --path names (before or after the subcommand); ls, whose one target is the procedure, also takes it as its PATH, as validate and run do.
tofupilot plug ls ./procedures/boardmethods <KEY>
Lists a plug's methods, inherited ones and static or class methods included, their parameters and the first line of their docstring, and the parameters of __init__, which receive the plug's with:. The class is read without being instantiated, so no instrument is opened. Underscore methods are left out: plug call refuses them. With --json, each method gives the file and line it is defined at (the parent class's file for an inherited one), and a parameter's kind is what plug call accepts (positional_or_keyword, keyword_only…), and phase_call_kind what a phase's call through the plug accepts: a phase passes positional arguments only, so a keyword-only parameter reads unreachable there (it keeps its default). phase_reachable is false for a method named call or deadline, which the plug proxy keeps for itself: plug call reaches it, a phase does not.
tofupilot plug methods psu --jsoncall <KEY> <METHOD>
Opens the plug, calls one method, prints its return value on stdout (a string as is, anything else as JSON, nothing for None, so v=$(tofupilot plug call psu read) reads it) and closes the plug. --args takes the positional arguments as a JSON array, --kwargs the keyword arguments as a JSON object. The method name and the arguments are checked against the class before the plug opens: an unknown method or parameter, a missing argument, or one given both in --args and in --kwargs, exits with code 2 without touching the instrument. An exception in the method prints its traceback, without the plug service's own frames, and exits with code 1; with --json, each call carries its args and kwargs, and on failure error_type (the exception class, or error for a refusal of the plug service such as a method it no longer has, connection when the plug's process is gone) and error_message, and the plug's log lines come in logs rather than on stderr (levels upper case, as run --json writes them), and a procedure that does not load, a with: that does not resolve or names a parameter the plug's __init__ does not take (checked before the plug opens), or a plug that fails to open (plug_error), exits with code 1 too. A call that does not answer within --timeout seconds (60 by default) fails with error_type timeout. Ctrl-C or a signal closes the plug and exits with the signal's code (130, 143, 129); a call it cut is listed with error_type stopped, the calls after it are counted in not_run. On a multi-slot procedure, a scope: slot plug opens as the first slot's ({run.slot.key} and {run.slot.name} in its with: read that slot); set another slot's values with --config.
tofupilot plug call psu set_voltage --args '[5.0]'--script <FILE>
To keep one session across several calls (configure, then measure), pass a JSON array of {method, args?, kwargs?} objects (any other key is refused), or - to read it from stdin. The calls run in order and stop at the first failure, unless --keep-going; the calls left out are counted (not_run with --json). A script file that does not exist, or cannot be read, is a usage error (exit 2).
echo '[{"method": "set_voltage", "args": [5]}, {"method": "read"}]' | tofupilot plug call psu --script ---config <JSON>
Overrides the plug's with: values for this command only. The YAML is not written. A key the plug's __init__ does not take is refused before the plug opens (exit 2).
tofupilot plug call psu read --config '{"port": "/dev/ttyUSB1"}'--timeout <SECONDS>
A call that does not answer within this time fails (default 60), with error_type "timeout" under --json. The plug is closed either way: closing a plug whose method is still running waits a few seconds for its cleanup before the process is ended, so the command takes that long past the timeout. Opening the plug is not a call: its __init__ gets the plug's init_timeout (30 seconds by default), as in a run, whatever --timeout says.
An instrument held by another process (a station service, a run, Studio's plug debugger) cannot be opened twice: the open fails with the operating system's error. Stop the other process first.
How is this guide?