Install Hermes Plugins

View as Markdown

Hermes plugins extend the Hermes runtime inside a NemoClaw-managed sandbox. They are different from NemoClaw skills and from OpenClaw plugins, so install them through the Hermes plugin path instead of skill install.

How Hermes Loads Plugins

NemoClaw sets HERMES_HOME to /sandbox/.hermes when it starts the Hermes gateway. Hermes plugin directories live under /sandbox/.hermes/plugins/<plugin-name>. NemoClaw uses the same mechanism for its built-in Hermes integration, which the sandbox image bakes into /sandbox/.hermes/plugins/nemoclaw.

The built-in NemoClaw Hermes plugin provides sandbox status tools, skill reload support, managed-tool broker patches, and runtime grounding for the OpenShell sandbox. Do not replace or remove /sandbox/.hermes/plugins/nemoclaw when you add your own plugin.

Configure the Bundled Hindsight Plugin

The stock Hermes image provides a durable lazy-install directory at /sandbox/.hermes/lazy-packages. Hermes installs the bundled Hindsight plugin dependency in this directory as the sandbox user. The dependency does not modify the root virtual environment, and the managed target is not declared in the sealed .env file.

NemoClaw supports hindsight-client==0.6.1 for this workflow. Hermes checks this exact version before it loads the plugin. This version uses the OpenShell proxy path. Do not replace it with a 0.8.x client because those releases do not use the proxy environment.

Start the self-hosted Hindsight service on the host before you configure the plugin. The local-memory preset permits only GET and POST requests from the Hermes Python runtime to host.openshell.internal on port 8888. The preset does not permit another private host or port.

Add the preset to the sandbox:

$nemohermes <name> policy add local-memory --yes

Check the current Shields posture:

$nemohermes <name> shields status

If Shields are up, open a timed maintenance window before setup changes the Hermes configuration and lazy dependency directory:

$nemohermes <name> shields down --timeout 15m --reason "Configure Hindsight memory"

Run the Hermes setup command through the NemoClaw CLI:

$nemohermes <name> exec --tty -- hermes memory setup hindsight

Select local_external when Hermes asks for the connection mode. Set the API URL to http://host.openshell.internal:8888. Set the memory bank name for your workload. Accept the hermes default if you do not need a workload-specific name. After the setup command finishes, restart the gateway:

$nemohermes <name> gateway restart

If you lowered Shields for setup, restore them after the restart:

$nemohermes <name> shields up

The setup command installs hindsight-client==0.6.1 under /sandbox/.hermes/lazy-packages as the sandbox user. When memory.provider is hindsight, gateway startup repairs a missing approved dependency before it launches. After Shields lock the directory, the gateway can import the client, but neither the gateway nor the sandbox user can modify the dependency tree. The directory is outside the integrity-sealed .env, config.yaml, and .config-hash files. It is part of the Hermes durable state plan, so the dependency remains available after a gateway restart.

Verify the provider and dependency after the restart:

$nemohermes <name> exec -- hermes memory status
$nemohermes <name> exec -- python -c 'import os, sys; sys.path.insert(0, os.environ["HERMES_LAZY_INSTALL_TARGET"]); import hindsight_client; print(hindsight_client.__version__)'
$nemohermes <name> status

The version command must print 0.6.1. The status command must report a running Hermes gateway without an integrity failure or quarantine.

If an earlier root install changed /opt/hermes/.venv, rebuild the sandbox before you use the lazy-install path:

$nemohermes <name> rebuild --yes

A rebuild replaces the root virtual environment and preserves any captured lazy-install directory as declared Hermes state. If the dependency is absent from the restored directory, the next setup or gateway start reinstalls the supported client as the sandbox user.

Do not edit /sandbox/.hermes/.env to set HERMES_LAZY_INSTALL_TARGET. Do not install the dependency into /opt/hermes/.venv. Both paths change sealed inputs and can make gateway reconciliation fail.

The preset permits one local host route only. To use another approved Hindsight host or port, create a custom preset and name the exact endpoint. The --from-file and --from-dir paths accept --trusted-private-host for a private host. Refer to Create Custom Policy Presets for that procedure.

Choose an Install Path

The supported path for custom Hermes plugins is to bake the plugin into a custom sandbox image and onboard from that Dockerfile. Use this path when the plugin adds Python code, runtime hooks, or dependencies that Hermes must see at gateway startup.

nemohermes <name> skill install <path> is only for SKILL.md agent skills. It uploads skill instructions and refreshes skill discovery, but it does not install Hermes runtime plugins.

When you change plugin code or dependencies, update the custom image and rebuild the sandbox so the plugin remains reproducible. When you change a supported startup-only setting with a NemoClaw host command, restart the Hermes gateway from the host:

$nemohermes <name> gateway restart

The command reloads supported startup-only state through NemoClaw’s authenticated lifecycle controller. Use nemohermes <name> config set or nemohermes inference set for supported configuration changes so NemoClaw updates managed config metadata together. For the controller topology, trust boundary, health proof, and fail-closed behavior, refer to Understand Gateway Lifecycle Control.

Prepare a Build Directory

Put the custom Dockerfile and every file it needs to COPY in one directory. nemohermes onboard --from <Dockerfile> sends the Dockerfile’s parent directory as the Docker build context.

The one exception is the managed Hermes Dockerfile itself: passing the agents/hermes/Dockerfile from the NemoClaw checkout the CLI runs from stages the repository root as the build context, exactly as the managed build does. The managed exception applies the .dockerignore from the repository root, not one under agents/hermes/. Use that path when you want to edit the managed Dockerfile in place (for example, to install extra Python packages) and rebuild the stock image with your changes.

