MyPrivateClaw logo
MyPrivateClaw
Private AI Directory
Agent Frameworks 45 min readMar 31· Updated Jul 13, 2026✓ Verified 2026-07-13

Hermes Agent + Ollama on Ubuntu: Build a Sandboxed Local Agent

An Ubuntu 24.04.4-validated build using CPU-only KVM guests, measured local models, and an isolated Docker terminal before real project work.

hermes-agent ollama local-llm agentic sandbox docker nous-research

What this build does

This runbook was clean-room validated on July 12, 2026 in fresh Ubuntu 24.04.4 KVM guests running on hermes-coord. The guests were CPU-only, had no GPU, no host directory mounts, no credentials, restricted egress, a hard lifetime, and automatic destruction. The tested software was Hermes Agent 0.18.2 and Ollama 0.31.2.

The build separates local model inference from agent execution and puts Hermes terminal commands in a constrained Docker container. Those are different controls. A local model does not sandbox commands, and a Hermes profile does not isolate the host filesystem. The starting container has no network, host workspace mount, forwarded secrets, or cross-process persistence. Use a disposable VM instead of Docker for unknown installers, hostile repositories, security research, or any workload that needs a separate kernel boundary.

THE EDGE — WEEKLY DIGEST

Get more guides like this in your inbox

No spam. Unsubscribe anytime.

Validation environment and scope

The latest stable Hermes release at validation time was v0.18.2 (v2026.7.7.2). The end-to-end path used a manual OpenAI-compatible endpoint at http://127.0.0.1:11434/v1. Check the official release page before installation because Hermes changes quickly.

The macOS notes below are reference guidance derived from current vendor documentation. We did not perform a clean-room macOS installation, Docker Desktop validation, 64K-context validation, Hermes tool-sandbox run, or model benchmark. Do not treat the Linux timing, memory, or security results as macOS evidence.

Sources: Hermes releases, Hermes installation, Ollama's Hermes integration, Ollama on macOS, and Docker Desktop on Mac.

PathEnvironmentValidation status
Ubuntu low-resource6 vCPU, 16 GiB RAM, no GPUFull bounded build passed end to end
Ubuntu coding candidate12 vCPU, 32 GiB RAM, no GPUNorth model timed out in full Docker workflow
Ubuntu rootless DockerFresh Ubuntu 24.04.4 KVM guestEnd-to-end validated
macOSDocker Desktop + Ollama appDocumented reference only; not lab-validated
GPU accelerationAny platformNot tested

Choose a model from measured tiers

These recommendations come only from the CPU-only Ubuntu KVM guests described above. They are not macOS, Apple Silicon, GPU, or hardware-normalized benchmarks.

Use qwen3.5:9b with the bounded settings in Steps 5 and 6. In the 6-vCPU, 16-GiB guest it loaded at 8.7 GB, returned the exact 64K connectivity marker in 4 minutes 43 seconds, and completed the full Docker-mounted inspect-edit-test workflow in about 16 minutes 45 seconds. It returned the exact final marker, changed only the implementation, preserved the test file, and passed all three independent host tests. The complete fresh-VM procedure finished in about 30 minutes.

The bounds matter. In an earlier run with default thinking and a much larger iteration allowance, Qwen corrected the source and passed tests but continued generating after success. Sending think: false to the matching local endpoint and limiting Hermes to 12 iterations produced the clean pass above.

Do not substitute north-mini-code-1.0 merely because it is coding-focused. In a 12-vCPU, 32-GiB guest it loaded at 19 GB and passed a simple local-terminal coding exercise, but the complete Docker-mounted workflow timed out after 30 minutes following only its first file read. It is therefore not the recommended model for this exact CPU-only guide.

gemma4:12b also worked in a 16-GiB guest at 64K but was slower than Qwen. qwen3.6:27b worked in a 32-GiB guest at 64K but took over ten minutes for one cold Hermes response. Model pages and publisher benchmarks are screening data, not substitutes for testing the actual Hermes harness on your hardware.

Sources: Qwen 3.5, North Mini Code, Gemma 4, and Qwen 3.6.

Expected time and stopping points

