{"id":50968165,"url":"https://github.com/DrBaher/sign-cli","last_synced_at":"2026-07-06T19:00:37.354Z","repository":{"id":356148551,"uuid":"1231097990","full_name":"DrBaher/sign-cli","owner":"DrBaher","description":"Agent-first e-signature CLI. Fully-offline PAdES signer (PKCS#7) — no signup — or hosted providers. 19-tool MCP server, hash-chained audit, RFC 3161. Per-signer tokens gate the human. Part of the eight-CLI contract-ops suite — cli.drbaher.com","archived":false,"fork":false,"pushed_at":"2026-06-21T11:38:06.000Z","size":1662,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-21T12:04:55.338Z","etag":null,"topics":["agent-first","ai-agent","audit-log","cli","compliance","contract-automation","contract-ops","docusign","dropbox-sign","e-signature","eidas","llm","mcp","model-context-protocol","pades","pdf-signing","rfc3161","signwell","typescript"],"latest_commit_sha":null,"homepage":"https://cli.drbaher.com/tools/sign-cli/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DrBaher.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-06T16:14:32.000Z","updated_at":"2026-06-21T11:38:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"92cf3e1c-44c4-4a43-b92f-6bbfa0f9bd74","html_url":"https://github.com/DrBaher/sign-cli","commit_stats":null,"previous_names":["drbaher/cli-digital-signature-mvp","drbaher/sign-cli"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/DrBaher/sign-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fsign-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fsign-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fsign-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fsign-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DrBaher","download_url":"https://codeload.github.com/DrBaher/sign-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fsign-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35202786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-first","ai-agent","audit-log","cli","compliance","contract-automation","contract-ops","docusign","dropbox-sign","e-signature","eidas","llm","mcp","model-context-protocol","pades","pdf-signing","rfc3161","signwell","typescript"],"created_at":"2026-06-18T23:00:24.284Z","updated_at":"2026-07-06T19:00:37.308Z","avatar_url":"https://github.com/DrBaher.png","language":"TypeScript","funding_links":[],"categories":["MCP Servers for Legal"],"sub_categories":["Multilingual \u0026 Regional Legal Models"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/icon.svg\" width=\"120\" alt=\"sign-cli\"\u003e\n\u003c/p\u003e\n\n# sign-cli\n\nFully-offline e-signature CLI. The built-in PAdES signer (PKCS#7 in `/ByteRange`, self-issued cert) produces real, cryptographically verifiable signed PDFs with no signup and no third-party provider — or routes through Dropbox Sign / DocuSign / SignWell when you need an external trust anchor. Per-signer approval tokens (TTL-bounded, scoped to one email), hash-chained audit events, RFC 3161 timestamping, named profiles, a 19-tool MCP server, and a 20-route HTTP API.\n\n**The asymmetry is the architecture**: an agent can drive every step except the actual signing gesture, which stays gated behind a human.\n\n\u003e **Part of the contract-ops CLI suite — optional.** sign-cli works entirely on its own; it's also the **signing + audit** step of the [contract-ops suite](https://cli.drbaher.com/): [template-vault-cli](https://github.com/DrBaher/template-vault-cli) → [draft-cli](https://github.com/DrBaher/draft-cli) → [nda-review-cli](https://github.com/DrBaher/nda-review-cli) → [docx2pdf-cli](https://github.com/DrBaher/docx2pdf-cli) → **sign-cli**, with drift detection via [compare-cli](https://github.com/DrBaher/compare-cli).\n\n## Run this\n\n```bash\nnpx @drbaher/sign-cli demo\n```\n\nThat single command runs the entire lifecycle — create → send → sign → verify chain → export receipt — against the offline local provider, then deletes everything. No signup. No keys. ~5 seconds.\n\n\u003e **[Live demo →](https://sign-cli-demo-production.up.railway.app/web-demo/)** — read-only, resets every 4 hours. Self-host: see [`deploy/README.md`](deploy/README.md).\n\n## Where to go next\n\n| If you are… | Start here |\n|---|---|\n| **A new user** evaluating the tool | This README's [Quick start](#quick-start), then [Standard user journey](#standard-user-journey) |\n| **An operator** wiring up a hosted provider | [docs/setup/](docs/setup/) — Dropbox / DocuSign / SignWell / embedded |\n| **An LLM agent** driving the CLI | [AGENTS.md](AGENTS.md) → [docs/agent-guide.md](docs/agent-guide.md) → [docs/recipes/](docs/recipes/) |\n| **An auditor** verifying a signed bundle | [docs/reference/audit-chain.md](docs/reference/audit-chain.md), [docs/reference/legal.md](docs/reference/legal.md) |\n| **A contributor** | [docs/reference/architecture.md](docs/reference/architecture.md), [docs/regression-testing.md](docs/regression-testing.md) |\n| **Adding a new CLI to the suite** | The [build-a-CLI playbook](https://cli.drbaher.com/build-a-cli) — the conventions every suite CLI follows |\n\nConcept deep-dives live in [docs/reference/](docs/reference/); task-oriented recipes in [docs/recipes/](docs/recipes/).\n\n## Quick start\n\n```bash\n# Install\nnpm i -g @drbaher/sign-cli\n\n# Or run without installing\nnpx @drbaher/sign-cli demo\n\n# After install, the binary is named `sign`\nsign --version\nsign demo\nsign init        # wizard: provider selection + .env\nsign doctor preflight   # structured per-check readiness report\n```\n\nOr download a standalone binary from [Releases](https://github.com/DrBaher/sign-cli/releases) — `./sign-linux-x64 demo`. See [DISTRIBUTION.md](./DISTRIBUTION.md) for every install path.\n\n## What this gives you\n\n- **Offline PAdES signing** with a self-issued cert — real PKCS#7 signed PDFs, no signup, no API keys.\n- **Three hosted providers** when you need them: Dropbox Sign, DocuSign, SignWell. Same surface across all four.\n- **Per-signer approval tokens** (single-use, TTL-bounded, tied to one email). Tokens go to the human, not the agent.\n- **Hash-chained audit chain** with append-only DB triggers + RFC 3161 anchors. See [docs/reference/audit-chain.md](docs/reference/audit-chain.md).\n- **Idempotent `request send`** — refuses to double-send unless `--force true`; pair with `--idempotency-key` for safe retries.\n- **Multi-document + multi-signer** requests; CSV-driven bulk send.\n- **Templates** from each provider's dashboard via `request from-template`.\n- **Auto-detect signature field** (`sign pdf detect-signature-field` + `sign sign --auto-place`). Detects AcroForm `/Sig` widgets and anchor text in English + French/EU conventions.\n- **Inspect any signed PDF** with `sign pdf inspect` — parses PAdES PKCS#7 from sign-cli or any other producer (Adobe, DocuSign, Dropbox Sign, SignWell). Returns signer CN/email, cert subject + issuer, validity window, fingerprint, trust label (`self_signed_local` / `self_signed_other` / `ca_signed` / `unknown`), and message-digest match.\n- **Counter-sign visibility** — `signer fetch-document` and the MCP `signer_fetch_document` tool surface `existingSignatures`, so a signer can see what they're countersigning before they sign.\n- **One-shot DOCX → sealed PDF** via `sign document` (chains the bundled docx2pdf-cli, auto-place, stamp, PAdES-seal, verify in one call against a scoped temp DB).\n- **Sandbox via `--read-only true`** on both `mcp serve` and `serve`. Mutating tools/routes return `FORBIDDEN_READ_ONLY`.\n- **Path-traversal guards** on every input and output path. See [docs/reference/security-controls.md](docs/reference/security-controls.md).\n- **Named profiles** bundle provider + dbPath + credentials (with `{{env:VAR}}` references for shell-managed secrets). See [docs/reference/profiles.md](docs/reference/profiles.md).\n- **PDF verification** end-to-end offline: `request verify-signed-pdf` recomputes the digest, extracts X.509 signer certs, supports `--recipient \u003cemail\u003e` for a redacted single-signer view, and reports per-signer `trust` labels.\n\n## Standard user journey\n\n```bash\nsign request create \\\n  --title \"Mutual NDA\" \\\n  --document ./nda.pdf \\\n  --signer name:Alice,email:alice@acme.com,order:1 \\\n  --signer name:Bob,email:bob@beta.com,order:2 \\\n  --provider signwell\n\nsign approve --request-id \u003cid\u003e --token \u003ctoken1\u003e\nsign approve --request-id \u003cid\u003e --token \u003ctoken2\u003e\n\nsign request send --request-id \u003cid\u003e --provider signwell --test-mode true\n\nsign request watch \\\n  --request-id \u003cid\u003e --provider signwell \\\n  --interval-seconds 5 --fetch-final true \\\n  --out ./signed.pdf\n\nsign audit show --request-id \u003cid\u003e\n```\n\nOr fully offline:\n\n```bash\nsign request create --title \"Mutual NDA\" --document ./nda.pdf \\\n  --signer name:Alice,email:alice@example.com,order:1 \\\n  --signer name:Bob,email:bob@example.com,order:2 \\\n  --provider local --auto-approve true\nsign request send --request-id \u003cid\u003e --provider local\n# Each signer runs:\nsign sign --request-id \u003cid\u003e --token \u003ctheir-token\u003e \\\n  --require-hash \u003csha256\u003e --require-title \"^Mutual NDA$\"\n```\n\nFor full provider-specific setup, see [docs/setup/](docs/setup/).\n\n## One-shot DOCX → sealed PDF\n\n```bash\nsign document contract.docx \\\n  --signer \"Alice Founder\" --signer-email \"alice@acme.com\" \\\n  --name-signature \"Alice Founder\" --auto-place first \\\n  --out contract.sealed.pdf\n```\n\n`sign document` chains: convert (via the bundled docx2pdf-cli) → detect signature field → stamp → PAdES-seal → verify chain. All intermediate state lives in a scoped temp DB.\n\n## MCP server (for LLM agents)\n\n```bash\nsign mcp serve                  # stdio MCP server\nsign mcp serve --read-only true # sandboxed: mutating tools return FORBIDDEN_READ_ONLY\nsign mcp tools                  # print the catalog (live; don't hardcode the list)\n```\n\n19 tools, split read-only vs mutating. Backed by the same `SignCliError` envelopes you'd see at the CLI. The full discovery contract, wire-up snippets (Claude Desktop, Cursor), and read-only walkthrough are in [AGENTS.md](AGENTS.md). Three resource shapes (`request://\u003cid\u003e` snapshot, `.../document` PDF blob, `.../audit` chain) and four agent-as-signer prompt templates (`review_and_sign`, `policy_check`, `inbox_triage`, `verify_receipt`) are also exposed.\n\n## HTTP API (for non-MCP clients)\n\n```bash\nsign serve --port 4000 --auth-token \u003ct\u003e --read-only true --rate-limit 5\ncurl http://127.0.0.1:4000/v1/openapi.json    # discover the route catalog\n```\n\nTwenty routes under `/v1/*`, 1:1 parity with the MCP tool surface — same input shape, same path-traversal guards, same read-only gating. Bearer auth via `--auth-token` or `SIGN_HTTP_AUTH_TOKEN`. Responses are `{ ok, result }` on success or the standard error envelope on failure.\n\n## Signer-side flow (agent-friendly)\n\nFor `--provider local`, an agent can act as a signer end-to-end without an email link. Set `SIGN_LOCAL_AUTOCOMPLETE=false` so the local provider holds at `sent` until each signer explicitly runs `sign sign`.\n\n```bash\n# As the requester (agent or human)\nsign request create --title \"Mutual NDA\" --document ./nda.pdf \\\n  --signer name:Alice,email:alice@example.com,order:1 \\\n  --signer name:Bob,email:bob@example.com,order:2 \\\n  --provider local --auto-approve true\n# response includes per-signer tokens\nsign request send --request-id \u003cid\u003e --provider local\n\n# As the signer, with their token\nsign signer list --signer-email alice@example.com\nsign signer fetch-document --request-id \u003cid\u003e --token alice-tok-... --out ./nda.pdf\n# fetch-document surfaces `existingSignatures` so the signer can see what they're countersigning\nsign sign --request-id \u003cid\u003e --token alice-tok-... \\\n  --require-hash \u003csha256\u003e --require-title \"^Mutual NDA$\" --require-signer-email alice@example.com\n# or\nsign signer decline --request-id \u003cid\u003e --token alice-tok-... --reason \"Terms changed\"\n```\n\nMulti-signer: status only flips to `completed` when every signer is in `signedBy[]`. Pre-sign safety checks (`--require-hash` / `--require-title` / `--require-signer-email`) throw `PRE_SIGN_*_MISMATCH` before any state mutation.\n\n## Templates\n\nReuse a template defined in the provider dashboard (no PDF upload):\n\n```bash\nsign request from-template \\\n  --template-id tmpl_abc --provider dropbox \\\n  --signer role:Buyer,name:Alice,email:alice@example.com,order:1 \\\n  --signer role:Seller,name:Bob,email:bob@example.com,order:2 \\\n  --prefill name:purchase_price,value:1000 \\\n  --auto-approve true\n\nsign request send --request-id \u003cid\u003e --provider dropbox --test-mode true\n```\n\nEach `--signer` must include `role:\u003croleName\u003e` matching a template role. `--prefill name:K,value:V[,signer:N]` populates template fields. Per-provider behavior: DocuSign uses per-signer text tabs; Dropbox uses `custom_fields`; SignWell uses `placeholders`.\n\n## Field placement\n\nBy default the hosted providers auto-append a generic signature page. For real contracts, pass `--field` (repeatable) on `request create`:\n\n```bash\nsign request create \\\n  --title \"NDA\" --document ./contract.pdf \\\n  --signer name:Alice,email:alice@example.com,order:1 \\\n  --field signer:1,page:1,x:100,y:200,type:signature \\\n  --field signer:1,page:1,x:100,y:240,type:date\n```\n\nSpec: `signer:\u003corder\u003e` (required), `doc:\u003ci\u003e` (multi-doc index), `type:signature|initials|date|text|name|email`, `page:\u003cn\u003e` `x:\u003cpt\u003e` `y:\u003cpt\u003e` (coordinate), or DocuSign-only `anchor:\"text\"` with optional `x-offset` / `y-offset` / `anchor-units`. The fields persist on the request and forward to the provider at send time.\n\n## Auto-detect signature field\n\nFor `--provider local`, `sign sign --auto-place` calls the detector and uses the top candidate iff there's a **unique** high-confidence (`≥0.8`) match.\n\n```bash\n# Inspect candidates first\nsign pdf detect-signature-field --pdf ./contract.pdf\n\n# Auto-place (errors loudly on ambiguity)\nsign sign --request-id \u003cid\u003e --token \u003ct\u003e --name-signature \"Alice\" \\\n  --auto-place first   # or true | last | all | page:N | index:N\n```\n\nAdjustment strategies in priority order: `underline-snap` (0.95), `below-anchor-probe` (0.85, French/EU conventions), `whitespace-probe` (0.75), `shrink-to-fit` (0.50). Date anchors are detected separately via `sign pdf detect-date-field`. Full reference in [`docs/agent-guide.md` §6.4a](docs/agent-guide.md).\n\n## Bulk send\n\n```bash\nsign request bulk \\\n  --csv ./signers.csv \\\n  --document ./contract.pdf --provider dropbox \\\n  --title \"Q2 NDA for {{email}}\" --test-mode true\n```\n\nEach row becomes its own request with `autoApprove: true`. Title template supports `{{email}}`, `{{name}}`, `{{row}}`. Exit code `3` if any row failed; JSON output lists per-row results.\n\n## Trust beyond the provider\n\n```bash\n# Inspect any signed PDF (ours, Adobe's, DocuSign's, …) — no DB lookup required\nsign pdf inspect --pdf ./signed.pdf\n\n# Inspect the embedded PKCS#7 of a request we sent\nsign request verify-signed-pdf --request-id \u003cid\u003e\nsign request verify-signed-pdf --request-id \u003cid\u003e --recipient alice@example.com   # single-signer view\n\n# Anchor the audit head against a public RFC 3161 TSA\nsign audit anchor --request-id \u003cid\u003e\n\n# Bundle for archival\nsign audit export --request-id \u003cid\u003e --out ./bundle/\n```\n\n`audit verify` walks the local hash chain. `request verify-signed-pdf` recomputes the SHA-256 over the `/ByteRange`, compares it to the `messageDigest` in the embedded PKCS#7, **and verifies the PKCS#7 signature value against the signer certificate's public key (RSA/ECDSA)** — so a forged or tampered signature fails, exit `3`, not just a modified-after-signing one. `sign pdf inspect` works on any signed PDF (no request id required). `audit anchor` issues a TimeStamp token from a TSA. See [docs/reference/audit-chain.md](docs/reference/audit-chain.md) for the full model.\n\n## Profiles\n\n```bash\nsign profile init --name prod --provider signwell --db \"~/.sign-cli/prod.db\" --strict-provider true\nsign profile set --name prod --key credentials.SIGNWELL_API_KEY --value \"{{env:SIGNWELL_API_KEY}}\"\nsign --profile prod request show --request-id \u003cid\u003e\n# Or implicitly via a project-level sign-profile.json (git/npm-style upward discovery)\n```\n\nResolution order: flag \u003e env \u003e project profile \u003e user profile \u003e built-in default. Credentials redacted by default in `profile show` (`--show-secrets true` to reveal). Over the MCP HTTP transport, `show_secrets` is refused unless an `--http-auth-token` is configured (it stays available on stdio MCP and the CLI). See [docs/reference/profiles.md](docs/reference/profiles.md).\n\n## Doctor\n\n```bash\nsign doctor                       # legacy env-report; always exits 0\nsign doctor preflight             # structured per-check report; exit 0 ok, 1 failed\nsign doctor providers             # capability matrix across all providers\nsign doctor account-check --provider signwell   # provider /me check\n```\n\n`preflight` runs env-health checks (`runtime:node_version`, `storage:db_path`) on every provider, then provider-scoped checks layer on top. Branch on `checks[].name` for agent self-recovery.\n\n## Security notes\n\n- Never commit `.env` or API keys.\n- Rotate keys if shared in chat/logs.\n- Keep test mode on during development.\n- For path-traversal guards, secret redaction, idempotency, and read-only mode, see [docs/reference/security-controls.md](docs/reference/security-controls.md).\n- For what the chain proves vs. what it doesn't, see [docs/reference/security-model.md](docs/reference/security-model.md).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n## See also\n\n- [AGENTS.md](AGENTS.md) — the agent quickstart (output contract, exit codes, discovery, failure recovery).\n- [docs/agent-guide.md](docs/agent-guide.md) — canonical agent reference (per-command schemas, side effects, idempotency).\n- [docs/setup/](docs/setup/) — provider setup (Dropbox, DocuSign, SignWell, embedded).\n- [docs/recipes/](docs/recipes/) — task-oriented recipes (preflight, agent-loop-mcp, weekly anchor, auditor handoff, sign as Alice, EU NDA).\n- [docs/reference/](docs/reference/) — concept deep-dives (audit chain, exit codes, profiles, security model, architecture, legal posture, comparison).\n- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) — error catalog.\n- [CHANGELOG.md](CHANGELOG.md) — what landed and when.\n- [integrations/](integrations/) — Claude Desktop config, langchain starter.\n- [deploy/](deploy/) — Fly / Render / Railway configs for the hosted demo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDrBaher%2Fsign-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDrBaher%2Fsign-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDrBaher%2Fsign-cli/lists"}