Skip to content

Releases: gl0bal01/pai-hermes

v0.1.3 — multi-model review hardening

19 Jun 10:16

Choose a tag to compare

Addresses a 4-reviewer (codex / deepseek / glm / kimi) audit of 0.1.2.
Headline: the SSH-only gate is now actually forge-resistant. No CRITICAL.

Fixed (HIGH)

  • bin/pai-accept-guard SSH gate was forgeable (G1): the gate trusted SSH_* env vars (which an LLM controls in its own child env) plus a plain PAI_LOCAL_OVERRIDE=1 bypass, so a prompt-injected Hermes could defeat the documented "never callable from a remote platform" guarantee. Replaced with a process-ancestry check (an sshd/sshd-session parent, walked via /proc) that the agent's process tree never has. Remote use is unchanged — a Tailscale SSH session satisfies it. The env bypass is gone; the only non-SSH escape hatch is a root-owned /etc/pai/local-accept.allow (mode 0600) a non-root process can't forge. New bats regressions for env-spoof refusal; CLAUDE.md/SKILL.md realigned to the enforced model.
  • bin/pai-accept-guard could wipe all SHA pins (G2/G3): grep -v … || true conflated grep's no-match (rc 1) with a read error (rc ≥ 2), so an unreadable paths.env mid-run replaced the file with a single line, dropping every other PAI_*_SHA pin. Rewritten with awk (rc 0 on no-match); a real error now aborts. The key filter is now a fixed-string prefix (was a grep regex, so a repo name containing . could strip unrelated keys). New pin-preservation regression.

Fixed (MEDIUM)

  • Config patching extracted + made safe (H9/H7/H2/H5): the duplicated inline python3 -c heredoc is now tools/patch_hermes_config.py. ruamel round-trip preserves user comments/anchors (PyYAML safe_dump destroyed them — H7); writes are atomic (mkstemp+fsync+os.replace, re-parsed before swap — never truncate-in-place, H2); the config path comes from argv/env as a Path, never interpolated into Python source (H5).
  • bin/pai-pulse-send wrapper (S7): pai-pulse's safe JSON pattern was prose only. Added an enforcing wrapper — JSON built solely via jq --arg, Pulse URL restricted to loopback http (also closes the pai-doctor SSRF), length/NUL guards. SKILL.md now mandates it.
  • pai-watch repo-name validation (S6): git -C <name> ran on unvalidated $PAI_WATCH_SOURCES entries. The skill now enforces ^[A-Za-z0-9._-]+$, confines the resolved path under $PAI_PROJET_ROOT, and sets GIT_CONFIG_GLOBAL=/dev/null.
  • pai-accept-guard proposals-dir symlink escape (G7): the root-only readlink -f escape check now also covers PROPOSALS_DIR, not just paths.env.
  • install.sh safety (H3/H1): single-flight flock + ownership guard; refuse a symlink backup path. Arc-review fence escape (G5): untrusted commit subjects are rendered as an indented code block (a ~~~ in a subject can no longer break out). template_vars injection removed (H4).

