---
name: skillclaw-vps-ops
description: Operate the SkillClaw closed loop on the VPS — proxy + evolve server units, local shared storage, config keys, verification, and pitfalls.
---

# SkillClaw VPS Ops

SkillClaw runs on the VPS as a closed loop: client proxy captures sessions → uploads to a local shared root → evolve server digests them into skills → proxy pulls evolved skills back. Use this skill for any SkillClaw install/config/troubleshoot task on this host.

## Layout (all paths stable)

- Repo + venv: `/root/.hermes/SkillClaw/` (`/root` is read-only except `/root/.hermes` — never try to clone/install elsewhere)
- HOME redirect: `HOME=/root/.hermes/skillclaw-home` — **prefix every `skillclaw` CLI command with this** or it reads/writes the wrong config
- Config: `$HOME/.skillclaw/config.yaml` (chmod 600 — contains the resolved Nous API key)
- Shared root: `$HOME/.skillclaw/local-share/<group_id>/` (`sessions/`, `skills/`, `evolve_skill_registry.json`)

## systemd units (both enabled, both Restart=always, logs via journalctl)

- `skillclaw.service` — client proxy, `127.0.0.1:30000` → upstream Nous (`moonshotai/kimi-k3`)
- `skillclaw-evolve.service` — evolve server, port `8787`, workflow engine, 300s periodic cycle:
  `ExecStart=/root/.hermes/SkillClaw/.venv/bin/skillclaw-evolve-server --use-skillclaw-config --interval 300 --port 8787`
  with `Environment=HOME=/root/.hermes/skillclaw-home`

## Closed-loop config keys (client config.yaml)

- `sharing.enabled: true`, `sharing.backend: local`, `sharing.local_root: <shared root>`, `sharing.auto_pull_on_start: true`
- `evolve.server_url: http://127.0.0.1:8787` — lets the proxy POST `/trigger` to the evolve server immediately after a session upload (no waiting for the 300s tick)
- Off by design (single-user, cheapest): PRM, remote sharing (OSS/S3/nacos), validation workers, dashboard. `claw_type: none` — the live `hermes-gateway.service` is never touched.

## Key behavioral facts (learned from live verification)

- **Sessions upload only when the proxy considers them CLOSED.** A one-shot curl test sits open until the idle sweeper closes it (`session_idle_close_seconds`, default 180s). Don't panic when a fresh test turn doesn't appear in `local-share/` — wait ~3 min and check the proxy log for `closed session=... reason=idle_timeout` then `session uploaded: ...`.
- The proxy uploads to `<shared>/<group_id>/sessions/<session_id>.json` and the evolve server **deletes session files after processing** — an empty `sessions/` dir after a cycle is success, not data loss.
- Manual evolve kick: `curl -X POST http://127.0.0.1:8787/trigger` returns a JSON cycle report (sessions, judged scores, uploaded_skills, `had_processing_error`).
- The evolve LLM legitimately skips trivial sessions ("reply with X" ping tests) — `no-skill sessions: LLM decided to skip` in the log is the pipeline working, not failing. Real multi-turn work sessions are what produce skills.
- Evolve cost: ~4 LLM calls per digested session (summarize → judge → aggregate → decide). Recurring spend scales with proxied traffic.

## Verification recipe (end-to-end)

1. `systemctl is-active skillclaw skillclaw-evolve` → both `active`
2. Send a turn: `curl -s http://127.0.0.1:30000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"skillclaw-model","messages":[{"role":"user","content":"..."}]}'`
3. Wait ≥180s (or close explicitly), then `find /root/.hermes/skillclaw-home/.skillclaw/local-share -type f` for the session file
4. `curl -X POST http://127.0.0.1:8787/trigger`; watch `journalctl -u skillclaw-evolve -f` for drain → summarize → judge → cycle-done
5. One-shot Hermes test path: `hermes chat -Q --provider skillclaw -m skillclaw-model -q "..."` (a `skillclaw` provider entry exists in Hermes config)

## Pitfalls

- **Proxy health probe: use `/v1/chat/completions`, NOT `/health`** — `/health` returns 404 (`{"detail":"Not Found"}`) even when the proxy is fully healthy; the README's `/healthz` is likewise unreliable here. A 404 from `/health` does NOT mean the proxy is down. Verify with a minimal chat completion or `systemctl is-active skillclaw`.
- **write_file refuses `/etc/systemd/**`** (sensitive-path guard). Create units via a terminal heredoc (`cat > /etc/systemd/system/x.service <<'EOF' ...`) then `systemctl daemon-reload`. Expect a user approval prompt. Note: file-mutation verifiers flag the refused write_file call as "file NOT modified" even when the heredoc succeeded — confirm with `cat`/`systemctl is-active` before conceding anything is missing.
- **Gateway/Desktop sessions do NOT reach SkillClaw.** The Hermes gateway default model points directly at Nous (`model.base_url: https://inference-api.nousresearch.com/v1` in `/root/.hermes/config.yaml`); the `skillclaw` provider entry exists but nothing uses it by default. So Desktop chats are never recorded/evolved. To check whether that's still true: `grep -n 'base_url' /root/.hermes/config.yaml | head`. Deliberately left this way (2026-07-28 decision: re-evaluate benefits later before adding proxy latency/cost/SPOF to the daily path).
- pip into the venv needs `PIP_CACHE_DIR` under `/root/.hermes` and the venv python: `/root/.hermes/SkillClaw/.venv/bin/python -m pip install -e "/root/.hermes/SkillClaw[evolve]"` (evolve extra = `openai`, required for the server).
- `config.yaml` `llm.api_key` holds the **resolved** Nous key (Hermes's own config uses `env:` refs — resolve from `/root/.hermes/.env` before reusing).
- Routing gateway/Desktop traffic through the proxy (so SkillClaw learns from real sessions) is a deliberate, separate decision — it changes the live inference path. Lay out trade-offs before doing it; don't do it as a side effect.

See `references/evolve-pipeline.md` for the cycle stages, trigger-response fields, and log-line glossary.
