QuNex extensions
Contents
QuNex extensions#
QuNex can be extended with commands that are not part of the suite. An extension is a folder of code — written by your lab, by a collaborator, or by you — that QuNex picks up and offers as ordinary commands. Once an extension is in place, its commands are run exactly like any other QuNex command:
qunex example_hello --example_name=QuNex
They take parameters the same way, they are listed by qunex --a, they explain
themselves through qunex <command> --help, they write the same logs, and they can be
sent to a scheduler in the same way. Nothing about using an extension command is special,
which is the point.
This page is about using extensions: where they go, how to confirm QuNex found one, and what it means when an extension replaces a command QuNex provides. Writing an extension is a developer topic, covered by the QuNex SDK documentation — look there for Writing a QuNex extension and The QuNex extensions whitepaper.
Where an extension goes#
An extension is a single folder whose name starts with qx_ — for example
qx_example. QuNex looks for such folders in three places:
Location |
Use it when |
|---|---|
|
the extension should travel with the QuNex installation |
|
the extension is shared by everyone using this installation |
any folder listed in |
the extension lives somewhere of your own choosing |
The first two are searched automatically. The third is an environment variable holding a
colon-separated list of folders, in the same style as PATH, and it is the one to use
for an extension you keep in your home directory or on a shared filesystem.
The important detail is that these are folders that contain extensions, not
extensions themselves. If your extension is at
/home/user/qunex_extensions/qx_example, the variable names the folder above it:
# names the folder holding qx_example, not qx_example itself
export QUNEXEXTENSIONSFOLDERS="/home/user/qunex_extensions"
# QuNex reads it every time it runs -- nothing else has to be set up
qunex example_hello --example_name=QuNex
QuNex reads the variable on every call, so it is enough for it to be exported in the
shell you run qunex from. If you name a folder that is not there, QuNex says so and
carries on with the rest:
WARNING: extensions folder '/data/shared/qx_extensions' does not exist or is not a folder, skipping it.
Where more than one location holds an extension of the same name, the one found later wins — so a copy in a folder of your own takes precedence over one installed for everybody. That is a convenient way to try a modified version of a shared extension without disturbing the shared copy.
Confirming that QuNex found it#
Sourcing the QuNex environment reports every extension it picks up, with a line for each part of it, and that listing is a convenient confirmation that the search location is set the way you think it is:
QuNex extensions identified
---> Registering extension qx_example
... setting QXEXAMPLEPATH to '/home/user/qunex_extensions/qx_example'
... setting QXEXAMPLEBIN to '/home/user/qunex_extensions/qx_example/bin'
... added /home/user/qunex_extensions/qx_example/bin to PATH
... added /home/user/qunex_extensions/qx_example/python to QXEXTENSIONSPY
... added /home/user/qunex_extensions/qx_example/matlab to MATLABPATH
Note, though, that QuNex does not depend on this. An extension installed after you last sourced the environment still works — the listing simply will not mention it.
Being found is the first half. The second is that QuNex knows which commands the
extension offers, which it reads from a listing inside the extension folder called
qx_commands.yaml. Most extensions arrive with one already built. If yours does not, or
if the extension has been updated, one command builds it:
# build the command listing of the extension called qx_example
qunex build_qx_extensions --extensions=example
You have to say which extensions to build. If you are not sure what is installed, ask
with --extensions=check: it builds nothing and tells you what it can see.
qunex build_qx_extensions --extensions=check
--> Extensions QuNex can see (2):
qx_example /home/user/qunex_extensions/qx_example [registry built]
qx_mytools /home/user/qunex_extensions/qx_mytools [no registry yet]
--> Name the ones to build:
qunex build_qx_extensions --extensions=<name>[,<name>...]
or build every one of them:
qunex build_qx_extensions --extensions=all
The name may be written with or without the qx_ prefix, several names may be given
separated by commas, and --extensions=all builds every extension QuNex can find. When
the build finishes, it names what it wrote:
--> Built 1 extension registry:
- extension:example: /home/user/qunex_extensions/qx_example/qx_commands.yaml
This never touches the installation's own command listing, only the extension's. That matters more than it sounds: on a shared installation, and inside a container, the installation is usually read-only, and an extension is something you can register without needing to write to it at all.
The final confirmation is to ask QuNex for the commands you are expecting. They are listed alongside every other QuNex command:
qunex --a | grep example
- example_bash_greet: Greets whoever is named, from a bash script.
- example_greet_sessions: Greets every session in the batch file, once per session.
- example_hello: Greets whoever is named -- the smallest useful command an extension can ship.
- example_matlab_greet: Greets whoever is named, from MATLAB.
And each one explains itself in the usual way:
qunex example_hello --help
Running an extension's commands#
There is nothing to learn here: an extension command behaves like any other QuNex command.
qunex example_hello --example_name=QuNex --example_times=2
---> Command example_hello is provided by extension example
---> Parameters for example_hello
parameter source value
------------------------------------
example_name command line QuNex
example_times command line 2
------------------------------------
started running example_hello at 2026-08-21 16:25:07, track progress in
/home/user/qunex_logs/2026-08-21_16.25.07_example_hello/comlogs/tmp_example_hello_....log
-----------------------------------------
Hello, QuNex!
Hello, QuNex!
-----------------------------------------
---> Successful completion of task at 2026-08-21 16:25:07
The one line that is not quite like every other command is the first: whenever the command being run comes from an extension, QuNex says which extension it came from, before it lists the parameters. Commands that are part of the suite print no such line.
Commands that process sessions take --batchfile, --sessions and the rest of the
usual machinery, run over the sessions you select, and produce the same per-session
reports and final summary as the suite's own processing commands. Parameters can be set
in the batch file header exactly as they are for any command — see
On specification of processing parameters.
When an extension replaces a QuNex command#
An extension may ship a command with the same name as one QuNex provides. When it does, the extension's version is the one that runs, for every command you issue in that environment.
This is intended behaviour and is often the reason an extension exists: it lets a lab adjust how a step works for its own studies without modifying the QuNex installation. Nothing is changed on disk. The QuNex command is still there, and it is used again as soon as the extension is out of the way.
It does mean that two people running what looks like the same command can get different results, so QuNex tells you when it happens. The run says so above the parameter table, and writes the same line into the log:
---> Command check_study is provided by extension example, replacing the core command of the same name
To find out what the replacement actually does before you run it, ask for its help, which shows the description of whichever version is active:
qunex check_study --help
If that describes something other than what the QuNex documentation describes, the
extension's version is what you would get. The commands each extension provides can be
seen in the qx_commands.yaml file inside its folder.
To stop using an extension, take its folder out of the search location — or remove that
location from QUNEXEXTENSIONSFOLDERS. The commands it provided disappear on the next
call, and any command it was replacing is back.
What an extension can add#
An extension can contribute three kinds of code, and as a user you will not usually need to know which is which — the commands look the same either way:
Python commands, which is what most extensions provide;
MATLAB commands, called through the MATLAB or Octave installation QuNex is configured with;
bash commands, which are shell scripts run as QuNex commands.
An extension may also carry plain scripts of its own, which its commands call by name.
Those are not QuNex commands. To run one yourself in a terminal, you need it on your
PATH: sourcing the QuNex environment puts it there, provided the extension was already
installed when you sourced it, and otherwise you can add the extension's bin folder to
PATH by hand.
Using an extension with a container#
If you run QuNex from a container, the tidiest arrangement is to prepare the extension
on the host and give it to the container when it starts. Build the extension's command
listing on the host as above, then bind the folder that holds the qx_ folders onto
/opt/qx_extensions, which is one of the places QuNex always looks:
qunex_container --interactive \
--container=/path/to/qunex_suite-latest.sif \
--bind=/home/user/qunex_extensions:/opt/qx_extensions
Nothing else is needed: no environment variable, and no setting up inside the container.
An extension installed after the container has started works too, as long as QuNex can
see it, with one limitation — its plain scripts will not be on the PATH of the
container's prompt, because that was fixed when the container started.
Building the command listing from inside the container#
You do not have to prepare the extension on the host. If you are working on an extension and changing its commands, it is easier to bind the folder in and rebuild from inside the container as you go:
# inside the container, after binding the extension folder in as above
qunex build_qx_extensions --extensions=example
The listing is written beside the extension's own code, so because the folder is bound in from outside, the result is waiting for you on the host afterwards, and the next container you start already has it.
One thing to know if you reach for the other command. build_qx_registry rebuilds the
installation's own command listing, and inside a container that listing lives on the
container image, which is read-only. QuNex will tell you so rather than failing obscurely:
qunex build_qx_registry
---> ERROR in completing build_qx_registry:
Registry location is not writable
Could not write the registry to: /opt/qunex/qx_commands.yaml
The installation's own registry cannot be written, which is normal inside a
container: it lives on the container image, and that is read only.
Registering an extension does not need it. Build the extension instead:
qunex build_qx_extensions --extensions=<name>
Registering an extension never needs that listing rebuilt, so build_qx_extensions is
the command to reach for, inside a container and out of one.