For a standalone custom Dockerfile, add a .dockerignore next to the Dockerfile to keep local caches, generated artifacts, model files, or other unneeded paths out of the staged context. NemoClaw still excludes credential-like paths such as .env*, .ssh/, .aws/, .npmrc, secrets/, *.pem, and *.key, even if .dockerignore tries to include them.

NemoClaw sends user-supplied --from contexts to the OpenShell gateway builder and reserves its host-side local BuildKit prebuild for contexts that NemoClaw generates itself. On a local Docker-driver gateway, a Local BuildKit build skipped notice is expected and the custom image build continues through the gateway. The managed Hermes Dockerfile keeps image probes in a checked-in runner so OpenShell gateway builders without Dockerfile heredoc support execute the same assertions.

my-hermes-plugin-sandbox/
├── Dockerfile
└── my-hermes-plugin/
├── __init__.py
└── requirements.txt

If you start from the stock NemoClaw Hermes Dockerfile, keep the NemoClaw Hermes image contract intact. The image must still include the generated Hermes config, NemoClaw Hermes plugin, blueprint files, nemoclaw-start entrypoint, root-only gateway control helper, root-only managed controller, and shared supervisor library.

A custom --from Dockerfile replaces the normal NemoClaw Hermes Dockerfile. Starting from ghcr.io/nvidia/nemoclaw/hermes-sandbox-base:latest alone is not enough. Your Dockerfile must also preserve the NemoClaw Hermes layers from agents/hermes/Dockerfile.

If gateway restart or recover reports privileged control unavailable for an older custom image, update the Dockerfile to the current Hermes image contract and rebuild it with nemohermes <name> rebuild --yes. The current contract supports a direct root entrypoint and the OpenShell-managed topology where OpenShell is PID 1 and launches nemoclaw-start as nonroot.

An arbitrary nonroot entrypoint that does not match the supported OpenShell-managed process shape cannot use lifecycle control. Kubernetes and other deployments without a matching direct container fail closed and do not fall back to ordinary openshell sandbox exec or an in-sandbox manual relaunch.

Install the Plugin in the Image

Add your plugin after the Dockerfile has created /sandbox/.hermes. The example below shows the layer that copies a plugin directory into the Hermes plugin tree.

1COPY my-hermes-plugin/ /opt/my-hermes-plugin/
2
3USER root
4RUN mkdir -p /sandbox/.hermes/plugins/my-hermes-plugin \
5 && cp -a /opt/my-hermes-plugin/. /sandbox/.hermes/plugins/my-hermes-plugin/ \
6 && if [ -f /opt/my-hermes-plugin/requirements.txt ]; then \
7 /opt/hermes/.venv/bin/python -m pip install --no-cache-dir -r /opt/my-hermes-plugin/requirements.txt; \
8 fi \
9 && chown -R sandbox:sandbox /sandbox/.hermes/plugins/my-hermes-plugin \
10 && chmod -R a+rX /sandbox/.hermes/plugins/my-hermes-plugin
11
12USER sandbox
13WORKDIR /sandbox

Keep plugin code and dependency files inside the build directory. Avoid copying host credentials, local caches, or broad home-directory contents into the image.

Create the Sandbox

Run onboarding with the custom Dockerfile and an explicit sandbox name. NemoClaw requires a name for --from builds so a custom image cannot silently replace the default sandbox.

$nemohermes onboard --name my-hermes-build --from ./my-hermes-plugin-sandbox/Dockerfile

For non-interactive onboarding, set the same values through environment variables.

$NEMOCLAW_NON_INTERACTIVE=1 \
>NEMOCLAW_SANDBOX_NAME=my-hermes-build \
>NEMOCLAW_FROM_DOCKERFILE=./my-hermes-plugin-sandbox/Dockerfile \
>nemohermes onboard

If you resume an interrupted onboarding run, use the same Dockerfile path that started the session. NemoClaw records the custom Dockerfile path and rejects a resume that points at a different image source.

Network Access

Hermes plugins still run inside the OpenShell sandbox boundary. If a plugin calls an external API at runtime, add a policy preset for the required hostnames and binaries before you recreate the sandbox.

Hermes uses Python for plugin execution, so policy entries usually need to allow the Hermes Python runtime, such as /opt/hermes/.venv/bin/python, in addition to any command-line wrapper your plugin starts. For package downloads during sandbox runtime, use the pypi preset or a custom preset that allows the package hosts you need.

Refer to Network Policies for policy concepts. Refer to Customize Network Policy for custom preset workflows.

Common Mistakes

The following places commonly mix Hermes plugin installation with other NemoClaw extension paths.

  • Do not use skill install for Hermes runtime plugins.
  • Do not install Hermes plugins into /sandbox/.openclaw/extensions; that path is for OpenClaw plugins.
  • Do not remove /sandbox/.hermes/plugins/nemoclaw; NemoClaw depends on that plugin for managed Hermes behavior.
  • Do not put the Dockerfile in a broad directory unless you intend to send that whole directory as the Docker build context.
  • Do not rely on .dockerignore to include credential-like paths; NemoClaw excludes those from staged custom build contexts for safety.
  • Do not assume OpenShell policy allows Python package downloads during runtime by default.
  • Do not install a bundled lazy dependency into /opt/hermes/.venv or declare its target in the sealed .env file.

Next Steps