Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 1da91c033c738ab74538d13d
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
AGENTS.md
# Sign
Sign is a free e-signature app, and a free alternative to DocuSign, Dropbox Sign and Adobe Acrobat Sign. It is an OpenApp in the OpenApps free apps store (https://free-apps.openapps.xyz/), owned by the OpenApps team.
## What it promises
- Free, with no limit on documents or signers, no ads and no paid tier. Never add a cap, an upsell or tracking.
- No sign-up for anyone. Every visitor is a guest account created in the browser.
- A record that holds up: signer consent, an audit trail (created, sent, opened, signed, voided) and the original document's SHA-256 fingerprint, all printed on the completion certificate of the signed PDF.
- AI assistants can send text documents for signature through the public API (`functions/api.ts`), documented in `public/llms.txt` and `public/openapi.json`. Keep both true whenever the API changes, and keep `public/index.md` (the landing page in plain markdown) in step with `index.html`.
## How it is built
- `index.html` is the static landing page that search engines and AI crawlers read. Keep its copy, FAQ and JSON-LD in sync with what the app does.
- `src/` is the React app. `/` mounts the start box and "Your documents" into the landing; `/new` writes a text document (`/new#title=...&text=...` prefills it, for assistants); `/d/<id>` is the owner's page (prepare, send, follow, download, make a copy, void); `/s/<docId>/<signerId>#t=<token>` is a signer's page. The owner can open any signer's page on their own device ("Sign on this device"), which is how people sign their own documents.
- The landing stays light: `src/Home.tsx` imports no data client or PDF library; `src/lib/actions.ts` (creating, copying, list statuses) loads on first use. Keep it that way.
- `src/lib/mydocs.ts` is the "Your documents" list with admin keys, kept in this browser only.
- Shared UI is in `src/ui.tsx` (dialog with exit animation, menu, toast, offline notice) on top of the kit in `public/kit.css`; `src/Skeleton.tsx` holds the loading shapes.
- PDFs are uploaded to Bounded storage (`docfiles/<id>/f/original`). Text documents store only their text: `src/lib/textpdf.ts` renders the same pages and signature fields from it everywhere, deterministically. Changing that renderer changes how existing text documents look, so keep it stable.
- `src/lib/finalpdf.ts` builds the signed PDF in the browser: the signers' values drawn on the original pages (honoring page rotation), then the certificate.
- `policy.json` holds the rules:
- Owners: the creator, or anyone presenting the admin key (`dockeys`, claimed through `docclaims`). The admin link carries the key in the URL fragment.
- Signers: a device joins as a signer (`signerjoins`) by presenting that signer's token (`signertokens`, claimed through `signerclaims`). A signing link carries the token in the fragment.
- Once a document is sent its text, signers and fields cannot change. A signature is written once and never changed, only by the joined signer, only with consent, only while the document is sent.
- A document is complete when every signer has a signature; nothing stores "completed".
- `dockeys` and `signertokens` are readable by owners and by the API's public principal (`@const.BOUNDED_PUBLIC_PRINCIPAL_API`), which checks owner keys for assistants.
- `functions/lib/doc.ts` is shared by the app and the API. `functions/lib/config.ts` holds the app id and the site URL used in links.
## Working on it
`npm install && npm run build` typechecks and builds `dist/`. Ship changes through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly.
Check a change end to end at 390px and 1440px: upload a PDF, add two signers, place fields (including on a rotated page, and from the keyboard), label a text field, send, sign from both links in separate browsers (one of them with "Sign on this device"), and download the signed PDF; make a copy; then the same through the API with a text document.
## Voice
Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.
Change history
Quality pass: phone signing, edit signers, copy to send again
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync