Skip to content
contract-ops CLI suite

contract-ops-agent

A contract agent in an enclosure.

Don't want to wire the suite into your own agent? contract-ops-agent is a ready-made terminal agent whose only tools are the contract-ops suite, exposed through contract-ops-mcp. No shell, no filesystem access, no web, no signing — not by policy but by construction. If a request can't be served by extract, lint, compare, fill, convert, review, draft, negotiate, the vaults, or verify, the agent literally has no way to do it.

TL;DR — npm install -g contract-ops-agent, run it, answer a short wizard (installed CLIs, workspace, model & auth), and you're in a REPL where you type contract requests in plain language. Works with Claude, OpenAI, Gemini, Grok, DeepSeek, OpenRouter, Ollama, or any OpenAI-compatible endpoint — the enclosure is identical on every backend. Repo.

Install & run

npm
npm install -g contract-ops-agent
contract-ops-agent          # first run: a one-time setup wizard, then the REPL

Or zero-setup via Docker — the agent, all nine CLIs, and a PDF backend bundled; bring only a model key. The named volume persists config and stored keys across runs:

docker
docker run -it --rm \
  -v "$PWD:/workspace" \
  -v contract-ops-config:/config \
  -e OPENAI_API_KEY \
  ghcr.io/drbaher/contract-ops-agent

The local install needs the contract-ops CLIs on your PATH (the MCP server shells out to them) — the wizard and doctor report which are missing and can install them. macOS and Linux; Windows via WSL or the container. Config lives under ~/.config/contract-ops-agent/; any secret is stored in a separate 0600 file, never in config.json or a transcript.

What a session looks like

Type requests in plain language — "extract acme-nda.docx, score it against our playbook, and show me what changed since round 2". Each executed tool is echoed as ⚙ tool {args}, and every turn ends with an accounting footer (tool calls, cost or tokens). Consequential tools — fill_template, convert_to_pdf, the run escape hatch — stop and ask you first.

the CLI surface
contract-ops-agent [--workspace <dir>] [--model <m>]   start the agent
contract-ops-agent --resume [last|<transcript.jsonl>]  continue a prior conversation
contract-ops-agent setup                               (re)run the setup wizard
contract-ops-agent doctor                              check env, auth, signing + fallback config
contract-ops-agent tool [<name> ['{json}']]            list tools, or run one directly (no model)
contract-ops-agent usage                               per-session turns / tools / tokens / cost

In the REPL, /help lists commands and /model switches the model mid-session (/model gemini — context resets, the enclosure is re-verified). Input can also be piped for scripted one-shot sessions: echo "lint agreement.md" | contract-ops-agent. And tool is the model-free path — it drives one CLI through the same MCP mount, with the same path confinement and the same gates.

Every tool call, gate decision, and result is recorded to a JSONL transcript, which is what --resume and usage read back.

Bring your own model

The model is a config choice, not an architecture choice:

Ref Runs on Auth
claude Claude Agent SDK (default) ANTHROPIC_API_KEY or your existing Claude Code login
openai/gpt-4o the agent's own tool-calling loop OPENAI_API_KEY
gemini/… grok/… deepseek/… openrouter/… ollama/… zero-config presets (ollama needs no key) the preset's key env var
myendpoint/… any OpenAI-compatible endpoint via a providers config entry your choice of env var

Fallback chains: list refs in config ("fallbacks": ["gemini/gemini-2.5-flash", "claude"]) and the agent fails over mid-conversation when a provider dies — terminal errors only; rate limits just retry — replaying your unanswered message with the conversation re-seeded. doctor validates every fallback ref and its key up front.

Local models have a real limit — The agent exposes ~50 tools, and small local models (7B–14B) can't reliably pick from that many — in testing, qwen2.5 7B and 14B both failed the full workflow. Frontier cloud models (Claude, gpt-4o) handle all 50 cleanly (5/5). For Ollama, use a large model (32B+); otherwise prefer a cloud model. Full data: docs/model-eval.md.

The enclosure

The guarantee is the same on every backend: the model only ever sees the contract-ops tools, every consequential tool passes a human gate, and the session refuses to start if anything else is mounted. On Claude (Agent SDK) that's three layers:

  1. Context strippingdisallowedTools removes every built-in and harness tool from the model's view.
  2. Gate deny — a canUseTool policy denies anything not matching mcp__contract-ops__*, and requires human approval for consequential tools.
  3. Startup assertion — the harness reads the SDK's init message and refuses to run unless every mounted tool is a contract-ops tool. This is the real guarantee; layers 1–2 are how it's satisfied.

On every other provider the harness owns the loop, so layer 1 is a property of construction — the tool list handed to the model is built only from the contract-ops MCP server; there are no built-ins to strip. The gate and the startup assertion are the same code on both paths. And a provider failure never loses your session: transient errors retry with backoff, anything else ends the turn — not the conversation — with a clear message.

Signing is opt-in, twice

By default signing is unreachable — the loop ends at "ready for signature" and hands off to your own sign-cli flow. Two modes soften this deliberately; both require "signing": {"mode": …} in config and --enable-signing at launch:

  • prepare mounts sign-cli's own MCP server least-privilege (enforced by sign-cli itself via --read-only --tool …): request tracking, audit/receipt verification, field detection, preview stamps. The signing act does not exist in the session.
  • full adds the signing act (sign, document, signer_decline). Every such action stops at a typed gate: you must type the exact target (request id / file name) back — y/N is not consent for a signature, and approvals are never remembered. A signing act can only be approved from an interactive terminal; piped or scripted input can never confirm a signature.

In both modes the startup assertion accepts exactly that mode's sign tools and still fails on anything unexpected. Design record: docs/sign-mount-scope.md.

NDA review & negotiation

The agent also drives the full nda-review-cli surface: score an NDA against your house playbook, generate clause-ready redlines, draft from a template, and run a round-based negotiation. Signing a negotiation round is a binding commitment, so — like signing itself — it stops at a typed-consent gate you approve.

Where it sits

Three ways to put an agent on the suite, in increasing order of assembly required: this ready-made agent (nothing to wire), contract-ops-mcp in your own MCP-aware client (Claude Code, Cursor, Codex…), or the CLIs driven directly by a shell-running agent (built for agents). The enclosure is what the first buys you over the other two: a session that cannot touch anything but contract work, on any model you point it at.

Next — The repo · point it at any endpoint · which models can drive it · or wire the suite into your own agent via the MCP page.

Edit this page on GitHub