The page's 45-minute label is reading time, not a guaranteed build duration. The final 6-vCPU clean-room run took about 30 minutes after the VM was ready: roughly 13 minutes through installation, configuration, the cold Hermes call, Docker setup, and image pulls, then 16 minutes 45 seconds for the Docker-mounted agentic task. Network speed, storage speed, CPU generation rate, and model cache state can add substantial time. Budget 60 minutes for a first CPU-only build and stop at each checkpoint instead of continuing after a failed command.

You need two terminal windows for the live container-inspection checkpoint. You also need temporary sudo access for Ubuntu package installation and systemd changes. Hermes itself, Ollama requests, rootless Docker, and project work run as your normal user. Do not perform the fresh-host Docker conversion on a machine already hosting rootful production containers.

Preflight checklist

For the validated Ubuntu path, use a normal non-root user with sudo access. The 9B lab build used 16 GiB RAM and a 35 GiB sparse guest disk; allow additional free disk for Ubuntu packages, Docker layers, logs, and future model updates. These are tested guest allocations, not universal minimums. Docker is required for the recommended terminal sandbox. A GPU was not tested. Stop if disk is tight or another memory-heavy workload is active. If Docker is already installed, inspect existing containers before changing its daemon mode; do not disable a rootful daemon that hosts real workloads.

bash
uname -a
free -h 2>/dev/null || vm_stat
df -h .
command -v docker && docker ps -a || true

Step 0A: Install rootless Docker on fresh Ubuntu

This path was clean-room validated on Ubuntu 24.04.4. It installs Docker's packaged rootless components, disables the newly installed rootful daemon, and runs Docker as your normal user. Do not use these commands on a machine whose existing rootful Docker daemon hosts workloads. Log in normally as the target user; sudo su can omit the user-systemd environment that rootless Docker needs. If your distribution is not Ubuntu, follow Docker's official package and rootless-mode documentation instead of adapting these commands blindly.

bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl git python3 jq nano uidmap dbus-user-session slirp4netns fuse-overlayfs

curl --fail --show-error --location --proto '=https' --tlsv1.2 \
  https://get.docker.com -o /tmp/get-docker.sh
sha256sum /tmp/get-docker.sh
sh -n /tmp/get-docker.sh
sudo sh /tmp/get-docker.sh

# Fresh host only: turn off the just-installed rootful daemon.
sudo systemctl disable --now docker.service docker.socket
sudo loginctl enable-linger "$USER"

test -n "${XDG_RUNTIME_DIR:-}" || {
  echo 'XDG_RUNTIME_DIR is missing; log out and back in normally, then retry.' >&2
  exit 1
}
dockerd-rootless-setuptool.sh install
systemctl --user enable --now docker

export DOCKER_HOST="unix:///run/user/$(id -u)/docker.sock"
grep -Fqx "export DOCKER_HOST=$DOCKER_HOST" ~/.profile 2>/dev/null || \
  printf '\nexport DOCKER_HOST=%s\n' "$DOCKER_HOST" >> ~/.profile
docker context use rootless
docker info | sed -n '/Security Options:/,/Kernel Version:/p'
docker run --rm hello-world
# PASS only when Security Options includes: rootless

macOS reference: Install Docker Desktop (not validated)

This path was not run in our clean-room lab. Follow Docker's official macOS installation instructions for the correct Apple Silicon or Intel package, start Docker Desktop, and wait for its engine to become ready. Do not apply the Linux systemd or rootless-daemon commands on macOS. Docker Desktop runs containers inside a managed Linux VM, but host directories you bind-mount still retain their host permissions. The commands below are acceptance checks for you to run, not results we observed.

bash
docker version
docker run --rm hello-world

Step 1A: Install Ollama on Ubuntu

This installer sequence was validated in the Ubuntu guests. Download the script, syntax-check it, then run it and confirm both the CLI and loopback API. Do not expose port 11434 to the LAN for this build. These shell-installer commands are not the macOS installation path.

bash
curl -fsSLo /tmp/ollama-install.sh https://ollama.com/install.sh
sh -n /tmp/ollama-install.sh
sh /tmp/ollama-install.sh
ollama --version
curl -fsS http://127.0.0.1:11434/api/tags

macOS reference: Install the Ollama app (not validated)

