Recover
September 5, 2026 ยท View on GitHub
This page covers Doberman's recovery and cleanup commands: clearing sticky taint (a session marked
as having seen something sensitive), re-approving a changed MCP (Model Context Protocol) tool,
resetting or pruning learned memory, and removing Doberman from a project. Every gated command here
uses the same possession-factor rule: TOTP (a one-time code from an authenticator app) if you've
enrolled 2FA (two-factor authentication), otherwise the local Doberman password set with doberman password set. With neither enrolled, the action fails closed (denies by default rather than
guessing) and nothing changes. There is no confirm-only path.
Recovering from sticky taint, doberman taint clear
Reading a secret taints a session for the rest of it, by design. A timed reset would be a bypass an
attacker waits out. In Strict/Paranoid that means a single legitimate secret read can raise every
later egress (data leaving the session) in that repo to AUTH or BLOCK, with no in-band way to reset
it. doberman taint clear is the explicit, human-only escape hatch. It requires an enrolled
possession factor and, once verified, wipes both taint stores for the current repo: the
accumulated-taint ledger and the read-vs-send fingerprint (a hash standing in for the raw content)
match. There is no --scope/--session
narrowing, and a denied or failed gate leaves every row untouched. Because taint is a
control-plane-blocked subcommand, a mediated agent can never shell out to run this itself. It only
runs from your own terminal.
MCP tool-schema rug-pull defense, doberman tools approve
On every proxied tools/list, Doberman pins a keyed-HMAC fingerprint (a hash tied to a secret key,
so only Doberman can produce it) of each tool's name, description, and input schema, then checks
that pin on the live tools/call path. A changed contract raises the call to AUTH in Light/Balanced
or BLOCK in Strict/Paranoid. Raw schemas are never stored or logged. This is honestly trust on first
use: it detects a change after first contact, not a malicious schema presented on that first
contact. After reviewing the server change out-of-band, run doberman tools approve <tool_name>
from your terminal (possession factor required). Mediated agents are blocked from invoking that
weakening themselves. Approving a changed pin also resets the tool's
learned familiarity across every entity in the repo, in the same transaction as the approval: a
changed tool is a new tool, so the behavioral baseline scores it as brand-new instead of inheriting
pre-change trust. Expect a short tail of extra step-up asks while it relearns.
Governing learned memory, doberman memory reset / doberman memory prune
The subjective baseline and revealed-preference tables, what Doberman has learned about this
deployment's normal behavior, are persistent, per-entity memory. Persistent agent memory is itself a
poisoning vector: if it were ever trained on a compromised session, nothing short of deleting it
clears the taint. doberman memory reset is that reliable-deletion escape hatch, gated the same way
as doberman taint clear, and scoped to one entity (--entity <id>) or the whole repo. Deleting
learned memory is raise-safe by construction: a colder baseline scores everything as more novel until
it relearns, never less protected. A successful reset is recorded in the append-only ledger
(doberman policy-history). A denied attempt leaves no ledger trace.
doberman memory prune --older-than-days N is the retention-limit sibling: an ungated maintenance op
(not a security decision) that drops entities whose newest activity is older than N days, never
touches the decision log, and never guesses at an entity's age from missing data. Output is counts
only, entity ids are never printed. Both commands are control-plane-blocked, so a mediated agent can
never shell out to run them itself.
Fully removing a project, doberman uninstall
Note Run
doberman uninstall --globalinstead of uninstallingdoberman-coredirectly. Removing the package first leaves hook entries pointing at a missing binary, and every tool call then fails withdoberman: command not found. If you already hit this, reinstalldoberman-core. The existing entries start working again. Then run the global uninstall below.doberman doctorconfirms the entries resolve (itsHook commandline) and fails, naming the fix, whendobermanis not on PATH for the host.
doberman uninstall-hooks only strips the hook entries. It never touches .doberman/, and it needs
no authentication. That means nothing stops a protected agent that reaches a shell from disabling its
own security layer, if it wanted to. doberman uninstall closes that gap. It removes both the
project- and local-scope hooks and the project's .doberman/ control plane (policy and decision
database) in one step. This is gated behind an enrolled possession factor, with no confirm-only
fallback and a hard fail-closed refusal if neither factor is enrolled. Because it's destructive and
irreversible, it also asks you to type the project directory name back before proceeding (--yes
skips that prompt, but never the factor check). Without --global, the command remains
project-scoped: global hooks and device-wide password, 2FA, fingerprint key, and state survive
unchanged. uninstall is itself control-plane-blocked, so a mediated agent can never shell out to
run it. It has the same protection as uninstall-hooks.
That project-scoping used to leave a gap. A global (--global) Claude Code hook, or a Codex
user-scope hook, keeps firing for every project, and there is no way to make the hook file itself
skip one (its matcher keys off tool name, not path). doberman uninstall now closes this too: when
it detects a still-active global or Codex-user hook it adds the project to a device-wide exclusion
list (~/.doberman/excluded_projects.json) that the global hook checks first on every call. That
way, an excluded project gets a true no-op instead of the hook silently recreating .doberman/. The
list is only ever written by this already-gated uninstall flow (never by a mediated agent, never on
the hot hook path). Reading it is a pure check that fails closed: a missing or corrupt list means
not excluded. To bring protection back, run doberman install-hooks in that project again, any
scope, no possession factor needed, since re-arming protection is a strengthen. doberman status
reports whether the current project is excluded.
Removing Doberman from the whole machine: doberman uninstall --global
Run this command from a regular terminal outside the protected agent session:
doberman uninstall --global --path /path/to/project
The command first prints every target and the package-removal command. --dry-run stops there and
changes nothing. Otherwise, it requires the enrolled possession factor before removing anything,
then asks you to type the literal word DOBERMAN. --yes skips only that typed confirmation. It
never skips the factor check.
After approval, Doberman removes these targets in order:
- Claude Code hooks from the global, project, and local settings for
--path. - Codex hooks from the user and repository settings. Plugin-scope hooks are read-only; run the
printed
codex plugin removecommand separately. - The project's
.doberman/directory. - The TOTP enrollment, password enrollment, fingerprint key, and device-wide
.doberman/state. - The
doberman-corepackage through pipx or the active Python's pip.
On Windows, package removal starts in a detached helper after the command exits. That lets Windows
release the running executable. On POSIX, removal runs before the command returns. Development
checkouts stay installed. Add --keep-package to remove hooks and state but keep the package.
The command continues after an individual removal failure, reports every error, and exits 1 if any
target remains. Removing device state deletes 2FA enrollment, the password, and the fingerprint key.
A fresh doberman setup enrolls new factors.