Skip to main content

oathline-guard

An AI agent's yes means exactly what the person saw.

oathline-guard sits between your MCP client (Claude Desktop, Claude Code, Cursor) and a real stdio MCP server. Reads you list pass straight through. Every other tool call waits: a person, in a second terminal, sees the exact call in the guard's own words and types its four-character code. Then it runs once, with exactly those arguments, and Oathline's hash-chained log records what was shown, heard, confirmed and run.

In April 2026 a coding agent deleted a production database and its backups in nine seconds, with no approval step. This is the same request, through the guard:

db / drop_database
name: prod
code: 44NF
Type the code to run it, or n to refuse: n
Refused and recorded (c-508e50ec). Nothing will run.

The agent only ever gets "Not run ... waiting for a person's yes"; the code is never sent to it, so it cannot approve itself.

Quickstart (about 5 minutes, with the demo database)

1. Install (Python 3.10 or later):

pip install oathline-guard

2. Prepare the demo:

oathline-guard demo

It writes the read list (the tools that pass without a yes) to ~/oathline-guard-demo/reads.json:

{"server": "db", "reads": ["list_databases", "list_tables"]}

and prints the block for Claude Desktop with your machine's real paths (it runs everything through the Python you installed with, so PATH and python vs python3 do not matter). It approves nothing and runs nothing.

3. Add the block to Claude Desktop. Open claude_desktop_config.json (Settings > Developer > Edit Config; on macOS it is in ~/Library/Application Support/Claude/, on Windows in %APPDATA%\Claude\), paste the printed block, then restart Claude Desktop. By hand, the block has this shape:

{
  "mcpServers": {
    "db": {
      "command": "oathline-guard",
      "args": ["run", "--server", "db", "--reads", "/path/to/reads.json", "--human", "you",
               "--", "python", "-m", "oathline_guard.demo.fake_db", "--state", "/path/to/db.json"]
    }
  }
}

oathline_guard.demo.fake_db is a tiny database server with two reads and two writes (drop_database, delete_backups) and no protection of its own. Claude Desktop starts it with a short PATH: written by hand, if oathline-guard is not found, use the full path that pip printed, and if python is not found (on macOS often only python3 exists), write python3 or the interpreter's full path. The block oathline-guard demo prints avoids both.

4. Open the approve window in a second terminal and leave it open:

oathline-guard approve --server db

5. Ask Claude: "clean up the old database". The reads run. The drop waits, and the approve window shows it as above: type n to refuse, or the code to let it run once. After a yes, the agent's next identical call runs it; a call with different arguments is a new request that waits again.

To guard a real server, put its own command after -- and list its read-only tools in reads.json. Tools not on the list always wait, whatever the server's own annotations (readOnlyHint) say.

What it guarantees, and what it does not

  • Reads on your list pass untouched; everything else is held, and the real server is not called until the yes.
  • The words in the window are the guard's: the tool and every argument, never the server's description. A value cannot add a line of its own; long values are shown whole and bound by hash, up to 16,000 characters of window text and Oathline Core's 8 KB cap on a call's items. A call beyond either is refused before anything is shown (text_too_large, items_too_large): split it.
  • The yes runs the stored arguments exactly once. A wrong code decides nothing; a no is recorded, and a later yes is too late.
  • The approve window reads only from a terminal: an agent's shell tool cannot pipe the code in.

Limits, said plainly:

  • A pseudo-terminal passes the terminal check. It stops a pipe, not a determined local process with a pty.
  • An agent with a raw shell or a raw token goes around any MCP guard. The guard governs the calls that pass through it; switch off the client's own write tools for the session if the guard must be the only way to act.
  • No timeout on an upstream call yet, and the agent retries after the yes (no waiting notification yet). On Windows, when the upstream is started through a virtual environment's python.exe (a launcher that holds the pipes), an upstream that closes its output but keeps running is noticed only when it exits.
  • stdio servers only; one person per guarded server; the terminal is the only approval channel.
  • Secret arguments are not masked yet: a secret in an argument is shown in the window.
  • Heard is not understood: the record proves the words were shown and answered, not that they were read.

The record

Each guarded server keeps its own folder (default ~/.oathline-guard/<server>/) with Oathline Core's audit chain and token store. The chain for one call reads REQUEST AUTHORIZED PROPOSED_BY_AGENT SHOWN HEARD CONFIRMED_BY_HUMAN EXECUTING EXECUTED, or ends at REFUSED_BY_HUMAN; verify() on the audit log checks every link.

Licence

MIT. Copyright (c) 2026 Nexxt Nest Group Pty Ltd. Built on Oathline Core.

Metadata

Release files for oathline-guard 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for oathline-guard 0.1.0
File Size Uploaded Provenance Actions
oathline_guard-0.1.0.tar.gz 26.6 kB Without provenance Details for oathline_guard-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for oathline-guard 0.1.0
File Interpreter ABI Platform Actions
oathline_guard-0.1.0-py3-none-any.whl Python 3 none any Details for oathline_guard-0.1.0-py3-none-any.whl

Total release size: 55.0 kB

Release files / oathline_guard-0.1.0.tar.gz

Download URL oathline_guard-0.1.0.tar.gz
Size 26.6 kB
Tags Source
SHA-256 checksum
How to use checksums
916d7f04a1dbf0bf4a17bf54c998affc1944180ecc75949d385d44fb22491611
BLAKE2b-256 checksum
How to use checksums
1f1fd969a062e320decc13440da2178f17290a85f76bdbefbdcb0485314c590c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.0

Release files / oathline_guard-0.1.0-py3-none-any.whl

Download URL oathline_guard-0.1.0-py3-none-any.whl
Size 28.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a38b95a17dac191884479674b7aba920e6708ed08032ecf89384cac779e863e0
BLAKE2b-256 checksum
How to use checksums
07330d336c05f5dc0172430064822cdc02eca8a96e07b13b2915c43f5bece2e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.0

Security for oathline-guard 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page