We did not run this path end to end. Ollama's current macOS documentation requires macOS Sonoma 14 or newer and recommends mounting the official DMG, moving Ollama to Applications, starting the app, and allowing it to place the CLI on PATH. Apple M-series Macs support CPU and GPU execution; Intel Macs are CPU-only. After following the official instructions, run the acceptance checks below yourself before continuing. Source: Ollama on macOS.

bash
ollama --version
curl -fsS http://127.0.0.1:11434/api/tags

Step 2: Pull one model

Download only the model used by the validated build. Starting with several models consumes disk without improving the first build. Do not substitute North for this CPU-only procedure: it passed a smaller coding test but timed out in the full Docker-mounted validation. Run the remaining setup in this shell. If you open a new shell, repeat the export MODEL=... line before model checkpoints.

bash
export MODEL=qwen3.5:9b

ollama pull "$MODEL"
ollama show "$MODEL"
REQUEST=$(jq -n --arg model "$MODEL" '{
  model: $model,
  prompt: "Reply briefly: local model ready",
  stream: false,
  think: false,
  options: {num_predict: 32}
}')
curl --fail --show-error --max-time 900 \
  -H 'Content-Type: application/json' \
  --data-binary "$REQUEST" \
  http://127.0.0.1:11434/api/generate | jq -e \
  '.done == true and (.response | length > 0)'

Step 3A: Set 64K context on Linux

Ollama may allocate only 4,096 tokens on a CPU or low-VRAM machine even when the model advertises much more. Hermes 0.18.2 rejected the tested 32K agent configuration, so set both Ollama and Hermes to at least 64,000. On a systemd Linux install, use a service drop-in and restart Ollama.

bash
sudo install -d -m 0755 /etc/systemd/system/ollama.service.d
printf '%s\n' '[Service]' 'Environment="OLLAMA_CONTEXT_LENGTH=64000"' \
  | sudo tee /etc/systemd/system/ollama.service.d/95-hermes-context.conf >/dev/null
sudo systemctl daemon-reload
sudo systemctl restart ollama
systemctl is-active ollama
systemctl show ollama --property=Environment

macOS reference: Set 64K context (not validated)

This step was not run in our lab. Open the Ollama application settings, set Context length to at least 64K, restart Ollama, then perform Checkpoint 1 yourself. Do not assume changing Hermes later will resize the Ollama runner. The effective allocation must be checked after the model is loaded.

Checkpoint 1: Verify the effective context

Load the model after restarting Ollama through the bounded loopback API request from Step 2, then inspect the live runner. Avoid using interactive ollama run for a scripted checkpoint; it hung before sending an API request in one clean-room retry. The CONTEXT column must show 64000 or greater. If it shows 4096 or another smaller number, fix Ollama before installing Hermes.

bash
export MODEL=${MODEL:-qwen3.5:9b}
ollama ps
# PASS only when the selected model is listed with CONTEXT >= 64000
# If no runner is listed, repeat the bounded API request from Step 2.

Step 4: Install Hermes

The command sequence below is the non-interactive path used in the Ubuntu clean-room run. It deliberately skips initial provider setup and browser dependencies; the next step configures Ollama explicitly. Reload the shell only if hermes is not immediately on PATH. Hermes supports macOS, but this guide did not validate a fresh macOS Hermes installation. Browser automation is outside this build and must be installed and tested separately if needed.

bash
curl --fail --show-error --location --proto '=https' --tlsv1.2 \
  https://hermes-agent.nousresearch.com/install.sh -o /tmp/hermes-install.sh
sha256sum /tmp/hermes-install.sh
bash -n /tmp/hermes-install.sh
HERMES_HOME="$HOME/.hermes" bash /tmp/hermes-install.sh \
  --non-interactive --skip-setup --skip-browser

export PATH="$HOME/.local/bin:$HOME/.hermes/bin:$PATH"
command -v hermes
hermes --version

Step 5: Connect Hermes to Ollama

Configure the exact endpoint non-interactively. Ollama does not require a real API key, but the OpenAI-compatible client expects a non-empty value, so use the inert string no-key. The model name must exactly match the Ollama tag you pulled. The matching custom-provider entry sends Ollama's think: false extension for this operational smoke build; this avoids long post-tool reasoning loops while preserving the normal tool loop. These commands write normal settings to ~/.hermes/config.yaml; they do not add a cloud provider or fallback.

