npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hasna/signatures

v0.1.14

Published

Open-source agreement and e-signature workflows for Markdown, PDFs, local signing, providers, CLI, API, and MCP

Readme

Open Signatures

Open Signatures is an open-source agreement workflow toolkit for local-first document signing. It can render Markdown agreements to clean PDFs, place signatures at detected fields or explicit coordinates, generate completion certificates, manage signers, send signing requests through open-emails, and prepare domain setup through open-domains.

The current package name stays focused on signatures, but the product surface is broader: agreements, people, signing sessions, provider handoff, evidence, and completion records.

Open Signatures is not a qualified trust service or a substitute for regulated digital signature infrastructure. It is intended for regular electronic signatures, internal workflows, and developer-owned signing flows where local audit evidence is sufficient.

Install

npm install -g @hasna/signatures

Local development:

bun install
bun run typecheck
bun test
bun run build

Quick Start

Create a text signature:

open-signatures signature create --name "Ada Lovelace" --type text --text "Ada Lovelace"

Render a Markdown agreement with variables and a signature anchor:

# Consulting Agreement

Client: {{ signer.name }}

Please sign here: {{signature:client}}
open-signatures document from-markdown ./agreement.md \
  --signer-name "Ada Lovelace" \
  --signer-email [email protected]

Sign at the generated field and create a local evidence certificate:

open-signatures document sign <document-id> \
  --signature <signature-id> \
  --field <field-id> \
  --signer-name "Ada Lovelace" \
  --signer-email [email protected]

The command writes:

  • a signed PDF in ~/.hasna/signatures/signed/
  • a signer-evidence or document-completion certificate in ~/.hasna/signatures/certificates/
  • audit events in the local SQLite database

Markdown Variables

Variables use double braces:

{{ signer.name }}
{{ signer.email }}
{{ company.name }}
{{ signature }}
{{ signature:client }}
{{ signature:review|type=agent|role=Reviewer|order=2|group=1 }}

{{signature}} and {{signature:name}} become signature fields when Markdown is rendered to PDF. Other variables are replaced from CLI --var key=value values or signer options.

Signature anchors can carry routing metadata:

  • type=human|agent sets the signer type.
  • role=Reviewer stores the signer role.
  • order=2 controls signing order.
  • group=1 groups parallel signers.
  • required=false makes the field optional.

Example:

Human approval: {{signature:client|type=human|role=Client|order=1}}
Agent review: {{signature:review|type=agent|role=Reviewer|order=2}}

Sending For Signature

Create a signing session and local URL:

open-signatures document send <document-id> \
  --signer-name "Ada Lovelace" \
  --signer-email [email protected] \
  --base-url https://sign.example.com

The generated signing URL resolves to /sign/<token>, where the signer can type their name/signature and complete the local signing session. Open Signatures creates a text signature when the signer does not already have one.

Send with open-emails if the emails CLI is configured:

open-signatures document send <document-id> \
  --person [email protected] \
  --from [email protected] \
  --base-url https://sign.example.com

Use --dry-run-email to preview the open-emails command without sending.

Attachment sharing is optional. If @hasna/attachments is installed and configured, send/share flows attach a document share link. If it is not installed, local signing URLs still work and the session records the share-link fallback.

People

open-signatures person add "Ada Lovelace" --email [email protected] --phone "+1..."
open-signatures signer add "Sagan" --type agent --agent-id agent-sagan --agent-provider codewith --role Reviewer
open-signatures person list
open-signatures person list --type agent
open-signatures document send <document-id> --person [email protected]

Signer records can be humans or agents. Agent signatures are recorded as local agent attestations with agent id, provider/runtime, run id, policy id, reason, hashes, audit events, and certificate metadata. They are useful for internal approvals between agents or systems, but they are not human identity proof and are not QES/eIDAS signatures. For ordered or multi-signer documents, Open Signatures writes signer-evidence certificates for partial completion and reserves document-completion metadata for the final required field/session.

Sign as an agent:

open-signatures document sign <document-id> \
  --field <field-id> \
  --signer-type agent \
  --signer-name "Sagan" \
  --agent-id agent-sagan \
  --agent-provider codewith \
  --agent-run-id run-123 \
  --agent-policy-id internal-agent-approval-v1 \
  --agent-reason "Policy check passed"

When --signer-type agent is used without --signature, the CLI creates a minimal local attestation signature automatically.

