feat(nix): add suffix PATHs during nix build for more agent-friendliness (#3274)
* refactor: suffix runtimeDeps PATH so apt-installed tools take priority Changes makeWrapper from --prefix to --suffix. In container mode, tools installed via apt in /usr/bin now win over read-only nix store copies. Nix store versions become dead-letter fallbacks. Native NixOS mode unaffected — tools in /run/current-system/sw/bin already precede the suffix. * feat(container): first-boot apt provisioning for agent tools Installs nodejs, npm, curl via apt and uv via curl on first container boot. Uses sentinel file so subsequent boots skip. Container recreation triggers fresh install. Combined with --suffix PATH change, agents get mutable tools that support npm i -g and uv without hitting read-only nix store paths. * docs: update nixosModules header for tool provisioning * feat(container): consolidate first-boot provisioning + Python 3.11 venv Merge sudo and tool apt installs into a single apt-get update call. Move uv install outside the sentinel so transient failures retry on next boot. Bootstrap a Python 3.11 venv via uv (--seed for pip) and prepend ~/.venv/bin to PATH so agents get writable python/pip/node out of the box. --------- Co-authored-by: Hermes Agent <hermes@nousresearch.com>
This commit is contained in:
@@ -10,6 +10,12 @@
|
||||
# container recreation. Environment variables are written to $HERMES_HOME/.env
|
||||
# and read by hermes at startup — no container recreation needed for env changes.
|
||||
#
|
||||
# Tool resolution: the hermes wrapper uses --suffix PATH for nix store tools,
|
||||
# so apt/uv-installed versions take priority. The container entrypoint provisions
|
||||
# extensible tools on first boot: nodejs/npm via apt, uv via curl, and a Python
|
||||
# 3.11 venv (bootstrapped entirely by uv) at ~/.venv with pip seeded. Agents get
|
||||
# writable tool prefixes for npm i -g, pip install, uv tool install, etc.
|
||||
#
|
||||
# Usage:
|
||||
# services.hermes-agent = {
|
||||
# enable = true;
|
||||
@@ -111,16 +117,45 @@
|
||||
chown -R "$HERMES_UID:$HERMES_GID" "$HERMES_HOME"
|
||||
fi
|
||||
|
||||
# Install sudo on Debian/Ubuntu if missing (first boot only, cached in writable layer)
|
||||
if command -v apt-get >/dev/null 2>&1 && ! command -v sudo >/dev/null 2>&1; then
|
||||
apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq sudo >/dev/null 2>&1 || true
|
||||
# ── Provision apt packages (first boot only, cached in writable layer) ──
|
||||
# sudo: agent self-modification
|
||||
# nodejs/npm: writable node so npm i -g works (nix store copies are read-only)
|
||||
# curl: needed for uv installer
|
||||
if [ ! -f /var/lib/hermes-tools-provisioned ] && command -v apt-get >/dev/null 2>&1; then
|
||||
echo "First boot: provisioning agent tools..."
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq sudo nodejs npm curl
|
||||
touch /var/lib/hermes-tools-provisioned
|
||||
fi
|
||||
|
||||
if command -v sudo >/dev/null 2>&1 && [ ! -f /etc/sudoers.d/hermes ]; then
|
||||
mkdir -p /etc/sudoers.d
|
||||
echo "$TARGET_USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/hermes
|
||||
chmod 0440 /etc/sudoers.d/hermes
|
||||
fi
|
||||
|
||||
# uv (Python manager) — not in Ubuntu repos, retry-safe outside the sentinel
|
||||
if ! command -v uv >/dev/null 2>&1 && [ ! -x "$TARGET_HOME/.local/bin/uv" ] && command -v curl >/dev/null 2>&1; then
|
||||
su -s /bin/sh "$TARGET_USER" -c 'curl -LsSf https://astral.sh/uv/install.sh | sh' || true
|
||||
fi
|
||||
|
||||
# Python 3.11 venv — gives the agent a writable Python with pip.
|
||||
# Uses uv to install Python 3.11 (Ubuntu 24.04 ships 3.12).
|
||||
# --seed includes pip/setuptools so bare `pip install` works.
|
||||
_UV_BIN="$TARGET_HOME/.local/bin/uv"
|
||||
if [ ! -d "$TARGET_HOME/.venv" ] && [ -x "$_UV_BIN" ]; then
|
||||
su -s /bin/sh "$TARGET_USER" -c "
|
||||
export PATH=\"\$HOME/.local/bin:\$PATH\"
|
||||
uv python install 3.11
|
||||
uv venv --python 3.11 --seed \"\$HOME/.venv\"
|
||||
" || true
|
||||
fi
|
||||
|
||||
# Put the agent venv first on PATH so python/pip resolve to writable copies
|
||||
if [ -d "$TARGET_HOME/.venv/bin" ]; then
|
||||
export PATH="$TARGET_HOME/.venv/bin:$PATH"
|
||||
fi
|
||||
|
||||
if command -v setpriv >/dev/null 2>&1; then
|
||||
exec setpriv --reuid="$HERMES_UID" --regid="$HERMES_GID" --init-groups "$@"
|
||||
elif command -v su >/dev/null 2>&1; then
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
${pkgs.lib.concatMapStringsSep "\n" (name: ''
|
||||
makeWrapper ${hermesVenv}/bin/${name} $out/bin/${name} \
|
||||
--prefix PATH : "${runtimePath}" \
|
||||
--suffix PATH : "${runtimePath}" \
|
||||
--set HERMES_BUNDLED_SKILLS $out/share/hermes-agent/skills
|
||||
'') [ "hermes" "hermes-agent" "hermes-acp" ]}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user