# ClawKeeper blocks tool calls, then asks a model to write the rules it enforces

> A Python safety core that sits between an agent and its tools, with a deterministic guard chain, an HTTP bridge for non-Python hosts, and an optional Watcher that judges trajectories with an LLM and persists the patterns it learns into the user's home directory.

**SafeAI-Lab-X/ClawKeeper** — ClawKeeper: Comprehensive Safety Protection for OpenClaw Agents Through Skills, Plugins, and Watchers (aka The Norton for OpenClaw)

- Repository: https://github.com/SafeAI-Lab-X/ClawKeeper
- Stars: 1,023 · Forks: 57
- Language: TypeScript
- License: not declared
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/safeai-lab-x-clawkeeper

## The repository sells OpenClaw protection, the readme sells host agnosticism

The project's one line description frames it as comprehensive safety protection for OpenClaw agents through skills, plugins and watchers, and reaches for an antivirus analogy, calling itself the Norton for OpenClaw. The readme frames something wider: host agnostic safety middleware for tool using agentic systems that can be wired into Hermes Agent, MCP tools, HTTP bridges, OpenClaw style runtimes or a custom host.

The two framings do not line up on the three mechanisms the description names. Skills and plugins have no documented surface in the readme, while the Watcher has a whole section with its own daemon, its own port and its own environment variables. What is actually documented is a core package, a set of adapters and a server.

The placement is the same in both versions: ClawKeeper sits between an agent and its tools, blocks risky tool calls, redacts sensitive tool results, remembers recurring attack patterns, and hands the harder trajectory level decisions to an external Watcher.

## Apache-2.0 is declared in two places and no license file is committed

The license is stated twice in text: the readme ends with a License section reading Apache-2.0, and the packaging metadata carries `license = { text = "Apache-2.0" }` alongside an Apache Software License classifier.

The canonical text is missing. The top level of the repository holds .gitignore, DESIGN.md, QUICKSTART.md, README.md, README_v02.md, pyproject.toml and the source directories, and no LICENSE file among them, while the repository's own license field is empty. For an Apache-2.0 project that is an unusual gap, because the notice file is the part that obliges you to state changes and carry the patent grant.

The version story sits in the same place. The package version is 0.2.0.dev0, the classifier says Development Status 3 Alpha, and the repository has published no releases at all, so there is no stable artifact to pin and the version string itself marks the build as a development one.

## The one documented install pulls the dev extra, and the sanity check is the test suite

The install section offers one path:

```bash
git clone git@github.com:SafeAI-Lab-X/ClawKeeper.git
cd ClawKeeper

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

The extra in that command is the development one, which adds pytest, pytest-asyncio, pytest-cov, ruff and mypy. No plain editable install and no wheel install appear anywhere, so the documented way to use the library is also the documented way to get the test and lint toolchain. The sanity check that follows is `pytest -q`, which means the first thing a new user verifies is the project's own suite rather than a conversion or a block.

Two pointers in the same section do not resolve. Red team fixtures are said to live under tests/redteam/ and benchmark scripts under experiments/, but there is no experiments directory at the top level of the repository.

The wheel target packages `clawkeeper_core` only, so the JavaScript adapters, the examples and the docs travel with a clone and not with an install.

## The Watcher is the layer that sees the most and sends the most away

The Watcher is optional and starts with three environment variables:

```bash
export CK_WATCHER_API_KEY="$OPENAI_API_KEY"
export CK_WATCHER_BASE_URL="$OPENAI_BASE_URL"   # optional, OpenAI-compatible
export CK_WATCHER_MODEL="gpt-5.5"               # or your configured model