List signing sessions:

open-signatures sessions list --signer-type agent

Domains

Open Signatures delegates domain setup to open-domains through the domains CLI.

Preview commands:

open-signatures domain setup example.com --subdomain sign --target cname.example.net --dry-run

Run setup:

open-signatures domain setup example.com --subdomain sign --target cname.example.net

Use --buy to ask open-domains to run its full domain setup flow.

Provider Integrations

The built-in local signing flow is first-class. Provider adapters are optional. Provider flows always require an explicit signature level:

  • ses - simple electronic signature evidence
  • aes - advanced electronic signature target
  • qes - qualified electronic signature target through a QTSP/provider
  • eseal - legal-entity electronic seal target
  • qeseal - legal-entity qualified eSeal target

Open Signatures does not turn local signatures into QES. QES and qualified eSeals must be completed by a qualified trust-service/provider flow. The app stores the request, hashes, provider response, validation status, and audit events as provider evidence.

Dry-run a PandaDoc QES request:

open-signatures provider send <document-id> \
  --provider pandadoc \
  --signature-level qes \
  --recipient [email protected] \
  --recipient-name "Ada Lovelace" \
  --signer-type human \
  --dry-run

Dry-run a Yousign QES request:

open-signatures provider send <document-id> \
  --provider yousign \
  --signature-level qes \
  --recipient [email protected] \
  --recipient-name "Ada Lovelace" \
  --signer-type human \
  --dry-run

List stored provider evidence:

open-signatures provider evidence <document-id>

For live connector-backed provider execution, configure either a hosted or local Hasna connectors endpoint:

open-signatures config set connectors_api_url "https://connectors.example"
open-signatures config set connectors_api_key "$CONNECTORS_API_KEY"

or:

open-signatures config set connectors_server_url "http://localhost:9876"

The provider layer uses @hasna/connectors-sdk and can route to pandadoc or yousign connector operations when those connectors and credentials are available. Without provider credentials, use --dry-run to verify requests and evidence locally.

For direct PandaDoc API calls without connectors:

open-signatures config set pandadoc_api_key "$PANDADOC_API_KEY"
open-signatures provider send <document-id> \
  --provider pandadoc \
  --signature-level qes \
  --recipient [email protected] \
  --recipient-name "Ada Lovelace"

PandaDoc documents may require asynchronous readiness polling before send in production integrations. Connector-backed execution should own that provider-specific behavior.

REST API

signatures-serve

Selected endpoints:

  • POST /api/documents/from-markdown
  • POST /api/documents/:id/sign
  • POST /api/documents/:id/send
  • POST /api/documents/:id/provider-send
  • GET /api/sessions
  • GET /api/sessions/:id/certificate
  • GET /api/provider-evidence
  • GET /sign/:token
  • POST /api/sign/:token
  • GET /api/people

The server is designed for trusted local or private deployments by default. If you expose it publicly, put it behind authentication, TLS, request logging, and a file access policy.

Dashboard

The dashboard is a separate Vite app for local operations:

signatures-serve
cd dashboard
bun install
bun run dev

It includes overview, agreement, signing session, people, signature, certificate, provider, and domain setup views.

MCP Server

signatures-mcp

Workflow tools include:

  • signatures_document_from_markdown
  • signatures_sign
  • signatures_send_for_signature
  • signatures_person_create
  • signatures_certificate_get

Configuration values containing key, secret, or token are masked in MCP responses.

Data Directory

When SIGNATURES_DB_PATH or HASNA_SIGNATURES_DB_PATH is set, that file is used as the SQLite database. Otherwise, a git checkout uses the repo-local .signatures/signatures.db; outside a git checkout, data is stored under:

~/.hasna/signatures/

Security Model

Open Signatures stores signing evidence locally. A certificate includes signer metadata, document hashes, session id, audit summary, and metadata that distinguishes signer_evidence from document_completion. This provides useful evidence for ordinary electronic signature workflows, but does not provide regulated digital signature, qualified electronic signature, or eIDAS/QTSP guarantees.

Provider evidence records are not validation reports by themselves. A QES/eSeal workflow is only considered externally validated after a provider/QTSP signed output, proof/audit file, and validation report are attached and recorded as valid.

Do not publish local .hasna/, .signatures/, .env, or .claude/ directories.

License

Apache-2.0 - see LICENSE.