Metadata-Version: 2.4
Name: openguardrails-instrumentation-hermes
Version: 0.1.0
Summary: Guard a Hermes agent and its sandbox through the OpenGuardrails (OGR) protocol — one policy enforced across the LLM gateway, the agent tool-call hook, and the real sandbox exec.
Project-URL: Homepage, https://openguardrails.com
Project-URL: Specification, https://github.com/openguardrails/openguardrails-spec
Project-URL: Source, https://github.com/openguardrails/openguardrails-python
Author: OpenGuardrails
License-Expression: Apache-2.0
Keywords: agent,ai,guardrails,hermes,ogr,sandbox,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.10
Requires-Dist: openguardrails>=0.1.0
Provides-Extra: srt
Description-Content-Type: text/markdown

# openguardrails-instrumentation-hermes

Guard a [Hermes](https://github.com/NousResearch/hermes-agent) agent **and its
sandbox** through the [OpenGuardrails (OGR)](https://pypi.org/project/openguardrails/)
protocol. One `policy.json` enforces across three altitudes — correlated by
`guard_id` and provenance.

```bash
pip install openguardrails-instrumentation-hermes
```

(pulls in `openguardrails`, the zero-dependency reference runtime.)

## Why a plugin, not a proxy

Hermes already exposes the interception points OGR needs, so no proxy and no core
patching is required for 3 of the 4 altitudes:

| OGR altitude | Hermes surface | Enforce? | Sees |
| --- | --- | --- | --- |
| `gateway` (LLM I/O) | `pre/post_api_request` hooks | observe | full prompt + completion |
| `agent_hook` (tool lifecycle) | `pre_tool_call` hook | **block** | tool name + args, pre-dispatch |
| provenance | `post_tool_call` hook | taint | tool results (web/mcp → untrusted) |
| `sandbox` (real exec) | wraps `BaseEnvironment.execute` | **block** | real `argv` + secret env keys + cwd |

Only the sandbox altitude needs a wrapper, because Hermes has **no**
environment-level hook. It is installed from `register()`, is idempotent, and
**fails open** if Hermes' layout differs.

## Install into a real Hermes

```python
# in a Hermes plugin entrypoint:
from openguardrails_instrumentation_hermes import register
register(ctx)   # binds the 4 hooks + installs the sandbox wrapper
```

Or drop the bundled `plugin.yaml` into a Hermes plugin dir. Override the policy
with `OGR_POLICY=/path/to/policy.json`; a Hermes-tuned default ships inside the
package.

## What Hermes calls a "sandbox" (and which to use)

There is **no syscall sandbox** by default. "Sandbox" = a pluggable `Environment`
backend: `local` = `subprocess.Popen` **on the host** (zero isolation, the
default), `docker` = `docker exec` into a container, plus Modal/SSH/Daytona. All
funnel through the one `BaseEnvironment.execute()` chokepoint we wrap.

Pick the OS-level enforcement backend with `OGR_SANDBOX`:

| `OGR_SANDBOX` | Scenario | Enforcement |
| --- | --- | --- |
| `argv` (default) | quick start | OGR decision only — no OS isolation |
| `srt` | **personal** (one laptop, no Docker) | [Anthropic Sandbox Runtime](https://github.com/anthropic-experimental/sandbox-runtime): `sandbox-exec`/`bubblewrap` enforces the real syscall boundary |
| OpenShell (gateway) | **multi-tenant** (shared fleet) | container + OPA/Rego egress proxy + gateway credential injection |

The same OGR `sandbox` policy block compiles to **both** backends — see
`openguardrails_instrumentation_hermes.sandbox.srt` and `.sandbox.openshell`.

### No sandbox? OGR degrades, it doesn't fail.

With `local` there is no isolation boundary, so the only **enforcement** altitude
is `pre_tool_call` (inspect argv *before* exec and block). You keep policy,
provenance, and gateway detection — but lose the adversary-proof view, so a clever
agent can obfuscate argv past the intent check. Run tools under `srt`/`docker` so
the `sandbox` altitude exists and closes that blind spot.

## Run the self-test (no Hermes install needed)

```bash
python -m openguardrails_instrumentation_hermes.selftest
```

Drives four scenarios through the real hook signatures: benign / injection-blocked
/ same-command-trusted / defense-in-depth.

## Status

`v0.1`. Verified against real Hermes (2026-06-28): all four hooks bound, benign
commands executed, credential reads and untrusted-origin `curl | bash` blocked at
the altitude that saw them first.