python -m clawkeeper_core.watcher.daemon
curl http://127.0.0.1:9099/watcher/health
```

Read those three lines next to what the Watcher is for: it reasons over intent, recent tool history, deterministic findings and proposed tool calls. That means the layer with the most context is the layer that forwards your agent's trajectory to a model endpoint, and because the base URL is marked optional, the default destination is the vendor's own API rather than something on your machine.

That is a deliberate trade for accuracy on multi step drift, which single command rules cannot catch. It is also the decision to document before deployment, not after.

One packaging detail follows from it. The openai client is a mandatory runtime dependency rather than an extra, so it is installed whether or not you ever start the Watcher, while litellm sits in an optional extra, consistent with the OpenAI compatible base URL variable.

## Learned patterns persist under ~/.clawkeeper/ and reload into the live guard

The self improving layer is the part with the longest lasting effect. When the Watcher catches something, it can synthesize a learned pattern, persist it under `~/.clawkeeper/`, and hot reload it into the live guard layer.

Three consequences follow from those words. The policy changes while the agent runs, so a call that was blocked yesterday can pass today without any file in the repository changing. The location is per user rather than per project, so patterns learned while guarding one agent apply to every other agent you run as the same user. And a reload that needs no restart needs no review either, which puts the trust question on whoever configured the model endpoint.

The deterministic layer is described with the opposite emphasis. The guard set is stated to be intentionally small and inspectable, with the policies living under `clawkeeper_core/guards/`, and it covers dangerous shell execution, protected path access, unsafe URL and SSRF patterns, script body and dynamic path inspection, base64 and hex encoded payloads, credential discovery combined with network exfiltration chains, poisoned return content, and credential redaction.

So there are two philosophies in one package: a fixed rule set you can read, and a learned set you cannot.

## Two fixed ports, one console script, and no described authentication

For hosts that cannot import the package, the documented fallback is a server:

```bash
clawkeeper-server
curl http://127.0.0.1:7474/v1/health
```

The endpoint list under it is short and telling: `/v1/judge`, `/v1/event`, `/v1/audit`, `/v1/scan/logs`, `/v1/scan/skill`, plus maintenance harden and rollback routes. `/v1/judge` is the decision path and `/v1/audit` is the record of what happened, so both processes hold the sensitive material a guard is supposed to protect.

Nothing in the file describes how either server authenticates a caller, and the only addresses shown are loopback. A deployment that moves the core or the Watcher off loopback, which is the normal shape for a shared guard service, has no documented token, header or bind configuration to copy.

The packaging reflects the same asymmetry. One console script is declared, `clawkeeper-server`, so the Watcher has to be launched as a module, `python -m clawkeeper_core.watcher.daemon`. The maintenance harden and rollback routes are named but not explained: what gets hardened, and what a rollback restores, is not stated.

## The repository's language is TypeScript while the installable package is Python

The repository records TypeScript as its primary language, and its packaging is a Python project: hatchling as the build backend, `requires-python = ">=3.11"`, classifiers for Python 3.11 through 3.13, and dependencies on pydantic, fastapi, uvicorn, httpx and the openai client.

The TypeScript in the tree is one directory, adapters_js/, and the wheel packages only clawkeeper_core, so that adapter is not distributed as part of the Python artifact.

That mismatch has a practical consequence for hosts. A Python agent imports the Judge directly and installs the guard chain in process, with no Hermes patching required. Anything else, including a JavaScript host, has to go through the HTTP core, which means the guard decision crosses a process boundary and the audit trail lives somewhere other than the agent's own runtime.

The rest of the layout points at an in place rewrite rather than a settled shape: a legacy directory, a second readme named README_v02.md beside README.md, and a version number still ending in a dev suffix.

## Conclusion

ClawKeeper fits a team that wants one guard chain shared across a Python agent, an MCP server and a JavaScript host, and that accepts sending tool history to an LLM endpoint to get trajectory level judgement instead of single command rules. Before adopting it, settle three things: which model endpoint sees your tool history, whether the patterns it writes into ~/.clawkeeper/ are ever reviewed, and what the ~0.2.0.dev0 version with no published release means for your dependency pinning.

## FAQ

### What does ClawKeeper actually block in an agent's tool calls?

The default guard set covers dangerous shell execution, protected path access, unsafe URL and SSRF patterns, script body and dynamic path inspection, base64 and hex encoded payloads, credential discovery combined with network exfiltration chains, and poisoned return content, plus credential redaction of results. The readme also names prompt injection, credential reads and encoded second stage payloads among the failure modes it targets.

### Does ClawKeeper need an OpenAI API key to run?

Not for the deterministic guards or the HTTP core, which run from the local rule set under clawkeeper_core/guards/. The optional Watcher does, through CK_WATCHER_API_KEY, with CK_WATCHER_BASE_URL able to redirect it to any OpenAI compatible endpoint. The openai client is a mandatory runtime dependency, so it is installed either way, and litellm is offered as an extra.

### Where does ClawKeeper store the attack patterns it learns?

Under ~/.clawkeeper/ in the user's home directory, and they are hot reloaded into the live guard layer without a restart. Because the location is per user rather than per project, patterns learned while guarding one agent also apply to other agents run as the same user.

### How do I install ClawKeeper and check that it works?

The documented path is a git clone, a virtual environment and `pip install -e ".[dev]"`, which pulls in pytest, ruff and mypy along with the package. The sanity check given is `pytest -q`. Python 3.11 or newer is required, and the wheel packages only the clawkeeper_core module, so the JavaScript adapters and examples come from a clone.

### Is ClawKeeper only for OpenClaw agents?

The repository description presents it as protection for OpenClaw agents through skills, plugins and watchers. The readme presents it as host agnostic middleware for tool using agentic systems, to be wired into Hermes Agent, MCP tools, HTTP bridges, OpenClaw style runtimes or a custom host, with a documented Python adapter, an HTTP core and an optional Watcher daemon.

## Sources

- [Issues](https://github.com/SafeAI-Lab-X/ClawKeeper/issues)
- [README](https://github.com/SafeAI-Lab-X/ClawKeeper/blob/main/README.md)
- [SafeAI-Lab-X/ClawKeeper on GitHub](https://github.com/SafeAI-Lab-X/ClawKeeper)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/safeai-lab-x-clawkeeper