bash
export MODEL=${MODEL:-qwen3.5:9b}
hermes config set model.provider custom
hermes config set model.base_url http://127.0.0.1:11434/v1
hermes config set model.api_key no-key
hermes config set model.default "$MODEL"
hermes config set model.context_length 64000
hermes config set model.max_tokens 4096
hermes config set custom_providers.0.name ollama-local
hermes config set custom_providers.0.base_url http://127.0.0.1:11434/v1
hermes config set custom_providers.0.model "$MODEL"
hermes config set custom_providers.0.extra_body.think false
hermes config check
# Inspect the effective non-secret settings:
hermes config show | sed -n '/^model:/,/^[^ ]/p'

Step 6: Allow slow local inference

CPU-only responses can take minutes. The API timeout allows one slow model call to finish, while the iteration cap prevents an agent from making dozens of unnecessary follow-up calls. Twelve iterations are enough for this five-tool smoke task but should be reevaluated for larger projects. The Ubuntu command below updates existing values instead of adding duplicates. Do not use a 256-token output cap: an earlier validation consumed it in reasoning and entered truncated-response recovery.

bash
install -d -m 0700 ~/.hermes
touch ~/.hermes/.env
if grep -q '^HERMES_API_TIMEOUT=' ~/.hermes/.env; then
  sed -i 's/^HERMES_API_TIMEOUT=.*/HERMES_API_TIMEOUT=1800/' ~/.hermes/.env
else
  printf '%s\n' 'HERMES_API_TIMEOUT=1800' >> ~/.hermes/.env
fi
if grep -q '^HERMES_MAX_ITERATIONS=' ~/.hermes/.env; then
  sed -i 's/^HERMES_MAX_ITERATIONS=.*/HERMES_MAX_ITERATIONS=12/' ~/.hermes/.env
else
  printf '%s\n' 'HERMES_MAX_ITERATIONS=12' >> ~/.hermes/.env
fi
chmod 0600 ~/.hermes/.env
hermes config check

Checkpoint 2: Verify model connectivity

Use a one-shot call first. This proves endpoint and context compatibility, not tool competence. A cold CPU call can appear idle for several minutes; monitor Ollama rather than repeatedly restarting it.

bash
hermes -z 'Reply with exactly MPC_HERMES_OLLAMA_OK and no other text.'
ollama ps
# PASS only when the exact marker is returned and CONTEXT remains >= 64000

Step 7A: Pull and inspect the sandbox image

Pull the tool image explicitly before disabling network access inside tool containers. This confirms the daemon can reach the registry and prevents the first Hermes tool call from failing on a missing image. Record the resolved image ID; the tag is mutable, so re-check it after future pulls.

bash
export SANDBOX_IMAGE=nikolaik/python-nodejs:python3.11-nodejs20
docker pull "$SANDBOX_IMAGE"
docker image inspect --format 'id={{.Id}} size={{.Size}}' "$SANDBOX_IMAGE"
# PASS only when pull and inspect both succeed

Step 7B: Configure a conservative Docker terminal sandbox

Hermes defaults to the local terminal backend, which gives the agent the same filesystem access as your user. Back up the working configuration now, then run hermes config edit and replace its terminal block with the YAML below. Do not replace the rest of config.yaml. Run hermes config check after saving.

The starting profile has no host workspace mount, forwarded environment variables, extra volumes, network, or cross-process persistence. Docker containers share the host kernel; this is useful containment, not a VM boundary. On Linux, access to a rootful Docker daemon through the docker group is effectively root-equivalent. Prefer rootless Docker and never mount a Docker socket into the agent container. The tested rootless overlay filesystem did not support per-container disk quotas, so CPU, memory, and PID limits did not cap disk consumption; monitor free disk and use a disposable VM for hostile or storage-abusive workloads. Sources: Hermes configuration and Hermes security.

yaml
terminal:
  backend: docker
  docker_image: nikolaik/python-nodejs:python3.11-nodejs20
  docker_mount_cwd_to_workspace: false
  docker_run_as_host_user: false
  docker_forward_env: []
  docker_env: {}
  docker_volumes: []
  docker_extra_args: []
  docker_network: false
  container_cpu: 2
  container_memory: 4096
  container_persistent: false
  docker_persist_across_processes: false
  docker_orphan_reaper: true
  timeout: 180
  lifetime_seconds: 300