Fixed (LOW)

  • tools/cost_check.py string-credit crash (P1): extract_metrics passed string used_credits/monthly_limit straight into arithmetic → TypeError, crashing the silent cron. Now coerced with float() + try/except like pct().
  • Stale docs (S1–S4, S8–S12): dead cron/*.yaml references replaced with the jobs.json flow; cost thresholds single-sourced on cost_check.py (5h alert 80 / block 95, 7d alert 85); removed api_spend_month_usd / ANTHROPIC_ADMIN_API_KEY; pai-doctor probes target jobs.json and dropped the retired bin/pai doctor delegation; HOME=$HOME (was /home/pai); README status → 0.1.3.
  • Installer polish (H6/H8/G6): true-atomic skill symlink (ln -s … && mv -T); mktemp backup instead of a fixed .bak clobber; install -d -m 700 for the lock dir (no mkdir+chmod TOCTOU).

Tooling

  • New dependency: ruamel.yaml (round-trip YAML) — install.sh auto-installs it (pip --user, PEP-668 fallback) and fails loudly if unavailable.
  • Tests: +28 (guard env-spoof / pin-preservation / fence; cost string inputs; pulse wrapper injection / SSRF; install append-not-replace / comment-survival / H5). bats 40, pytest 32, shellcheck clean.

Install

# review first, then run
curl -fsSLO https://raw.githubusercontent.com/gl0bal01/pai-hermes/v0.1.3/install.sh && less install.sh && bash install.sh

v0.1.2 — Security review hardening

31 May 05:55

Choose a tag to compare

Summary

Addresses full-tree security review of 0.1.1: 2 HIGH + 5 MEDIUM + 5 LOW + 1 INFO. No CRITICAL.

All tests pass:

  • bats: 18/18 (was 15, +3 regressions for M4 / M2 / M5)
  • pytest: 27/27
  • shellcheck: clean on install.sh, uninstall.sh, bin/pai-accept-guard

HIGH

  • M4bin/pai-accept-guard heredoc command injection in arc markdown writer. Unquoted <<EOF shell-expanded ${LOG} (untrusted upstream commit subjects) at write time; a malicious $(cmd) would execute. Replaced with quoted printf per line; fence changed from triple-backtick to ~~~ to reduce markdown-break risk.
  • H1install.sh rollback gap. ALREADY_PRESENT branch deleted backup before YAML validate; unexpected patcher output was non-fatal. Now: validate-then-delete in every branch; any unexpected output is a fatal rollback.
  • H2pai-accept-guard env-var path trust under sudo. With EUID=0, PAI_PATHS_ENV=/etc/shadow would overwrite. Refuses non-canonical paths when root; readlink -f symlink-escape check.

MEDIUM

  • M1docs/INSTALL.md curl | bash replaced with download → sha256sum -cless review → bash pattern.
  • M2 — Lock file moved from /tmp to $XDG_RUNTIME_DIR/pai-accept/lock (mode 700); refuses pre-existing symlink at lock path.
  • M3 — Trap chain replaced with CLEANUP=() accumulator; exit code preserved.
  • M5tools/cost_check.py snapshot path: resolve() + ~/.hermes/ allowlist + O_NOFOLLOW open.

LOW

  • L1install.sh ln -snf (atomic) replaces -L/-e race.
  • L2uninstall.sh cp --no-dereference; refuses symlink backup target.
  • L3skills/pai-pulse/SKILL.md adds Safety section: jq -n --arg mandatory.
  • L4docs/INSTALL.md regex-on-YAML antipattern replaced with PyYAML.
  • L5docs/INSTALL.md stale cron yaml refs removed; bats count 13→15.

INFO

  • I1set -uo pipefailset -euo pipefail in pai-accept-guard.

Also in this release

  • docs/HERMES_CONTRACT.md — operating contract for pai-hermes skills + cron, distilled from gl0bal01/contract-agents AGENTS_CONTRACT.md v2.0 (MIT) §1/§4/§5/§6/§7 (Scope, Evidence, Approval, Security, Verification). Adapted for the Hermes single-agent + skills + cron runtime.

Known limitations

  • I3 (SSH_CONNECTION env spoofable by local unprivileged user) is a design choice per CLAUDE.md — the SSH gate prevents Hermes-via-prose bypass, not local-shell attacks.
  • Anthropic admin-API spend fetch still deferred (carried from 0.1.1).
  • Live Hermes integration runtime still unverified.

Full diff: v0.1.1...v0.1.2

v0.1.1 — review-driven fixes

16 May 12:04

Choose a tag to compare

Addresses external code review of 0.1.0. All 5 must-fix + 6 missing items resolved.

Fixed

  • cost_check.py pct() zero-falsy bug0% genuine no longer falls through to utilization fallback.
  • install.sh / uninstall.sh — regex-on-YAML replaced with PyYAML (safe_load/safe_dump). Pre-edit .bak backup + post-edit parse validation + automatic rollback on failure.
  • Cron pivot — 3 yaml files deleted. Real Hermes cron is JSON in ~/.hermes/cron/jobs.json managed by Hermes's cronjob tool. Replaced with cron/README.md documenting manual prompt-based registration via Hermes.
  • bin/pai-accept-guard (NEW) — shell-level enforcer of SSH-only constraint that was previously markdown-only. Refuses non-SSH (exit 77), validates inputs (exit 65), flock + timeout (exit 75), atomic paths.env + proposal mutation.
  • CLAUDE.md skill-chaining rule — clarified to permit DAG composition via prose hints. Hermes is orchestrator, skills are leaves, no cycles.
  • README + docs/INSTALL.md — placeholder <you> URLs replaced with gl0bal01.

Added

  • tests/test_cost_check.py (27 pytest tests) — pct edge cases, classify alert/block precedence, compose_voice silence + staleness, cache parse failures, end-to-end smoke.
  • tools/cost_check.py staleness check — cache mtime read; output gains cache_age_seconds + cache_stale; voice alert prepends "stale" warning when >15min old.
  • .github/workflows/test.yml CI — shellcheck + bats + pytest + guard SSH-refusal smoke on push/PR.

Removed

  • api_spend_month_usd from output schema (was declared, never computed — honest removal until admin-key fetch lands).
  • 3 obsolete cron yaml files.

Test status

  • 27/27 pytest ✓
  • 15/15 bats ✓
  • shellcheck clean ✓
  • pai-accept-guard fake-id (no SSH env) → exit 77 ✓

Known limitations (still in 0.1.1)

  • Hermes cron job registration is manual prompt-based (see cron/README.md).
  • Anthropic admin-API spend fetch deferred — removed rather than stubbed.
  • Live Hermes integration runtime still unverified.

Full diff: v0.1.0...v0.1.1

v0.1.0 — Hermes Agent bridge for PAI ecosystem

16 May 11:55

Choose a tag to compare

First public release of pai-hermes — a bridge that makes Hermes Agent PAI-ecosystem-aware via 7 skills + 3 cron jobs.

What's in this release

7 SKILL.md routes (drop into Hermes `external_dirs`):

  • `omc` — Claude Code harness routing (ralph/team/autopilot/ultrawork/ask)
  • `pai-pulse` — Pulse `/notify` TTS POST wrapper (ElevenLabs server-side)
  • `pai-watch` — `git fetch` × 4 sources + impact-score + JSON proposal writer
  • `pai-doctor` — PAI ecosystem health probes (Pulse, Tailscale, paths, OMC CLI)
  • `pai-accept` — SHA pin in paths.env + arc review markdown. SSH-only
  • `pai-cost-tracker` — Claude 5h/7d usage % + voice alert at threshold (reads PAI canonical usage cache)
  • `pai-statusline-banner` — daily 18:00 mobile digest

3 Hermes cron yaml (zero-AI-cost jobs):

  • `pai-watch` hourly
  • `pai-cost-tracker` hourly
  • `pai-statusline-banner` daily 18:00

Tooling:

  • Idempotent `install.sh` / `uninstall.sh` (Python-driven config patcher)
  • `tools/cost_check.py` (PAI usage cache parser → voice alert text)
  • `tests/skill-format.bats` (13 tests, all green)

Docs:

  • `README.md`, `CLAUDE.md` (agent briefing), `docs/INSTALL.md`, `docs/ARCHITECTURE.md`

Built atop

Install

```bash
git clone https://github.com/gl0bal01/pai-hermes ~/.hermes/pai-hermes
cd ~/.hermes/pai-hermes
./install.sh
```

See docs/INSTALL.md for full VPS deploy walkthrough.

License

MIT. AGPL boundary documented in `CLAUDE.md` for safe interaction with `pai-collab` (AGPL-3.0).

Known limitations (v0.1.0)

  • Skills written, integration runtime untested on Hermes (PRs welcome to validate)
  • Hermes cron yaml format guessed from `~/.hermes/cron/` examples — needs schema verification
  • `tools/cost_check.py` reads PAI usage cache format — verify against your `~/.claude/PAI/MEMORY/STATE/usage-cache.json`
  • No CI workflow yet