---
name: vps-third-party-cli-installs
description: Install third-party CLI tools on the Hostinger VPS where /root is a READ-ONLY mount (only /root/.hermes is writable). Trigger whenever an installer, binary, or package manager fails with 'Read-only file system' or ENOENT writing to /root/... — e.g. tools that hardcode $HOME/.<tool> config dirs (composio, bun-compiled CLIs), curl|bash installers, or anything that refuses env-var overrides. Covers the three-tier workaround ladder ending in the unshare+bind-mount wrapper pattern.
---

# Installing third-party CLI tools on the read-only-/root VPS

## The constraint

On this VPS, `/root` is a **read-only mount**. Only `/root/.hermes` is writable. Any tool that writes config/state to `$HOME/.<tool>` (or anywhere under `/root` outside `.hermes`) will fail at install time OR at first run — sometimes both, at different stages.

## The workaround ladder — try in order, escalate on failure

1. **Installer env vars.** Many `curl | bash` installers honor an install-dir override (e.g. `COMPOSIO_INSTALL_DIR`). Download the script first and `grep` it for the var name instead of guessing: `curl -fsSL <url> -o /tmp/i.sh && grep -n -iE "install_dir|PREFIX|HOME" /tmp/i.sh`.
2. **HOME redirect.** `HOME=/writable/dir <binary>`. Works for tools that resolve `$HOME` from the environment. **Pitfall:** bun-compiled CLIs (and some others) resolve home from passwd or hardcode the absolute path — this tier silently does nothing for them. Verify by checking whether the tool created its config in the fake HOME.
3. **`unshare -rm` bind-mount wrapper** (the reliable endgame). Run the binary in a private mount namespace where a fake `$HOME` exists and its `.<tool>` dir is bind-mounted to persistent storage under `/root/.hermes/`. Symlinks in `/root` do NOT work (read-only mount blocks creation) — the namespace is the way.

## The wrapper pattern (tier 3)

Generic template in `templates/home-bind-wrapper.sh`. Worked example — composio, `/root/.hermes/bin/composio`:

```bash
#!/bin/bash
PERSIST_DIR=/root/.hermes/composio-home   # persistent state, survives reboots
BIN=/root/.hermes/composio/composio       # the real binary (installed under .hermes)
mkdir -p "$PERSIST_DIR"
exec unshare -rm bash -c "
  mkdir -p /tmp/composio-fakehome/.composio
  mount --bind '$PERSIST_DIR' /tmp/composio-fakehome/.composio
  export HOME=/tmp/composio-fakehome
  export PATH=/root/.hermes/composio:\$PATH
  exec '$BIN' \"\$@\"
" -- "$@"
```

`chmod +x` it, put it in `/root/.hermes/bin/`, and always invoke the wrapper — never the raw binary. State lands in the persist dir, so it survives reboots even though the namespace is ephemeral.

## Verification (do all three)

- `wrapper --version` exits 0 with NO error output (partial failures print errors but exit 0 — check stderr text, not just exit code).
- The persist dir contains the tool's state files after first run (`ls $PERSIST_DIR`).
- A second invocation in a NEW shell still sees the state (proves persistence, not just in-namespace success).

## Pitfalls

- **Env vars in the binary's strings ≠ honored.** `strings <bin> | grep TOOL_DIR` may show promising vars that the tool ignores at runtime (composio shows `COMPOSIO_DIR` but still wrote to `/root/.composio`). Test, don't trust.
- **Installers can half-succeed.** The composio installer placed the binary fine under the custom dir, then its post-install step crashed writing `/root/.composio/config.json`. The install is usable; only the post-install needs the wrapper.
- **Approval-gated pipe-to-shell.** `curl | bash` triggers a security-scan approval prompt on this box. Pre-downloading the script (tier 1 grep step) also makes the approval review meaningful.
- **`unshare -rm` requires root** — fine here (we are root on the VPS), but don't cargo-cult this pattern to the Windows/WSL side without checking privileges.
- When a tool needs system packages (`unzip` was missing for composio), `apt-get install` works normally — only `/root` is read-only, not the whole FS.

## Known wrapped tools on this VPS

- **composio** → `/root/.hermes/bin/composio` (binary `/root/.hermes/composio/composio`, state `/root/.hermes/composio-home`). Usage workflows live in the `composio` skill (hub-installed, read-only for curation); VPS install/auth specifics incl. the browserless login flow are in `references/composio-on-vps.md`.