Step 7C: Save and validate the Hermes configuration

Create the backup before editing, save the YAML through hermes config edit, then run the validation commands. If configuration checking fails, restore the backup and do not start an agent session.

bash
cp -a ~/.hermes/config.yaml ~/.hermes/config.yaml.before-local-sandbox
hermes config edit
# Paste only the Step 7B terminal block, save, and exit the editor.
hermes config check
hermes doctor
# PASS only when config check succeeds and doctor reports no blocking error

Interpret first-run warnings

A fresh Hermes 0.18.2 configuration can report an older config version and list many optional unset integrations. That is not a failed local build when no required field is missing and hermes config check exits successfully. Do not add cloud keys merely to clear optional notices. Use hermes config migrate later if the checker says required options are missing.

The sandbox command can print /root and uid=0 inside the container because this conservative profile does not map your host identity into it. With the validated rootless Docker daemon, that container root maps to an unprivileged host user; it is not host root. The separate docker info rootless check is what proves this distinction. A warning that the storage driver cannot enforce per-container disk limits is also expected in the tested guest and is why disk capacity remains an operator responsibility.

Checkpoint 3: Prove tools are isolated

Open two shells. In Shell 1, start Hermes and ask it to run the exact long-lived command below with its terminal tool. While that command is sleeping, inspect the live container from Shell 2. This removes the timing race caused by inspecting after a short command has already exited. The working directory must be inside the container, network mode must be none, the PID limit must be finite, capabilities must include ALL in the drop list, no-new-privileges must be present, and mounts must not include your home or Docker socket. End the Hermes session after the check. A model's success sentence is not evidence.

bash
# Shell 1
hermes
# Send this prompt:
# Use the terminal tool to run exactly:
# pwd; id; ls -la /workspace; sleep 120

# Shell 2, while sleep is running
CID=$(docker ps --filter label=hermes-agent=1 --format '{{.ID}}' | head -1)
test -n "$CID"
docker inspect --format 'network={{.HostConfig.NetworkMode}} pids={{.HostConfig.PidsLimit}} capdrop={{json .HostConfig.CapDrop}} security={{json .HostConfig.SecurityOpt}} mounts={{json .Mounts}}' "$CID"
# PASS requires network=none, finite pids (validated value: 256),
# CapDrop containing ALL, no-new-privileges, and no unexpected host mounts.
# Back in Shell 1, also ask the terminal tool to run:
# curl --max-time 5 -I https://example.com
# PASS only when that network request fails.

Step 8A: Create a disposable failing project

Create the exact fixture used by the clean-room test. It contains one implementation bug and three standard-library tests, so no package download or network access is needed. The final command must fail before Hermes runs; if it passes, stop because the fixture is wrong.

bash
export FIXTURE=$HOME/hermes-sandbox-smoke
test ! -e "$FIXTURE" || { echo "Refusing to overwrite $FIXTURE" >&2; exit 1; }
install -d -m 0700 "$FIXTURE"
cat > "$FIXTURE/calculator.py" <<'PY'
def average(values):
    if not values:
        raise ValueError("values must not be empty")
    return sum(values) // len(values)
PY
cat > "$FIXTURE/test_calculator.py" <<'PY'
import unittest
from calculator import average

class AverageTests(unittest.TestCase):
    def test_fractional_average(self):
        self.assertEqual(average([2, 3]), 2.5)

    def test_integer_average(self):
        self.assertEqual(average([2, 4]), 3)

    def test_empty_input(self):
        with self.assertRaises(ValueError):
            average([])

if __name__ == "__main__":
    unittest.main()
PY
(cd "$FIXTURE" && ! python3 -m unittest -v)
echo "EXPECTED FAIL: fixture is ready at $FIXTURE"

Step 8B: Mount only the disposable project

Run printf '%s\n' "$FIXTURE" and copy the resulting absolute path. In hermes config edit, change only docker_volumes from [] to the mapping below, replacing /home/YOU with that absolute path. Keep docker_network: false and every other hardening setting unchanged. Then run hermes config check.

