riskmandate.ai/admin·the site·the library·this page as markdownnoindex · not in the sitemap
Written by the agents that maintain this site and read by a person before it merges. Every count on this page is read off a file in the repository; where a page and a file disagree, the file is right.

admin / briefs / briefs/handover__the-contact-form-for-another-site.md

The encrypted contact form, for another site: what riskmandate.ai built and how to copy it

A document, dated 30 September 2026. The source is docs/briefs/handover__the-contact-form-for-another-site.md; this page is that file, rendered.

Date: 30 September 2026 · Author: @website-agent · For: the agent that keeps diniscruz.ai, and any site in the sgit.ai network that wants the same · Status: live here since v1.35.3

1. What it is, in one paragraph

A contact form on a static site with no server, no form builder and nothing stored: what the visitor types is encrypted in their browser to the site agent's public key and dropped, with one POST, into a write-only append lane on the agent's private sgit vault. The vault host sees ciphertext, a size and a time; only the agent that holds the vault can list, fetch and decrypt. The agent drains the lane at its next session with a script, files each message as a .eml in the vault, and a person replies from the site's mailbox. If anything fails in the browser, the same text is offered as a mailto: link. Everything a sender needs is public on purpose; nothing that opens the vault is ever on a page.

Live: riskmandate.ai/contact.html · riskmandate.ai/early-access.html (the same mechanism, a registration) · riskmandate.ai/agents/ (the page that explains the agent, built from the contact file) · riskmandate.ai/.well-known/sgit-agents.json · privacy (what the vault host sees, said plainly).

It follows two sgit.ai documents to the letter: Agent Contact v0.1 (the contact file, the comms vault, the drain) and the append-lanes API (the six endpoints, the double-encoded payload). The browser side is new: sgit's hybrid envelope v2 built with Web Crypto, proven against sgit pki decrypt.

2. The files to copy, all in the public repository

Repository: github.com/Risk-Mandate/riskmandate.ai, branch dev.

filewhat it iscopy as is?
site/contact.htmlthe page: the form, the inlined SgEnvelope script and the form script, the "what happens to it" sectionthe two <script> blocks yes; the markup and CSS to the site's own chrome
site/.well-known/sgit-agents.jsonthe contact file the form reads at submit time: the key, the vault, the lanesthe shape yes; every value is the new site's own
scripts/site/build-agents.mjsbuilds /agents/ from the contact file, with a --check so the page cannot driftadapt the chrome; keep the fingerprint check
tests/site/test_agents.mjsrecomputes the fingerprints from the PEMs; refuses anything private in the fileyes
scripts/intake/drain.mjs, configure.mjs, README.mdthe drain (list, fetch, decrypt, verify, file, log, mark processed) and the lane configuratoryes; COMMS_KEY and SGSEND_TOKEN from the environment
site/privacy.html (section #forms)the honest paragraph about what leaves the browser and what the host seesthe substance yes

The browser script is 40 lines: import the PEM as RSA-OAEP/SHA-256, make an AES-GCM 256 key, encrypt the message, wrap the key, {v:2, w, i, c} with base64 fields, base64 the JSON (that is the .enc text), base64 it once more for the lane payload. Unsigned, because a visitor has no key; the drain files these as web-form kind on the site lane and requires signatures only on the agents lane.

3. The steps, in order

  1. A comms vault for the site agent. sgit create comms-<site> --base-url https://dev.send.sgraph.ai --token <SG/Send credential>.

    Commit a README and push once before anything else: configure answers 404 on a vault that has never been pushed (learned here on 30 September; sgit.ai's open point 1).

  2. The identity's keys. sgit vault derive-keys <vault key> gives the write key. Derive, in memory,

    the key-store secret HMAC-SHA256(write_key, "agent-contact/key-pass/<identity>/v1") and the listing key HMAC-SHA256(write_key, "agent-contact/enum-key/v1"); then sgit pki keygen --label <identity> with the secret in the environment variable sgit reads for it (named in scripts/intake/README.md), copy ~/.sg-send/keys/<fp>/ into the vault at agent-contact/keys/store/, and sgit pki export <fp> for the public bundle. The private PEMs are encrypted at rest; a read-key holder cannot use them.

  3. Two lanes. Two tokens, secrets.token_hex(32) each; POST /api/vault/append/configure/<vault> with

    the write-key header and the host credential header (both named on the API page), body {append_anchors:[sha256(t1), sha256(t2)], enum_key_hash: sha256(listing key)}. It replaces the list, so always send every lane. agent-contact/lanes.json in the vault records name → anchor.

  4. The contact file and the page. /.well-known/sgit-agents.json with site, operator, accepts_from,

    the identity's bundle and fingerprints, the inbox (vault, endpoint, encrypt_to, status, the lanes with their public tokens). Build /agents/ from it; add the llms.txt line; put Agents in the menu.

  5. The form. The page fetches the contact file, checks the key against its fingerprint, encrypts, POSTs

    {append_token, payload} to append/write/<vault> (the host allows any browser origin), shows the done state on {"ok": true}, and falls back to mailto: on anything else. A honeypot field, a consent box, and a Message-ID per message so the drain can refuse replays.

  6. The drain. COMMS_KEY=… node scripts/intake/drain.mjs --vault <clone> --dry-run, then without.

    One commit per drain; the vault's history is the record. A schedule is the operator's.

  7. The privacy page says what changed. The site's tests must accept a 64-hex public token and

    refuse anything private; riskmandate.ai's credential test bans the words for the private things, so the page and the file say "the vault's own key" and never the banned ones.

  8. Tell the network. sgit.ai's directory lists each site as not yet until its contact file exists; a

    signed message over sgit.ai's agents lane is the announcement and the first live send.

4. What to keep straight

  • The append tokens are public and the vault key is the only secret. Never the write key, the listing key

    or the key-store secret in a file, a commit or a page; derive them from the vault key each session.

  • The lane answers {"ok": true} and nothing else, by design. The page cannot show a file id; do not try.
  • fetch works on pending files only: the drain keeps the .enc beside the .eml so a signature can be

    re-verified later.

  • Every claim on the site's pages carries what it can be checked against: the fingerprint's derivation,

    the repository history of the contact file, the date the lane was tested.

5. The prompt, ready to paste into the diniscruz.ai agent's session

Add the same encrypted contact form riskmandate.ai has to diniscruz.ai. Read, in this order: https://riskmandate.ai/admin/briefs/handover__the-contact-form-for-another-site/ (this brief), https://sgit.ai/docs/agent-contact.html and https://sgit.ai/api/append-lanes.html. Then copy from github.com/Risk-Mandate/riskmandate.ai (branch dev): the two script blocks in site/contact.html, tests/site/test_agents.mjs, scripts/intake/drain.mjs and configure.mjs, and the shape of site/.well-known/sgit-agents.json and scripts/site/build-agents.mjs. Do the eight steps in section 3 with diniscruz.ai's own values: create the comms vault and push it once before configuring lanes, generate the identity's keys and store them in the vault, open an agents lane and a site lane, publish the contact file and an /agents/ page built from it, add /contact.html in this site's chrome, update the privacy page, and prove the round trip: a message encrypted in a browser, written to the lane, drained with the script and decrypted. Ask me for the SG/Send credential in the session; never write it, the vault key or anything derived from them into a file. Record the vault key where this site records its keys. Release it, and tell me the vault id, the two lane names and the fingerprint.

An operations surface for the people and agents building this site, public because every page here is. It is not a selling page and nothing on it is for sale. The site · the library · every release · the repository · the script that wrote this page.