The workflow
From a versioned template to a signed agreement, on your machine.
Nine steps across nine CLIs. Each is a single CLI invocation. The output of one step is the input
of the next. Stop at any point — the artifacts you have are useful on their own. Two entry points:
ingest foreign paper with extract (step 0), or start from your own versioned
template (step 1).
extract → template-vault get → draft →
review → negotiate → contract-lint → compare →
docx2pdf → sign → contract-vault. Nine tools, no SaaS, no shared database. Files in, files out.
0 — Ingest any contract (the open-loop front door)
The rest of this pipeline is a closed loop that handles documents authored from your own templates.
extract-cli is how foreign paper gets in: hand it a
counterparty's contract in .md / .txt /
.html / .docx / .pdf and it
returns structured JSON — parties, dates, governing law, and a clause map normalized onto the same
canonical vocabulary the rest of the suite speaks. Feed that straight into review
(step 3) or compare (step 5). Authoring from your own template instead? Skip to step 1.
# Turn a counterparty's contract into structured JSON
extract counterparty-nda.docx --output extract.json
# Its canonical_title values line up with your vault, so a plain diff finds clause gaps
extract counterparty-nda.docx | jq -r '.clauses[].canonical_title' | sort -u 1 — Store & version
Start in your vault. template-vault-cli keeps your house
templates and forked public sources (Common Paper, YC SAFE, Bonterms) in one Git-backed, searchable
place. Pull a public template in, or compose your own by forking a base and swapping a clause — every
swap records its provenance in meta.json, so a later upgrade
pulls parent improvements in without clobbering your local changes. Resolve a versioned template to a
path and hand it to the next step.
# One-time: make a vault and import a public source
template-vault init
template-vault import common-paper-mutual-nda # → nda/common-paper-mutual
# Compose a house variant; swap one clause in, with provenance recorded
template-vault compose --base nda/common-paper-mutual --as nda/house-mutual
template-vault swap nda/house-mutual --clause "Term and Survival" --from nda/yc
# Resolve the template path to hand to draft-cli
template-vault get nda/house-mutual --path-only 2 — Draft
Take the template from your vault and fill it with draft-cli. Point it at the
file (markdown or
.docx — the Common Paper Mutual NDA, your own house template, a SAFE,
anything with placeholders) and pass the parameter values. --list-placeholders
first if you want to see what the template expects; --diff previews the
substitutions before writing. Output is markdown or a styling-preserving .docx
round-trip.
# Discover what the template needs (run once)
draft templates/mutual-nda.docx --list-placeholders
# Fill it, .docx → .docx with styling preserved
draft templates/mutual-nda.docx \
--party-a "Acme Inc." \
--party-b "Beta LLC" \
--purpose "evaluating a partnership" \
--effective-date "2026-06-01" \
--term "2 year(s)" \
--governing-state "California" \
--output output/nda.docx
# Or feed unstructured prose and let the LLM tier extract values
draft templates/mutual-nda.md --from-deal deal-notes.txt \
--output output/nda.md draft-cli generalizes drafting: anything with placeholders can be
filled the same way (NDAs, SOWs, SAFEs, board consents). nda-review-cli
also ships a few bundled NDA templates and can render them directly via its own
draft subcommand — convenient when you're working with one of those known
templates and want the review step pre-wired in the same invocation.
3 — Review
Whether the document was drafted by you or arrived from the other side, run it through
review to score it against your house policy. Findings come with severity,
matched rule patterns, and clause-level evidence. Optionally add --llm
to layer in a second-pass adjudication from your model of choice.
nda-review-cli review --file output/nda.md --why \
--out-md output/review.md 4 — Negotiate
If the counterparty has the CLI installed too, you can run a structured back-and-forth on a single state file that bounces between you (email, Drive, Git — whatever channel you prefer). Each round is signed and hash-chained; tampering is detected on load. Stance, clause priorities, and non-negotiable redlines all live in your local policy.
# Party A starts the negotiation
nda-review-cli negotiate init --template common-paper-mutual ... --out neg.json
# Party B counters using their own policy and stance
nda-review-cli negotiate counter --state neg.json --as b --auto
# Party A reviews the diff and accepts
nda-review-cli negotiate diff --state neg.json --out-md round-2.md
nda-review-cli negotiate accept --state neg.json --as a
# Both sign off; finalize emits the agreed text
nda-review-cli negotiate sign-off --state neg.json --as a --yes
nda-review-cli negotiate sign-off --state neg.json --as b --yes
nda-review-cli negotiate finalize --state neg.json \
--out-md output/agreed.md --out-docx output/agreed.docx
No counterparty CLI install? Send them the .docx directly and skip ahead.
Negotiation is opt-in; the workflow doesn't depend on it.
5 — Lint, then gate for drift
Two complementary gates run before anything goes into a signing envelope. First, contract-lint checks the document's internal consistency — leftover placeholders, broken cross-references, undefined/unused defined terms, numbering gaps, and party-name/date inconsistencies — and exits non-zero so CI can block on it. Where compare gates drift between versions, contract-lint gates defects within one document.
# Catch internal defects before the file goes anywhere
contract-lint ready-to-sign.md --check --fail-on error
# exit 0 = clean · 1 = findings at/above the threshold · 2 = bad usage Then compare-cli does a clause-aware diff between the text you agreed to and the artifact you're about to sign — catching the quiet shift between "final version" and "the file the paralegal actually sent back." The verdict is an exit code your script or CI can branch on, so a human only gets pulled in when the drift is substantive.
# Did the ready-to-sign file drift from the agreed text?
compare output/agreed.md ready-to-sign.pdf --json
# exit 0 = safe to sign · 2 = substantive drift (review!) · 3 = cosmetic only · 4 = clauses moved
Deterministic and cross-format (.docx / .pdf /
.md / text), with no LLM tier — the same two inputs always produce the same
verdict, which is what makes it defensible as a gate. If the drift is only cosmetic or a reordering,
you've confirmed the agreement didn't change and can proceed.
6 — Convert to PDF
Once you have an agreed .docx, hand it to docx2pdf-cli.
Single-file or batch, parallel processing, font validation, and a hybrid backend strategy that picks
the right converter for what's on your machine. No silent fallbacks — failures are loud, fonts are
checked, the output is honest.
docx2pdf output/agreed.docx output/agreed.pdf
# or for a folder full of contracts:
docx2pdf --concurrency 4 --out-dir ./pdfs ./drafts/*.docx 7 — Sign
Hand the PDF to sign-cli. Pick a provider — the built-in
local provider produces real PAdES-signed PDFs fully offline (no
signup, no API keys), or route through Dropbox Sign, DocuSign, or SignWell for an external
trust anchor. Each signer gets a per-recipient approval token with a TTL. Every signing event
lands in a hash-chained audit log, and the receipt bundle includes RFC 3161 timestamps so you
can prove what was signed and when, even years later.
sign request create \
--title "Mutual NDA" \
--document output/agreed.pdf \
--signer "name:Alice Founder,email:alice@acme.com" \
--signer "name:Bob Counsel,email:bob@beta.com" \
--provider signwell
# Or skip the convert + sign steps and seal a DOCX in one shot (offline, PAdES)
sign document output/agreed.docx \
--signer "Alice Founder" --signer-email alice@acme.com \
--name-signature true --auto-place first \
--out output/agreed.sealed.pdf
# Verify a signed PDF later, offline (works on any PAdES-signed PDF)
sign pdf inspect --pdf output/agreed.signed.pdf
sign audit verify --request-id <id> 8 — Manage (post-signature)
Signing isn't the end — it's the start of the obligations. Register the executed contract in
contract-vault-cli (it ingests the same
extract output that drove intake), and it surfaces what you'd
otherwise miss: auto-renewal notice deadlines, expirations, and payment dates — as a
queryable portfolio and an .ics calendar. risk --strict
is a CI gate for a missed auto-renewal notice.
# Register the signed contract (ingests extract-cli output)
extract output/agreed.signed.pdf | contract-vault ingest -
# Project the next quarter of renewals / notice deadlines to a calendar
contract-vault due --within 90d --format ics > deadlines.ics
# Renewal-exposure gate (non-zero on a missed auto-renewal notice)
contract-vault risk --within 30d --strict What you end up with
output/agreed.md— the human-readable agreed textoutput/agreed.docx— the same content as a Word documentoutput/agreed.pdf— the rendered PDFoutput/agreed.signed.pdf— the signed PDF, with embedded signatures- A negotiation state file with every round, every amendment, every signature, hash-chained
- A signing receipt bundle with all audit events and timestamps
- A registered deal in your contract-vault — git-tracked, with a renewals/notice
.icscalendar
All of these live on your machine. Nothing is held by a vendor. You can archive them, version-control them, or hand them to opposing counsel as evidence of what was agreed and when. That's the whole point.
Skipping or substituting steps
Each tool stands alone. If you already have a filled Word document, skip the vault + draft steps. If you trust the ready-to-sign file, skip the compare gate. If you sign with a notary or a different e-signature provider, skip the signing step — you'll still have a clean PDF from the convert step. The point isn't that you must use all nine; it's that they compose cleanly when you do.