yaml
terminal:
  # Keep every Step 7B setting; change only this field:
  docker_volumes:
    - /home/YOU/hermes-sandbox-smoke:/workspace/project

Step 8C: Run and independently verify the agentic task

Record the test hash, give Hermes an exact path and completion contract, then verify the result from the host. The model must edit only calculator.py, run all tests, and return the requested marker. The bounded clean-room run satisfied that contract, but the host checks remain authoritative: they prove the protected test stayed unchanged, only the two expected files exist, the implementation contains real division, and all tests pass. If any host check fails, do not mount a real project.

bash
export FIXTURE=${FIXTURE:-$HOME/hermes-sandbox-smoke}
sha256sum "$FIXTURE/test_calculator.py" > /tmp/hermes-smoke-test.before.sha256
hermes -z 'Work only in /workspace/project. Use your tools to inspect the Python project. Fix the implementation bug by editing only calculator.py. Do not edit test_calculator.py and do not create other files. Run python3 -m unittest -v from /workspace/project. Only after all tests pass, reply exactly MPC_AGENTIC_FIX_OK.'

(cd "$FIXTURE" && python3 -m unittest -v)
(cd "$FIXTURE" && sha256sum --check /tmp/hermes-smoke-test.before.sha256)
grep -Fqx '    return sum(values) / len(values)' "$FIXTURE/calculator.py"
test "$(find "$FIXTURE" -maxdepth 1 -type f | wc -l)" -eq 2
echo 'PASS: observable edit, protected test, and independent tests verified'

Step 8D: Remove the smoke mount and fixture

Before real work, change docker_volumes back to [], run hermes config check, and remove only the known disposable fixture. The path guard prevents an accidental broad deletion.

bash
hermes config edit
# Restore: docker_volumes: []
hermes config check

export FIXTURE=${FIXTURE:-$HOME/hermes-sandbox-smoke}
case "$FIXTURE" in
  "$HOME/hermes-sandbox-smoke") rm -rf -- "$FIXTURE" ;;
  *) echo "Refusing unexpected cleanup path: $FIXTURE" >&2; exit 1 ;;
esac
test ! -e "$FIXTURE"
echo 'PASS: disposable fixture removed'

Opt in to one real project

Only after every checkpoint and the disposable agentic smoke pass should you mount a real project. Start from a clean Git branch or backup and confirm git status --short yourself. Add exactly one absolute host path to docker_volumes; do not mount your home directory, Docker socket, SSH directory, or cloud credentials. Keep network disabled unless the task specifically needs it. If package downloads are required, enable network only for that task, forward no secrets by default, and restore docker_network: false afterward.

Replace the host path below with your project. After editing, run hermes config check, start with a read-only inspection request, review what Hermes can see, and only then authorize edits.

yaml
terminal:
  backend: docker
  docker_mount_cwd_to_workspace: false
  docker_forward_env: []
  docker_network: false
  docker_volumes:
    - /absolute/path/to/my-project:/workspace/project

Build completion checklist

The installation is complete only when every gate below passes. A model response alone never satisfies a gate.

GateIndependent evidenceRequired result
Docker daemondocker info and hello-worldRootless on validated Ubuntu path
Local modelollama psSelected model loaded with context >= 64000
Hermes connectionExact one-shot markerMPC_HERMES_OLLAMA_OK only
Tool sandboxdocker inspect plus failed network requestNo network, finite PIDs, dropped capabilities, no unexpected mounts
Agentic workflowHost-side hashes, file count, source check, and unit testsOnly intended file changed and all tests pass
CleanupFilesystem checkSmoke mount removed and fixture absent

When Docker is not enough

Use a disposable VM for untrusted install scripts, unknown repositories, security audits that execute target code, browser automation against hostile pages, or tasks involving kernel-facing tools. Give the VM synthetic data, no production credentials, restricted egress, a hard lifetime, and an automatic cleanup audit. GPU passthrough is optional and increases configuration and attack surface; validate CPU mode first.

Privacy and network boundaries

Local Ollama inference keeps model prompts off a hosted model API, but optional features can still transmit data. Web search, remote MCP servers, Telegram or Discord, cloud fallbacks, hosted media generation, and hosted speech all use networks. Keep cloud keys unset for a strict local build, leave the tool container network disabled, bind dashboards to loopback, and inspect every enabled skill and MCP integration before handling sensitive material.

