kysigned

mcp
Security Audit
Fail
Health Warn
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in .github/workflows/publish-mcp.yml
  • fs module — File system access in .github/workflows/publish-mcp.yml
  • network request — Outbound network request in frontend/src/auth/AuthContext.tsx
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Self-verifying e-signatures: sign by email, proof sealed by DKIM, verifiable offline forever. Forkable template running on run402.

README.md

kysigned

kysigned

E-signatures at $0.25 an envelope — simple, secure signing powered by your email.

kysigned uses DKIM — the cryptographic signature your email provider already puts on every message you send — as the signature itself. A signer forwards one email; the result is a self-contained evidence bundle (a single PDF) that anyone can verify on their own machine, even offline, even if this service disappears.

Quick Start

1. Sign a document right now (no setup)

Sign documents at kysigned.com. Buy credits, send. No install, no SDK.

2. Deploy your own

kysigned is a complete, self-hostable app: clone it, point it at your own run402 project (managed email + DB + compute), and you're operating your own instance. All run402 I/O goes through @run402/sdk.

git clone https://github.com/kychee-com/kysigned.git
cd kysigned
KYSIGNED_ALLOWED_CREATORS='[email protected],*@example.org' run402 up --name my-kysigned

That command reads run402.json, creates or links a Run402 project, creates the
forward-to-sign and notifications mailboxes, sets generated runtime secrets,
runs the local build, deploys the database/site/function release, and verifies
the app. See docs/run402-cloud.md for the detailed
runbook and smoke-test checklist.

A forker following this path runs the identical public code on their own run402 project, under their own domain, and produces verifiable bundles end-to-end.

Agent Native — drive day-to-day signing from any MCP agent. Once your instance is live, the bundled MCP server (kysigned-mcp) exposes the signing operations — create_envelope, check_envelope_status, list_envelopes, send_reminder, void_envelope — against your endpoint (configurable via KYSIGNED_ENDPOINT, defaults to kysigned.com). Configure it in any MCP-capable agent (Claude, Cursor, …):

{
  "kysigned": { "command": "npx", "args": ["kysigned-mcp"] }
}

Then ask: "Send the attached PDF to [email protected] for signature via kysigned."

Where does your instance live? (no domain needed on day 1)

kysigned deploys on run402 — the same pattern as any other repo hosted there. You don't need to register a domain to get started:

  • Default (no domain): your run402 project is reachable at a run402-issued subdomain like <your-project>.run402.com. Your dashboard, signing pages, and verify page all live there — no DNS to configure, no certificate to renew.
  • Bring your own domain (later): register a domain (e.g., lawyerxx.com), point its DNS at run402 per the project settings, and run402 takes over TLS + CDN + routing. Existing signing emails keep working; new envelopes use the new domain.
  • Static information pages included: /faq, /pricing, and /how-it-works are served from the same Run402 origin as the app, so the default clone path does not need a second marketing site.

The repo contains no hardcoded reference to a specific domain. References to kysigned.com here are illustrative — they refer to the canonical Kychee-operated instance.

Operator configuration

An operator is configured entirely through environment / secrets — no source edits:

Variable Purpose
KYSIGNED_ALLOWED_CREATORS comma-list of creator emails or exact-domain wildcards such as [email protected],*@example.org allowed to send
KYSIGNED_BILLING hosted to enable the prepaid-credit money-gate; unset = allowlist-gated
KYSIGNED_UNSUBSCRIBE_MAILTO optional — the List-Unsubscribe contact on outbound mail

run402 up generates and sets the Run402 substrate values:
RUN402_PROJECT_ID, RUN402_SERVICE_KEY, RUN402_ANON_KEY,
RUN402_PUBLIC_ORIGIN, RUN402_MAILBOX_FORWARD_TO_SIGN_ID,
RUN402_MAILBOX_FORWARD_TO_SIGN_ADDRESS, RUN402_MAILBOX_NOTIFICATIONS_ID,
and RUN402_MAILBOX_NOTIFICATIONS_ADDRESS. Migrations are declared in
run402.json and applied by the release.

Branding, home page & pricing

This repository ships generic, operator-free content: a placeholder home hero, no
pricing page and no "Pricing" nav item, a generic footer, and no hardcoded domain. Your
own identity is injected at build time through a single JSON environment variable, so you
never edit source to rebrand:

Variable Purpose
VITE_OPERATOR_CONFIG JSON string with your brand and home content. Fields: brandName, companyName, companyUrl, contactEmail, showPricing (adds the "Pricing" nav item), and home (hero, plus optional comparison and audiences marketing sections). See frontend/src/config/operator.ts for the full shape and the generic defaults.

With no VITE_OPERATOR_CONFIG set, the SPA renders the generic defaults (a fork advertises
you, not the upstream). To customise, pass the variable into the frontend build:

VITE_OPERATOR_CONFIG='{"brandName":"Acme Sign","companyName":"Acme, Inc.","showPricing":true}' \
  npm run build --prefix frontend

Static & legal pages

The passive pages in frontend/public/ (faq.html, how-it-works.html,
how-it-works-technical.html) are plain HTML you can edit freely. The legal pages
(terms.html, privacy.html, cookies.html, aup.html, dpa.html) ship as blank
placeholders
: replace them with your own before going live, since terms are specific to
each operator and jurisdiction. There is no pricing page in this repo; add one only if you
enable showPricing and want to link it.

Sender access control

