# Doberman Core

> Doberman is an AI agent security framework for guardrails, prompt injection defense, runtime policy enforcement, tool-use permissions, agent monitoring, audit logs, LLM safety, autonomous workflow protection and secure AI deployment.

- **Type:** MCP server
- **Install:** `agentstack add mcp-fu351-doberman-core`
- **Verified:** Pending review
- **Seller:** [fu351](https://agentstack.voostack.com/s/fu351)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [fu351](https://github.com/fu351)
- **Source:** https://github.com/fu351/Doberman-Core
- **Website:** https://pypi.org/project/doberman-core/

## Install

```sh
agentstack add mcp-fu351-doberman-core
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Doberman

**Adaptive Authorization & Runtime Guardrails for AI Coding Agents**

[](https://github.com/fu351/Doberman-Core/actions/workflows/ci.yml)
[](./LICENSE)
[](https://www.python.org/downloads/)
[](#roadmap)
[](https://discord.gg/Sfy5XGNqty)

Your AI coding agent can `rm -rf` your repo, leak your API keys, or be prompt-injected into exfiltrating data — **autonomously, with no undo.** Doberman is the guard dog on the execution path that stops the dangerous call **before it runs.**

  
  
  doberman demo against the live dashboard (doberman dash): five attacks blocked as they happen, then a human denies a high-risk approval.

> If it isn't on the execution path, it's advisory, not protective.

Doberman sits *between the agent and its tools* — a transparent **MCP proxy** or **host hook** — and turns every action into an explicit, auditable decision. Every tool call gets exactly one verdict, decided *before* it executes:

| Verdict | What happens |
|---|---|
| **PASS** | Routine work — straight through, zero friction. |
| **AUTH** | Sensitive — paused for your one-tap approval. |
| **BLOCK** | Dangerous — stopped cold. It never runs. |

```
AI agent ──▶ Doberman ──▶ real tools (files, shell, MCP servers, APIs)
                 └─ normalize → risk engine → PASS / AUTH / BLOCK
```

Works with **Claude Code, Cursor, Codex, Copilot, and any MCP-compatible agent.** Open-source, local-first, and bound by two rules it will never break: it **fails closed** (uncertainty denies) and is **raise-only** (it can tighten automatically, but never silently loosens).

### [Get protected in two commands](#quick-start)  ·  [Join the pack on Discord](https://discord.gg/Sfy5XGNqty)

---

## Contents

- [Why Doberman?](#why-doberman) — what it does, and the two guarantees
- [Quick Start](#quick-start) — install and protect an agent in two commands
- [Verify it end-to-end](#verify-it-end-to-end) — watch it front a real MCP server
- [Turn gate](#turn-gate) — the optional pre-inference chokepoint
- [Benchmark](#benchmark) — attack-block rate (ASR) vs. false-positive friction (FPR)
- [Write a custom Guardrail](#write-a-custom-guardrail-plugin) — register your own rule as a plugin
- [Tune to your risk tolerance](#tune-to-your-risk-tolerance) — strictness modes + the enforcement dial
- [Who is this for?](#who-is-this-for)
- [Roadmap](#roadmap)
- [Contributing](#contributing) · [License](#license)

---

## Why Doberman?

Prompt injection, tool poisoning, data exfiltration, and runaway agents are the defining security problems of agentic AI. Most "AI guardrails" inspect prompts and offer advice. Doberman is different: it is **on the tool-execution path**, so a blocked action *never runs*.

Those three verdicts aren't advice a model can talk its way past — each is enforced at the one place that counts: the instant *before* the call runs. Evade the model's own guardrails all you want; the action still has to clear Doberman.

**Two non-negotiable properties:**

- **Fail closed** — any error, uncertainty, or unhandled case denies the action. There is no path to a tool around the decision engine.
- **Raise-only learning** — guardrails and adaptive learning can auto-*tighten*, never silently loosen. Every permanent policy weakening requires explicit, possession-factor-gated, audited human approval (TOTP if enrolled, otherwise the local Doberman password).

---

## Quick Start

Doberman guards any **MCP-compatible** coding agent: pick your agent, run one command, and every
tool call is reviewed *before* it executes. The full walkthrough - every option, flag, the
dashboard, and health checks - lives in the **[Setup Guide](docs/SETUP.md)**.

```bash
pip install doberman-core
```

| Your agent | How Doberman plugs in | Get started |
|---|---|---|
| **Claude Code** | Hooks - gate every built-in *and* MCP tool call *(recommended)* | `doberman setup` -> [guide](docs/SETUP.md#claude-code-hooks) |
| **Claude Desktop / Cursor / Codex** | MCP proxy - wrap your tool server | `doberman serve -- ` -> [guide](docs/SETUP.md#mcp-proxy) |
| **OpenClaw** | Native plugin adapter | [guide](docs/SETUP.md#openclaw) - [adapter](adapters/openclaw/README.md) |
| **Any MCP-compatible agent** | MCP proxy | [guide](docs/SETUP.md#mcp-proxy) |

**Fastest path - Claude Code:**

```bash
doberman setup      # pick a strictness mode, tune guardrails, wire the hooks
```

Doberman now reviews every tool call your agent makes. Confirm it with `doberman doctor`, or watch
real verdicts with `doberman demo`. Everything else - MCP-proxy wiring, the dashboard, TUI, scan,
and 2FA - is in the **[Setup Guide](docs/SETUP.md)**.

---

## Verify it end-to-end

Two ways to watch Doberman front a **real** MCP server — no in-process test doubles anywhere in the chain.

**Interactive demo — MCP Inspector + a real filesystem server:**

```bash
npx -y @modelcontextprotocol/inspector doberman serve -- npx -y @modelcontextprotocol/server-filesystem ~/my-project
```

Open the Inspector UI and call tools through Doberman: routine reads and writes PASS straight through to the real filesystem server; a destructive call comes back as a policy error and never executes.

**End-to-end test — in a dev checkout:**

```bash
pytest tests/integration/test_serve_end_to_end.py -q
```

This spawns `doberman serve` as a real subprocess fronting a real stdio tool server ([`tests/fixtures/stdio_tool_server.py`](tests/fixtures/stdio_tool_server.py)), connects to it with a real MCP client playing the agent, and asserts the deployable chain over actual stdio:

1. the downstream's tools are re-exposed through the proxy,
2. a PASS verdict reaches the tool (the downstream's call log records it), and
3. a BLOCK verdict (`rm -rf /`) never reaches it — the call log stays empty.

That last assertion is the **chokepoint property** the whole project hangs on.

> **Note on the test fixtures:** the rest of the integration suite deliberately uses an *in-process* fake downstream ([`tests/fixtures/fake_tool_server.py`](tests/fixtures/fake_tool_server.py)) that records every call it executes — recording is how the tests prove a blocked action reached *nothing*. It is a test fixture, not the runtime. `doberman serve` always spawns and talks to the real server you give it after `--`.

---

## Turn gate

A **second invocation point** for the same decision engine — consulted at a host **pre-inference hook** on the user's *turn* (prompt + attached/pasted/tool-fetched content), so a flagrant turn is judged **before a single inference token is spent**. The turn gate is an **efficiency / early-warning** layer with a deliberately narrow guarantee — *no Tier-0-signature turn reaches the model*. The **action gate above remains the safety guarantee**: an attacker who evades the turn gate still meets it.

- **One engine, two invocation points.** `decide_turn` reuses the raise-only `combine`, the `Decision` audit model, and the tiered-auth challenge — **zero new verdict authority**. It needs no change to the action path; `turngate/` is a new adapter (sibling to the proxy), and the engine stays pure (the tier guardrails are injected). Turn verdicts append to the same redacted `decisions` log, marked `action_type='turn'`.
- **Tier 0 — deterministic signatures (the only hard-stop, small by design).** `instruction_nullification`, `authority_override` (impersonation / mode-switch / "print your system prompt"), `secret_export`, and `encoded_payload`. The precision core is the **issue-vs-mention discriminator** + **origin rule**: a match in *untrusted* (pasted / tool-fetched) content blocks unconditionally (indirect injection); a *typed + issued* match blocks; a *typed + mentioned* (quoted / meta-discussion) match steps up to AUTH so a researcher discussing an attack is never hard-blocked; ambiguous → issued; code fences never exempt.
- **Tier 1 — heuristic recall (AUTH-only, structurally BLOCK-incapable).** Embedded agent-directed instructions inside *pasted* text (not mere imperative mood, so tutorials don't trip it), persona override, sub-threshold obfuscation, and urgency+secrecy framing — a false positive costs one tap, not a denied prompt.
- **Stylometric co-occurrence gate.** A per-entity **prompt-style baseline** (coarse scalar buckets only — length, word shape, punctuation/case/digit density; never any text) scores each turn's style as an empirical-CDF p-value, the same calibration idea the subjective baseline uses for actions. The gate steps up **only** when an *extreme* style outlier co-occurs with a *sensitive* apparent intent (credential / destructive / external-send) — **never on style alone** (people type differently tired/mobile/pasting; a device or language switch is drift, not an attack). Style-weird alone is **tagged, not gated**, and stays inert until the prompt baseline matures (the same maturity rule as the other baselines); Tier 0 is active from turn one. Known limitation: shared accounts blend typists, degrading the style signal toward noise — co-occurrence bounds the cost at one extra tap.
- **Tag-and-pass: turn signals feed the action stage (raise-only).** Every *released* turn publishes its stylometric p-value and heuristic flags as a per-entity `TurnContext`. The action stage consumes it two ways — the subjective surprise term accepts a **bounded, non-negative** contribution (a flagged turn makes its follow-on actions score harsher; a clean turn contributes exactly nothing), and actions tracing to **flagged pasted segments** inherit `provenance: untrusted_data`, which makes the lethal-trifecta floor reachable for them. Raise-only by construction; a blocked turn publishes nothing.
- **Repeat-after-block escape hatch.** A near-match resubmission of a just-blocked turn is treated as deliberate human intent and routed to a challenge with proof **scaled to the block** (a Tier 0 signature → `two_factor`; a replay loop cannot produce a TOTP), the **original reason restated**. Approval is single-use; the third attempt within the TTL locks out. The cache stores only a per-entity HMAC fingerprint, a reason, a count, and an expiry — **never the prompt**.
- **AUTH-first & graceful absence.** `BLOCK` is reserved for the obvious; everything merely suspicious asks the human. Any internal error **fails toward the human** (AUTH), never a silent pass. With no host pre-inference hook (pure MCP-proxy deployments) or `DOBERMAN_TURN_GATE=off`, the gate is simply absent and the action gate carries everything.

---

## Benchmark

A suite-agnostic harness scores Doberman as a **filter over labeled actions** and reports **ASR** (attack bypass rate) and **FPR** (benign over-block / friction). It runs the real decision engine over each labeled tool-call — Doberman is the filter, not the agent — so the gated path is deterministic and offline.

```bash
python -m tests.benchmarks.run --suite synthetic --profile both          # builtins vs plugins
python -m tests.benchmarks.run --suite synthetic --profile before_after  # without vs with Doberman
```

It reports two plugin profiles — `builtins_only` and `with_plugins` (built-ins plus any installed entry-point plugins) — and their uplift. The `before_after` profile adds a **no-guardrail baseline** (the unmediated tool path, where every attack executes) so you can read the engine's effect directly as `{before, after, delta}` — how many otherwise-executing attacks it stops vs. how much benign friction it adds. A deterministic synthetic suite gates in CI; map external task suites (**AgentDojo**, AgentDyn, AgentSentry, …) onto core's types with a small adapter — see [`tests/benchmarks/README.md`](tests/benchmarks/README.md).

> Reports hold counts, verdicts, and reason codes only — never payload text. ASR is reported alongside a stricter `asr_strict` (where only a hard `BLOCK` counts as mitigation): honest measurement, not a single headline number.

---

## Write a custom Guardrail (plugin)

Third-party rules register through the **`doberman.rules`** entry-point group. Core never imports your package by name — install it, and `discover_rules()` / the objective guardrail pick it up automatically.

A five-minute worked example lives at [`examples/plugin-guardrail/`](examples/plugin-guardrail/) (from a git checkout):

```bash
pip install -e ".[dev]"
pip install -e examples/plugin-guardrail
pytest examples/plugin-guardrail/tests -q
pip uninstall -y doberman-example-plugin-guardrail   # optional: restore core-only discovery
```

The tutorial rule steps up a write to `SECRETS_TODO.md` to AUTH, stays raise-only, and never puts the path or payload into its explanation. Copy the package when you need a real custom rule of your own.

> While the example is installed, core's "no plugins registered" checks will see it — that is expected. Uninstall before re-running the full core suite if you want a clean standalone environment.

---

## Tune to your risk tolerance

Set a mode in `.doberman/policies.yaml` or via `doberman mode `. Every mode change made this way — the CLI dial or the setup wizard — is recorded in the append-only policy-change ledger (view it with `doberman policy-history`). Lowering strictness (paranoid → strict → balanced → light) is a **weaken** and requires confirmation plus a possession factor: **TOTP if enrolled, otherwise the local Doberman password**. If neither exists, the lowering fails closed; confirmation alone never suffices. Raising stays frictionless and auto-applies:

| Mode | Best for | Bulk-delete threshold | Step-up for unknown destinations | Step-up for behavioral anomalies | Lethal-trifecta exfil |
|---|---|---|---|---|---|
| **Light** | Exploratory / trusted environments | 100 files | No | No | AUTH |
| **Balanced** *(default)* | Everyday coding agents | 25 files | No | Yes | AUTH |
| **Strict** | Production repos, shared codebases | 10 files | Yes | Yes | **BLOCK** |
| **Paranoid** | Highly autonomous or security-critical agents | 3 files | Yes | Yes | **BLOCK** |

> Hard blocks (secret exfiltration, destructive commands, role-boundary violations, smuggled-token-channel exfiltration) are **identical in every mode**. The mode dial only affects where step-up authentication is required for ambiguous or high-risk actions.
>
> **Unknown network destinations** step up to authentication only in Strict/Paranoid. Light and Balanced treat a plain unknown host (e.g. fetching a docs site or an API) as allowed — that AUTH fired on almost every web fetch and was the top source of benign prompts. This relaxes the *destination-alone* signal only: a secret leaving to **any** host is still a hard block (secrets rule + raise-only combine, every mode), and the sharper destination smells (credentials embedded in the URL, raw IP addresses, unresolvable hosts) still step up in every mode. An **out-of-scope role target** likewise steps up in Balanced/Strict/Paranoid but is relaxed in Light; a role-**blocked** target is a hard block in every mode.
>
> One escalation is mode-gated: the **lethal trifecta** — sensitive data **and** untrusted-content provenance **and** an external destination — steps up to authentication in Light/Balanced, and is a hard **BLOCK** in Strict/Paranoid. Those high-security modes refuse this serious-exfil pattern outright rather than leaving it to a confirmation prompt that alert fatigue could rubber-stamp.
>
> Strict/Paranoid now hard-**BLOCK** a **LOCAL hard smuggled-token channel** (previously AUTH); this is raise-only, and Light/Balanced remain unchanged at AUTH.

### Enforce / monitor / off — the enforcement dial

Orthogonal to the strictness *mode* is an **enforcement dial** (`enforce` *(default)* / `monitor` / `off`) that decides whether Doberman **acts** on a verdict or just observes:

- **`enforce`** — the normal behavior: AUTH prompts, BLOCK denies.
- **`monitor`** — a deliberate **observe mode**. The *discretionary* layer (behavioral anomalies, soft step-ups) is evaluated and **recorded** — `doberman log` / `doberman tui` show what *would* have happened — but it

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [fu351](https://github.com/fu351)
- **Source:** [fu351/Doberman-Core](https://github.com/fu351/Doberman-Core)
- **License:** Apache-2.0
- **Homepage:** https://pypi.org/project/doberman-core/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-fu351-doberman-core
- Seller: https://agentstack.voostack.com/s/fu351
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