Dashboard and profiles

Start the dashboard explicitly with hermes dashboard; a normal chat does not launch it. Keep the default loopback binding unless you intentionally add authentication and trusted-network controls. Profiles isolate Hermes configuration, secrets, memory, sessions, skills, cron jobs, gateway state, and Docker-container labels. They do not create a kernel or filesystem sandbox by themselves.

bash
hermes dashboard
# Default local URL: http://127.0.0.1:9119

hermes profile create local-lab --description 'Local Ollama test profile'

Troubleshooting checkpoints

Rootless Docker cannot connect to user systemd: do not install it through sudo su. Log in normally so XDG_RUNTIME_DIR and the user bus exist. Confirm /etc/subuid and /etc/subgid contain a range for your user, then follow Docker's rootless troubleshooting guide.

`docker` still targets the wrong daemon: export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock, run docker context use rootless, and confirm docker info lists rootless. Do not continue based only on the context name.

Hermes says the context is too small: run ollama ps; fix Ollama's effective allocation and restart it. Editing only Hermes config is insufficient.

The first response appears stuck: the bounded Qwen cold connectivity prompt took 4 minutes 43 seconds and its full Docker-mounted task took 16 minutes 45 seconds. Check ollama ps and system CPU activity, then wait within the configured timeout. Repeated restarts discard progress. An earlier unbounded run continued after its tests had passed, which is why Steps 5 and 6 disable thinking and cap iterations.

Hermes responds but tools do nothing: verify the model advertises tool support, then run an observable terminal task. Model connectivity and tool competence are separate gates. North passed a smaller coding exercise but stalled in this full mounted workflow; passing a chat or micro-benchmark does not certify a guide model.

The model ignores the exact final marker: run every independent host check in Step 8C. If those checks pass, the tool workflow succeeded but strict output-format adherence did not. If they fail, the build has not passed.

Docker tools cannot download packages: this guide deliberately sets docker_network: false. Temporarily enable it only when needed, then recreate or restart the Hermes-managed container and turn it back off.

Files disappear between sessions: the conservative profile disables persistence. Use an explicit project volume for durable authorized work rather than broad persistence or a home-directory mount.

The installer warns about npm/browser tools: verify hermes --version and hermes doctor. Install and test browser dependencies separately only if the workflow needs them.

A model claims completion but the result is wrong: independently inspect the diff and run tests. Never use the model's own status sentence as proof that a tool or security boundary worked.

Rollback and cleanup

Step 7C created ~/.hermes/config.yaml.before-local-sandbox before the sandbox edit. Restore that file if configuration validation fails. To remove an unwanted model, use ollama rm. To undo the Linux context drop-in, remove only the file created by this guide, reload systemd, and restart Ollama. Hermes-managed containers are labeled hermes-agent=1; inspect them before removal. Switching back to terminal.backend local removes isolation and should be limited to explicitly trusted personal work.

bash
# Restore the pre-sandbox Hermes config if needed
cp -a ~/.hermes/config.yaml.before-local-sandbox ~/.hermes/config.yaml
hermes config check

# Remove a model only when you no longer need it
ollama rm qwen3.5:9b

# Ubuntu context rollback
sudo rm /etc/systemd/system/ollama.service.d/95-hermes-context.conf
sudo systemctl daemon-reload
sudo systemctl restart ollama

# Inspect, then remove only Hermes-managed containers if desired
docker ps -a --filter label=hermes-agent=1

Updating without surprises

For an unmodified upstream installation, check first without changing files. If an update is available, use Hermes' atomic backup option during the update, then check and migrate configuration before repeating the local marker and sandbox smoke tests. hermes config migrate is interactive; run it only when hermes config check reports missing options. The update may restart a running gateway, so schedule a brief interruption.

Customized deployments should not run this sequence directly on production. Update a separate test instance, reapply and test local patches there, then promote the tested build. Do not update a working customized agent blindly.

bash
hermes version
hermes update --check

# Continue only after reviewing the available update.
hermes update --backup
hermes config check
# Run only if config check reports missing options:
hermes config migrate
hermes doctor

# Repeat Checkpoint 2 and Checkpoint 3 before real work.
Read next

RELATED GUIDES