Skip to content
contract.cli

Tool · Node.js

draft-cli

draft-cli v0.9.0 0 665/wk on npm Latest from npm · checked Sun, 17 May 2026

Fill placeholders in a legal-document template with parameter values. Five-tier detection (literal brackets, mustache, .docx highlights, generic-name heuristic, optional LLM), a locked parameter-schema contract, and a .docx round-trip that preserves runs and styling. The drafting step at the start of the contract pipeline.

TL;DR — npm i -g @drbaher/draft-cli, then draft template.md --party-a "Acme" --output filled.md. Hand .docx in and out for a styling-preserving round-trip. Run --list-placeholders first to see what the template needs.

What it does

  • Five-tier detection cascade. Bracket syntax ([Party A]), mustache ({{party_a}}), .docx highlighted runs, a generic-name heuristic dictionary, and (only when configured) an LLM tier. First tier with ≥1 hit wins; the rest are skipped. Active tier is reported in --why and JSON output.
  • .docx round-trip with run preservation. Input .docx, output .docx. The Word package is unzipped, substitutions land inside the same <w:t> runs detection found, and everything else (relationships, images, headers, content types) passes through unchanged. v0.9.0 added smart run-merging for placeholders split across runs (the Common Paper case) with --strict-runs as the opt-out.
  • Typed parameters. Schema declares type (date / money / party) and per-type format + currency. Inputs normalize before substitution — "2026-06-01" renders as June 1, 2026, 5000000 as $5,000,000.00.
  • Computed placeholders. Date arithmetic via computed.from in the schema. expiry_date = effective_date + term, derived once at substitution time. No spreadsheet glue.
  • Positional addressing. When the same role appears under different labels (YC SAFE: "Investor" on the cover page, "[Investor]" in the body), positions maps the role to its occurrence list so one CLI flag fills all positions.
  • parties.json registry. Resolve ref:parties.acme_corp.name across templates so the same legal entity definition is the single source of truth.
  • Multi-document bundles. One parameter set, many output documents. NDA + SAFE + Side Letter all share the same party_a, party_b, effective_date; bundle config maps each template to its output path.
  • LLM-from-deal inference (opt-in). --from-deal deal-notes.txt hands free-form prose to your configured LLM provider; only declared placeholder keys are extracted, CLI / --params always win on collision. Extra keys warned to stderr; --no-llm opts out.
  • Honest discovery + diff. --list-placeholders enumerates what the template needs (keys, aliases, occurrence counts, tier). --diff shows the substitution table without writing output. --why prints a stable structured explanation.

Quickstart

install + run
# Install
npm i -g @drbaher/draft-cli
draft --version

# What placeholders does this template need?
draft template.md --list-placeholders

# Fill a markdown template; print to stdout
draft template.md --party-a "Acme Corp" --party-b "Globex"

# Fill a Word document; round-trip styling preserved
draft contract.docx --params deal.json --output filled.docx

# Preview substitutions without writing output
draft template.md --params deal.json --diff

# Validate completeness (CI / agent precheck)
draft template.md --params deal.json --validate

# Infer values from unstructured prose (LLM, when configured)
draft nda.md --from-deal deal-notes.txt --output draft.md

Why a separate drafting tool

nda-review-cli ships a few bundled NDA templates and can render them via draft — fine when you're drafting an NDA against one of those known templates. draft-cli generalizes the same idea: any markdown or .docx file with placeholders, any parameter set, any output format. Side letters, SAFEs, employment agreements, board consents, vendor MSAs — same shape, same substitution discipline, same --why / --diff / --validate affordances.

The locked PARAM_SCHEMA.md contract is the load-bearing part: schemas don't change between minor versions, so an agent or pipeline that reads the schema at startup can rely on the surface shape. --json output mirrors the same shape.

For agents and automation

Agent affordances are baked in. AGENTS.md documents the output envelope, exit codes, and failure → recovery loop. --list-placeholders --json is a structured manifest of what a template needs (keys, aliases, types, defaults). --validate is the precheck before substitution. The LLM tier is opt-in and isolated under its own provider config (ANTHROPIC_API_KEY / OPENAI_API_KEY / explicit DRAFT_LLM_*); no network call without consent.

recommended agent defaults
# Discover schema, then fill — error-fast at validation
draft template.md --list-placeholders --json
draft template.md --params deal.json --validate
draft template.md --params deal.json --output filled.docx --json

Where it fits in the workflow

The first step in the four-CLI workflow: take a template you control (markdown or .docx) and produce a filled draft to hand to nda-review-cli for policy review or directly to docx2pdf-cli for PDF rendering. See the full workflow for the chained commands.

It's also useful on its own for any templated drafting — SOWs, invoice prefaces, board materials, anything with placeholders. The contract pipeline is one application.

Repo

github.com/DrBaher/draft-cli · MIT licensed · Node.js · npm-installable.

Edit this page on GitHub