kysigned ships with a built-in allowlist (allowed_senders) so you decide exactly who may create envelopes from your instance. Set KYSIGNED_ALLOWED_CREATORS to a comma-list of exact emails and exact-domain wildcards such as [email protected],*@example.org. Wildcards match only that domain, not subdomains. For local dev and tests the gate is off by default; run402 up fails fast when the required deployment secret is missing.

Trial signature documents

Want to kick the tires before sending a real document? The repo ships two deliberately-silly trial forms in docs/test-assets/: the ACME Approval Form 42-B (acme-approval.pdf) and the ACME Anvil Liability Waiver (acme-anvil-waiver.pdf), both carrying a bold TEST DOCUMENT — NOT LEGALLY BINDING watermark. Use either as the first document in a freshly-deployed instance to exercise the forward-to-sign flow end-to-end. Regenerate at any time:

node docs/test-assets/build-acme-approval.mjs
node docs/test-assets/build-acme-anvil-waiver.mjs

How signing works

  1. A signer receives an email from forward-to-sign@<your-domain> with the document attached.
  2. They forward it back and type "I sign this document" as the first line. No account, no app, no password.
  3. Their email provider's DKIM signature on that forward is the signature — only the provider can produce it, so no one else can forge a message in their name.
  4. kysigned verifies the DKIM signature, confirms the forwarded attachment is byte-identical to what was sent, timestamps the forwarded email, and records the signer.

When everyone has signed, every party receives one evidence bundle.

The evidence bundle & verification

The bundle is a single PDF holding the document, a signature page, and each signer's original DKIM-signed email — plus the public keys and timestamps needed to check them. It's a clean, unsigned PDF (no certificate, no seal — it opens with no warnings) carrying a printed SHA-256 fingerprint over its evidence set.

Anyone can verify a bundle at https://<your-domain>/verify (drag-and-drop, fully client-side) or with the bundled CLI:

node bin/verify-bundle.mjs <bundle.pdf>

Verification runs entirely on the verifier's own machine — offline, and even if your instance no longer exists. kysigned is not part of the trust set: the proof rests on the signers' email providers (DKIM), the public key archives, the timestamp authorities, and the math. See docs/trust-model.md for the full trust set and threat model.

Want to try both tools right now, with nothing signed yet? docs/test-assets/ ships ready-made samples: drop acme-anvil-waiver-signed-bundle.pdf (a genuine signed record) on /verify, and pair acme-anvil-waiver.pdf with that bundle or with acme-anvil-waiver-sign-request.pdf on /hashcheck to confirm an original document. The folder also holds a full set of tampered bundles that must FAIL, each breaking one named check. docs/test-assets/README.md lists the expected verdict for every file, and scripts/verification-tools/ replicates every check independently of the app.

Architecture

kysigned/
  src/
    api/            # envelope lifecycle, distribution, account + admin handlers
    api/signing/    # forward processing: DKIM verify, intent + attachment gates, reconciler
    bundle/         # evidence-bundle assembly + fingerprint + the verifier engine
    timestamp/      # RFC 3161 (TSA) + OpenTimestamps clients behind a TimestampProvider contract
    pdf/            # deterministic canonical PDF, cover page, signature page (pdf-lib)
    email/          # transport-agnostic EmailProvider + the HTML templates
    db/             # schema + data-access layer (runs over run402's HTTP SQL)
    integrations/   # run402 adapters (@run402/sdk email + HTTP SQL pool) + the route table
    functions/      # the run402 routed-HTTP entry + email-triggered durable work
  frontend/         # React + Vite + Tailwind: dashboard, signing review, /verify
  mcp/              # kysigned-mcp (agent surface)
  bin/              # verify-bundle.mjs (standalone CLI verifier)

Tests

# Backend unit suite
npm run test:all

# Frontend
cd frontend && npx vitest run

# MCP
cd mcp && npm test

# Deployed e2e — set BASE_URL to a running instance
BASE_URL=https://your-instance npm run test:e2e

Billing

Hosted (kysigned.com): $0.25 per envelope, flat, up to 20 signers. Creators buy prepaid credit packs by card — $5 buys 20 envelopes — and credits never expire. Stripe is the payment processor; card details never reach kysigned. The money-gate is config-gated (KYSIGNED_BILLING=hosted).

Self-hosted (this repo): you pay run402 for infrastructure (compute, email, DB). Gate who can create envelopes with the built-in allowed_senders allowlist, or wire your own billing using it as the authorization hook.

Built on run402

kysigned runs entirely on run402: routed-HTTP functions for the API, email-triggered durable work for signing replies and bounces, run402's HTTP SQL for the database, and run402 mailboxes for email.

All run402 I/O defaults to the @run402/sdk — the SDK owns the wire translation, so the app keeps no hand-maintained snake_case boundary adapters. The two raw-HTTP exceptions are documented and contained: the auth helpers call run402's /auth/v1/* endpoints directly (passing the project anon key), and the database pool wraps run402's HTTP SQL surface. Both map run402's lower_snake_case wire shape at the boundary.

License

Apache-2.0 — the whole repository, with no per-file exceptions. Every dependency is permissive (MIT/Apache-2.0); there is no GPL or other copyleft anywhere in the tree, so forking and commercial use are unrestricted. See LICENSES.md for the dependency inventory and LEGAL.md for signature-validity disclaimers and jurisdictional limitations.

Reviews (0)

No results found