hermes - ✅(Solved) Fix [Bug]: workingDirectory outside stateDir is read-only in NixOS module sandbox [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#12653Fetched 2026-04-20 12:17:36
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

Error Message

Relevant Logs / Traceback

Root Cause

In nix/nixosModules.nix, the native systemd service's hardening block is:

serviceConfig = {
  # ...
  ProtectSystem = "strict";
  ProtectHome = false;
  ReadWritePaths = [ cfg.stateDir ];
  PrivateTmp = true;
};

ReadWritePaths only includes stateDir. When workingDirectory defaults to ${stateDir}/workspace this works because it's a subpath. When the user sets workingDirectory elsewhere (common when they want the workspace visible to file managers, under /home/*, or synced via Syncthing), the path is outside the sandbox write list and becomes read-only.

Fix Action

Fix / Workaround

Local workaround (for users hitting this on current versions):

PR fix notes

PR #12775: fix(nix): make working directory writable

Description (problem / solution / changelog)

What does this PR do?

<!-- Describe the change clearly. What problem does it solve? Why is this approach the right one? -->

We previously assumed that workingDirectory would always be a subpath of stateDir. However, if the user configures workingDirectory to a different location, it may fall outside the sandbox’s writable paths and therefore be treated as read-only.

Related Issue

<!-- Link the issue this PR addresses. If no issue exists, consider creating one first. -->

Fixes #12653

Type of Change

<!-- Check the one that applies. -->
  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

<!-- List the specific changes. Include file paths for code changes. -->
  • Extend systemd ReadWritePaths to always include workingDirectory

How to Test

<!-- Steps to verify this change works. For bugs: reproduction steps + proof that the fix works. -->

Checklist

<!-- Complete these before requesting review. -->

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: NixOS with latest nixpkgs-unstable <!-- e.g. Ubuntu 24.04, macOS 15.2, Windows 11 -->

Documentation & Housekeeping

<!-- Check all that apply. It's OK to check "N/A" if a category doesn't apply to your change. -->
  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

<!-- Only fill this out if you're adding a skill. Delete this section otherwise. -->
  • This skill is broadly useful to most users (if bundled) — see Contributing Guide
  • SKILL.md follows the standard format (frontmatter, trigger conditions, steps, pitfalls)
  • No external dependencies that aren't already available (prefer stdlib, curl, existing Hermes tools)
  • I've tested the skill end-to-end: hermes --toolsets skills -q "Use the X skill to do Y"

Screenshots / Logs

<!-- If applicable, add screenshots or log output showing the fix/feature in action. -->

Changed files

  • nix/nixosModules.nix (modified, +4/-1)

Code Example

services.hermes-agent = {
     enable = true;
     stateDir = "/var/lib/hermes";            # default
     workingDirectory = "/some/other/path";   # outside stateDir
     # ... other config
   };

---

sudo systemd-run --uid=hermes --gid=hermes \
     -p ProtectSystem=strict -p ProtectHome=no \
     -p ReadWritePaths=/var/lib/hermes \
     --wait --pipe --quiet -E PATH=/run/current-system/sw/bin \
     -- sh -c 'touch /some/other/path/test.txt'

---

touch: cannot touch '/some/other/path/test.txt': Read-only file system

---

ReadWritePaths=/var/lib/hermes
ProtectSystem=strict

---

touch: cannot touch '/path/to/workspace/test.txt': Read-only file system

---

serviceConfig = {
  # ...
  ProtectSystem = "strict";
  ProtectHome = false;
  ReadWritePaths = [ cfg.stateDir ];
  PrivateTmp = true;
};

---

ReadWritePaths = [ cfg.stateDir cfg.workingDirectory ];

---

systemd.services.hermes-agent.serviceConfig.ReadWritePaths = [
  config.services.hermes-agent.workingDirectory
];
RAW_BUFFERClick to expand / collapse

Bug Description

When services.hermes-agent.workingDirectory is set to a path outside services.hermes-agent.stateDir, the hermes-agent systemd service cannot write to the workspace. Any attempt fails with Read-only file system.

Root cause: the service unit sets ProtectSystem=strict with ReadWritePaths = [ cfg.stateDir ]. When workingDirectory is a subpath of stateDir (the default ${stateDir}/workspace), it is implicitly writable. When relocated elsewhere (e.g. to a user-visible location for sync/inspection), the sandbox silently locks it to read-only.

The service itself still starts successfully because it does not write to its CWD on startup — the failure only surfaces later when the agent actually tries to create or modify a file in the workspace (e.g. during a task).

Steps to Reproduce

  1. Configure hermes-agent with a workspace outside the state directory:
    services.hermes-agent = {
      enable = true;
      stateDir = "/var/lib/hermes";            # default
      workingDirectory = "/some/other/path";   # outside stateDir
      # ... other config
    };
  2. nixos-rebuild switch
  3. Observe the service starts cleanly.
  4. Try to write to the workspace under the same sandbox:
    sudo systemd-run --uid=hermes --gid=hermes \
      -p ProtectSystem=strict -p ProtectHome=no \
      -p ReadWritePaths=/var/lib/hermes \
      --wait --pipe --quiet -E PATH=/run/current-system/sw/bin \
      -- sh -c 'touch /some/other/path/test.txt'

Expected Behavior

workingDirectory should be writable by the service regardless of whether it lives inside stateDir. When a user overrides workingDirectory, the module should include it in ReadWritePaths automatically.

Actual Behavior

touch: cannot touch '/some/other/path/test.txt': Read-only file system

Verified against systemctl show hermes-agent.service:

ReadWritePaths=/var/lib/hermes
ProtectSystem=strict

The workspace path is absent from ReadWritePaths.

Affected Component

Configuration (config.yaml, .env, hermes setup)

Operating System

NixOS 25.11 (Xantusia), systemd 257.9

Python Version

3.11.14

Hermes Version

0.7.0 (pinned rev 8d7a98d2; also present on main at 6116574 — see nix/nixosModules.nix:780)

Relevant Logs / Traceback

touch: cannot touch '/path/to/workspace/test.txt': Read-only file system

Root Cause Analysis

In nix/nixosModules.nix, the native systemd service's hardening block is:

serviceConfig = {
  # ...
  ProtectSystem = "strict";
  ProtectHome = false;
  ReadWritePaths = [ cfg.stateDir ];
  PrivateTmp = true;
};

ReadWritePaths only includes stateDir. When workingDirectory defaults to ${stateDir}/workspace this works because it's a subpath. When the user sets workingDirectory elsewhere (common when they want the workspace visible to file managers, under /home/*, or synced via Syncthing), the path is outside the sandbox write list and becomes read-only.

Proposed Fix

Extend ReadWritePaths to always include workingDirectory. systemd deduplicates the list, so when workingDirectory is a subpath of stateDir the effective sandbox is unchanged:

ReadWritePaths = [ cfg.stateDir cfg.workingDirectory ];

Local workaround (for users hitting this on current versions):

systemd.services.hermes-agent.serviceConfig.ReadWritePaths = [
  config.services.hermes-agent.workingDirectory
];

Co-Authored-By: Claude Opus 4.7

extent analysis

TL;DR

To fix the issue, update the ReadWritePaths configuration to include the workingDirectory path.

Guidance

  • The root cause of the issue is that the ProtectSystem=strict setting in the systemd service unit only allows writing to the paths specified in ReadWritePaths, which by default only includes stateDir.
  • To verify the issue, check the ReadWritePaths setting in the hermes-agent.service file and confirm that it does not include the workingDirectory path.
  • To mitigate the issue, update the ReadWritePaths configuration to include the workingDirectory path, as proposed in the fix: ReadWritePaths = [ cfg.stateDir cfg.workingDirectory ];.
  • As a temporary workaround, users can override the ReadWritePaths setting for the hermes-agent service using the following configuration: systemd.services.hermes-agent.serviceConfig.ReadWritePaths = [ config.services.hermes-agent.workingDirectory ];.

Example

The proposed fix can be implemented by updating the nix/nixosModules.nix file to include the workingDirectory path in the ReadWritePaths setting:

serviceConfig = {
  # ...
  ProtectSystem = "strict";
  ProtectHome = false;
  ReadWritePaths = [ cfg.stateDir cfg.workingDirectory ];
  PrivateTmp = true;
};

Notes

This fix assumes that the workingDirectory path is a valid and writable location. If the workingDirectory path is not writable, additional configuration or permissions changes may be required.

Recommendation

Apply the proposed fix by updating the ReadWritePaths configuration to include the workingDirectory path, as this will ensure that the hermes-agent service has the necessary write permissions to function correctly.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: workingDirectory outside stateDir is read-only in NixOS module sandbox [1 pull requests, 1 participants]