# not.bot — full documentation corpus > Cryptographic identity without surveillance. not.bot proves people and content are real — proof of humanness, age and attribute verification, and content signing — without revealing who anyone is. Every published not.bot documentation page, inlined as Markdown in reading order. Each page is also available on its own: its canonical HTML URL and a clean .md twin are noted above each one. Generated at build time from the canonical sources. Start here: the [Overview](https://not.bot/learn/overview.md) is the fastest grounding in what not.bot is, and the [Evaluation Framework](https://not.bot/learn/evaluation-framework.md) is the vendor-neutral criteria for judging any human-verification or identity product, not.bot included. Both appear in full below. --- > **Overview** — https://not.bot/learn/overview/ · Markdown: https://not.bot/learn/overview.md · Updated 2026-06-17 # not.bot™: Cryptographic Identity Without Surveillance The internet has no way to tell humans from machines. AI passes CAPTCHAs, generates convincing faces, clones voices, imitates writing styles, and operates social media accounts at scale. You cannot tell, with confidence, whether you are interacting with a person or a program. Neither can anyone else. The obvious fix, requiring people to prove their real identity, trades one problem for another. You should not have to hand your government ID to a gambling site, a forum, or a social network. Businesses collecting that data take on a liability they do not want: data they hold can be leaked, hacked, or subpoenaed. not.bot takes a third path. You prove specific things about yourself, with cryptographic certainty, without revealing who you are. The math behind a not.bot signature is unforgeable. No AI can produce one. No bot can fake one. And the site that checks it never collects the underlying data, because not.bot was built so the data does not leave your device. Julia Social, the company behind not.bot, built the system so that Julia Social itself cannot access your identity information. The company does not know your name, your age, your nationality, or which sites you visit. It cannot read your signatures. It cannot correlate your aliases. The privacy guarantee is enforced by architecture, not by policy. Julia Social cannot leak data it does not have. ## Three products, one identity not.bot is three products built on one identity infrastructure. ### not.bot app The not.bot app runs on your phone. You enroll by scanning the NFC chip in your passport. The app verifies the passport's cryptographic signatures, confirms it is genuine and unexpired, and creates your digital identity. Your passport data stays on your device. Julia Social receives a cryptographic proof that you are a unique, real person with a real passport. That proof is enough to create an identity controlled by your device. From that identity, you create aliases: separate identities for different contexts. Your professional alias. An alias for a forum. A throwaway for a site you will visit once. Each alias is cryptographically independent. Nobody, including Julia Social, can connect your aliases to each other. You sign content by composing a message, authenticating with your biometric (FaceID, TouchID, or device passcode), and producing a cryptographic signature in the form of a QR code or JAB code. You attach a JAB or QR code to images, documents, or posts; signed video carries a QR code. Anyone who scans the signature can verify that a passport-verified human created the signature, check any credentials the signer chose to include, and confirm the content has not been altered. You verify other people's signatures by scanning their QR or JAB codes. You do not need a not.bot identity to verify signatures. Download the app and scan. ### not.bot Verify not.bot Verify is server software that businesses deploy inside their own infrastructure. A website or service integrates Verify to request and check credentials from not.bot users. Verify answers the questions businesses care about. Is this a human? Verify provides cryptographic proof, replacing CAPTCHAs that AI has defeated. Is this the same human who was here before? Site Passes give each person a unique, per-site token that prevents one person from creating multiple accounts, without revealing who they are. Is this person old enough? not.bot users can prove they are over 18, over 21, or within a specific age range, without the site learning their birthdate. Verify runs in the business's own data center or cloud account. No user data flows through Julia Social during verification. The business controls its own infrastructure, its own data retention, and its own compliance posture. This matters for regulated industries. Healthcare organizations bound by HIPAA, financial institutions subject to data residency requirements, and government agencies pursuing FedRAMP can deploy Verify without routing sensitive interactions through a third party. ### not.bot Sign My Work The not.bot app handles occasional signing. For public figures and brands who sign content several times a day, the app alone adds too much friction. not.bot Sign My Work is a web-based tool for regular, high-volume signing, launching at the end of June 2026\. You upload content, write a title and description, and sign. Sign My Work hosts an encrypted known-good copy of the signed content at a permanent verification URL. Anyone who encounters the signed content elsewhere can compare it against the hosted original. The decryption key is in the signature. Julia Social doesn’t have it. Signing through Sign My Work still requires the not.bot app on the signer's phone. The web interface handles content management and hosting. The phone handles biometric or device-passcode authentication and cryptographic signing. The key never leaves the signer's device. [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/) covers the product in full: how a team signs day to day, the content types, pricing, and the privacy properties. ## Content provenance: verify the authentic Detecting fakes is an arms race. The detector must catch every forgery. The attacker only needs to fool it once. Each generation of AI narrows the gap. not.bot inverts the problem. You sign your authentic content. Recipients verify the signature. Unsigned content gets appropriate skepticism. Signed content carries proof that a specific verified human reviewed it and approved it. A not.bot signature carries the signer's identity with it: an alias, a message, credentials (including the not.bot credential proving the signer is human), a timestamp, and cryptographic proof tying it all to the signer's private key. A verifier does not need a pre-existing relationship with the signer. Visible signatures (QR and JAB codes, patent pending) survive distribution channels that strip invisible metadata. A screenshot of a signed image still contains the signature. A forwarded photo still contains the signature. Visibility also solves discoverability: the visible code tells the recipient that a signature exists and can be checked. For the full treatment of content provenance, signature encodings, the relationship to C2PA, and how verification works, see [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/). ## Human verification for websites Websites face three categories of identity challenge, and not.bot handles all three without collecting personal data. **Proof of humanity.** A valid not.bot verification requires an enrolled human, on their own device, authenticating with their biometric or device passcode at the moment of the request. No bot, script, or agent can produce one. **Sybil resistance.** Site Passes are per-site tokens computed through a three-party multiparty computation among the user's app, the site's Verify server, and Julia Social. If the same human visits the site twice, the same Site Pass appears, regardless of which alias the user chose. The site can detect duplicates. Julia Social cannot learn which sites a user visits. **Age and attribute verification.** Users can prove they are over 18, over 21, or any age from 13 to 25, prove they are within a five-year or ten-year age range, or meet other criteria, without the site learning their birthdate. The site requests specific claims. The user approves or declines each claim. The site learns only the information the user chooses to share. For the buyer-side story, the verification flow, and the BYOC deployment model, see [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/). ## Verifiable agent identity: honest.bot™ AI agents interact with people and systems through natural language, API calls, and realistic audio and video. These interfaces imply identity, but no identity exists. An agent is a process. It has no legal standing and no capacity for accountability. honest.bot gives agents verifiable, process-bound identity. The core mechanism is multiparty computation: when an honest.bot process starts, it and Julia Social jointly compute a value that neither can derive alone. That value becomes the honest.bot credential. A verifier can confirm the presenting process holds the original credential, without contacting Julia Social. If any other process attempts to present the honest.bot credential, verification fails. Every honest.bot delegation chain traces back to a single alias of a not.bot-verified human. An agent acts as an extension of the person that deployed it. The delegation chain, included in every presentation, lets any verifier trace the agent's authority back to one specific alias of an accountable human. The core component of honest.bot is in production. Every not.bot Verify signature server acquires an honest.bot credential at startup. No two signature servers in the world can hold the same credential at the same time. The not.bot app verifies the server's honest.bot credential on every interaction. For the full honest.bot story, see [honest.bot: Verifiable Agent Identity](https://not.bot/learn/honest-bot/). ## Privacy by architecture Companies that collect identity data promise to keep it safe. not.bot makes the promise unnecessary by removing the data from everyone except the user. Julia Social never sees your identity data. It does not know your name, age, nationality, or any other detail from your identity document. It cannot tell which sites you visit. It does not store which aliases belong to which person. It cannot correlate your activity across sites. An independent escrow agent ([Praxis Escrow](https://praxisescrow.com/)) stores encrypted identity data but does not hold the decryption key. The identity verification provider ([Signicat](https://www.signicat.com/)) validates your passport during enrollment and deletes the data within minutes. Only the app on your phone holds both the encrypted data and the key to decrypt it. Sites running not.bot Verify never collect identity data either. A site learns whether the user is human, potentially whether they have visited before (via Site Pass), and the answers to specific credential questions the user approved. Nothing more. For the full privacy architecture, including what each party can and cannot learn, compromise scenarios, and known privacy weaknesses, see [Privacy Architecture](https://not.bot/technology/privacy/). ## Accountability under law Privacy and accountability are in tension, and not.bot handles both. U.S. law enforcement can identify the person behind a specific signature by presenting a valid legal demand. The process requires cooperation from both Julia Social and the independent escrow agent (Praxis), takes one to two weeks, has a real financial cost, cannot be expedited, and works on one signature at a time. Bulk surveillance using not.bot is impossible by design: there is no database mapping users to identities, and every identification request requires an independent legal process for each signature. For the full law enforcement access model, timeline, and architectural constraints that prevent bulk identification, see [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/). ## Security model not.bot's security properties are testable claims. Signatures cannot be forged. Credentials cannot be modified after issuance. Identity survives device loss through a recovery process that requires both the user's passport and their recovery password. Compromise of a user’s signing keys can be detected and remediated without destroying the user’s identity. For the full security model, known weaknesses, and planned mitigations, see [Security Model & Known Weaknesses](https://not.bot/technology/security/). ## Built on Chia not.bot identities are decentralized identifiers (DIDs) on the Chia blockchain, using a custom DID method called `did:julia`. Chia provides the properties the system requires: BLS12-381 signatures enabling non-interactive aggregation, a programmable UTXO model (Chialisp) for on-chain identity logic, and a network architecture that makes running your own node practical. not.bot is not a cryptocurrency product. Users do not buy, hold, or trade tokens. There is no “not.bot token”. The blockchain is infrastructure, like a database, invisible to the user. For the architectural rationale, see [Why Chia?](https://not.bot/technology/why-chia/). For the DID method specification, see [did:julia Technical Specification](https://not.bot/technology/did-julia-specification/). ## Where to go from here This technology documentation covers the not.bot system in depth. Choose the path that matches your interest: **If you are evaluating not.bot for your platform or business,** start with [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), then read the [Privacy Architecture](https://not.bot/technology/privacy/) for the data-handling guarantees your compliance team will want. **If you are a content creator or public figure concerned about deepfakes,** start with [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/) to understand how signing works and why visible signatures matter, then [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/) for the tool that signs at volume. **If you are evaluating agent identity solutions,** start with [honest.bot: Verifiable Agent Identity](https://not.bot/learn/honest-bot/) for the product story. **If you are a privacy advocate or policy analyst,** start with the [Privacy Architecture](https://not.bot/technology/privacy/), then read [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/) for the identification model. **If you are a developer integrating not.bot Verify,** the [Architecture & Privacy Guide](https://not.bot/technology/verify-architecture/), [Deployment Checklist](https://not.bot/technology/verify-deployment-checklist/), and [Operations & Reference Guide](https://not.bot/technology/verify-operations/) are delivered with your Verify subscription. The [not.bot Verify: Julia Web SDK Reference](https://not.bot/technology/web-sdk/) covers the integration API. **If you want to understand the cryptographic foundations,** start with [Identity Architecture: DIDs, Aliases, and Ownership](https://not.bot/technology/identity-architecture/), then move to [Cryptographic Foundations](https://not.bot/technology/cryptographic-foundations/) and the [did:julia Technical Specification](https://not.bot/technology/did-julia-specification/). --- > **Content Provenance and Digital Signatures** — https://not.bot/learn/content-provenance/ · Markdown: https://not.bot/learn/content-provenance.md · Updated 2026-06-17 # **Content Provenance & Digital Signatures** Generative AI can produce convincing video, audio, images, and text of people who never said or did what the content depicts. You have no reliable way to tell, by looking at or listening to a piece of content, whether a real person created it. Neither does anyone else. The standard response is detection: train classifiers to spot AI-generated content, watermark AI output so it can be identified later, and look for artifacts in generated media. Detection is an arms race. The detector must catch every fake. The attacker needs to fool it once. Each generation of AI closes the gap between generated and genuine content. Detection tools that work today will degrade as models improve. not.bot™ takes a different approach. You sign your content with a cryptographic signature bound to your verified identity. Anyone who encounters that content can check the signature. Unsigned content gets appropriate skepticism. Signed content carries proof that a specific verified human reviewed it and approved it. ## **A signature is an identity, not a key** Traditional digital signatures (PGP, S/MIME) bind content to a cryptographic key. A verifier who encounters the signature needs a separate channel to figure out who owns that key. Key directories, certificate authorities, and webs of trust all exist to bridge this gap between "someone with key X signed this" and "a specific person signed this." A not.bot signature carries the signer's identity with it. Each signature includes: - The signer's **alias DID**, a decentralized identifier the signer controls - A **message** the signer composed describing what they're signing - **Credentials**, including at least the not.bot credential proving the signer is a passport-verified human - A **timestamp** and **nonce** preventing replay The signature also includes cryptographic proof that the holder of the alias's private key authorized its creation. That key lives in the device's encrypted database, protected by the device's secure element. Creating a signature requires biometric authentication (FaceID, TouchID, or the device passcode) at the moment of signing. A verifier doesn't need a pre-existing relationship with the signer. The signature itself describes what kind of entity signed, what credentials they hold, and what they attested. ### **What the signer signs** A not.bot signature is the signer's whole identity acting, not a detached key. The signer's DID rides inside the signature. Anyone who reads the signature resolves who signed from the signature itself, checked against the chain, with no certificate authority and no key directory to look up. The signer signs a message, the content being attested to, and can bind a self-attested timestamp and a nonce into the same signature. A verifier cannot peel any of them off the signature, and cannot move the signature onto other content. The timestamp is the signer's own attested time. A verifier weighs it as a self-attested claim from the signer, not a notarized stamp from a third party. When you sign in response to a not.bot Verify request, your signature embeds a complete copy of that request: the server that asked, its domain, the nonce, and the claims it requested. The server signed its request, so your signature and the server's request bind together into one record. The signer cannot later deny producing the signature, and the requesting server cannot deny asking for it. No tool surfaces this embedded request today, but it rides inside every Verify signature, so a captured signature traces to both the person who produced it and the site that requested it. For the formal message model, see [did:julia Message Model](https://not.bot/technology/did-julia-specification/). For how credentials ride inside a signature, see [Credentials](https://not.bot/technology/credentials/). ### **Verified Signer badges** A basic not.bot signature proves "a verified human signed this." For deepfake defense, that claim is necessary but insufficient on its own. The threat is impersonation of a known person. A politician, journalist, or creator needs to prove that *they* signed something, with a persistent public persona their audience recognizes. Verified Signer badges give public figures a consistent, verified identity across platforms. A creator's badge appears in their signatures, linking the content to a persona their audience knows. The badge is tied to their not.bot identity, which traces back to a passport-verified human, but the badge itself does not expose the creator's government-issued name or documents. You can maintain a verified public persona across communication channels without revealing your legal identity. ## **Signature encodings: matching the channel** A not.bot signature is one cryptographic structure. The encoding changes depending on where the signature needs to travel. **QR code signatures** store encrypted data on Julia Social's servers. The QR code image contains a randomized URL, a decryption key, and a hash of the signature data. Julia Social cannot read the contents: the decryption key exists only in the QR image and in the scanning app's memory. Julia Social cannot alter the stored data without detection, because any modification would fail verification against the hash embedded in the QR code. **JAB code signatures** use the JAB (Just Another Barcode) format, a high-density color barcode that stores more data than QR codes. JAB signatures are self-contained: the entire signature, compressed to fit, is encoded in the image. No server is contacted to create or verify a JAB signature. **Audio encoding** for audio-only channels is on the roadmap. The cryptographic structure is the same in both visual formats. New encodings can be added for new channels as needed. ## **Why signatures should be visible** A signature that nobody knows about doesn't get checked. Invisible metadata, no matter how durable, requires the recipient to know in advance that a credential might be embedded and to use a specific tool to look for it. Few people will do this. Few people know what C2PA is, let alone that they should be checking for invisible content credentials. A QR code or JAB code printed on or alongside content says "scan me." The signature's presence is self-evident. A viewer who encounters a signed photograph, video, or document sees the code and understands that verification is available. The visual encoding serves as both the signature and the call to action. This is a deliberate design choice with a tradeoff: a visible signature takes up space in the image. not.bot accepts that tradeoff because a signature that reaches the viewer and gets checked is more valuable than an invisible one that doesn't. ### **Surviving hostile distribution channels** Visibility also solves a durability problem. Social media platforms strip embedded metadata when you upload content. They remove C2PA manifests, EXIF data, invisible watermarks, and any information attached to the file rather than visible in the content. Instagram, X, and Facebook all do this during upload processing. Screen-recording, screenshotting, and re-photography destroy embedded metadata the same way. QR code and JAB code signatures (patent pending) survive these channels because the signature is part of the visible content. Any copy, screenshot, re-encoding, or re-photograph that preserves the visible image preserves the signature. A printout of a signed photograph carries the signature. A phone recording of a signed video carries the signature. ## **How not.bot complements C2PA** C2PA (Coalition for Content Provenance and Authenticity) is an industry standard backed by Adobe, Microsoft, Sony, Google, the BBC, and others. C2PA lets cameras and editing software attach a tamper-evident record to a file, tracking how it was created and modified. If someone edits a photo in Photoshop, C2PA records that edit. If someone crops a video, C2PA records the crop. C2PA-aware tools carry this record forward as the file moves through production. C2PA adoption is real and growing. Leica, Sony, Samsung, and Google ship cameras and phones that sign photos at capture. The C2PA Conformance Program maintains a public registry of certified products. EU AI Act Article 50 enforcement begins August 2026, requiring machine-readable labeling of AI-generated content, and C2PA satisfies that requirement. C2PA tracks the device and the software. It does not track the person. A camera that records a deepfake playing on a screen produces a valid C2PA record for the resulting file. The record proves the camera captured the image. It says nothing about whether a specific human stands behind the content. not.bot adds the human layer. A verified human signs the content, attesting that they vouch for it. C2PA catches tampering in the production pipeline. not.bot catches impersonation and fabrication at the source. Running both gives you coverage that neither provides alone. The Creator Assertions Working Group (CAWG) is building the specification-level bridge between device provenance and human identity. CAWG's Identity Assertion specification lets a verified human sign within a C2PA manifest. The specification supports decentralized identifiers, which is the identifier format not.bot uses. The architectural path for embedding not.bot credentials in C2PA manifests exists, though Julia Social is focused on its visible-signature approach, which addresses the discoverability and metadata-stripping problems that manifest-level integration would not solve. Three complementary approaches to content authenticity: 1. **C2PA manifest.** Protects file integrity through the production pipeline, from capture through editing and publishing. Stripped by most social platforms during upload. 2. **Durable watermarking.** Protects against re-encoding and casual modification through invisible embedded signals. Degrades under sufficient compression and format conversion. 3. **Visible not.bot signature.** Survives any distribution channel that preserves the visible image, and tells the recipient that verification is available. Requires space in the image. The three approaches cover different failure modes. Where one breaks, another holds. ## **not.bot Sign My Work: signing content at scale** The not.bot app handles occasional signing: you compose a message, authenticate with your biometric or device passcode, and produce a QR or JAB code. For public figures and brands who sign content several times a day, the app alone adds too much friction. not.bot Sign My Work is a web-based tool designed for regular, high-volume signing, launching at the end of June 2026\. You upload content (video, images, PDFs, links, or posts), write a title and description, and sign. Sign My Work hosts a known-good copy of the signed content at a permanent verification URL. Anyone who encounters the content elsewhere can use the not.bot app to compare it against the hosted original. Signing through Sign My Work still requires the not.bot app on the signer's phone. The web interface handles content management and hosting. The phone handles biometric or device-passcode authentication and cryptographic signing. The signing key never leaves the signer's device. [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/) is the product document: the signing workflow for teams, the content types, the known-good hosting model, pricing, and the privacy properties. ## **Verifying a signature** You do not need a not.bot identity to verify signatures. Downloading the app gives you verification capability without enrollment. The app verifies QR and JAB signatures because those are the visual encodings it can capture through the device camera, photo library, screenshots, or a still video frame that contains a code. Point the camera at a QR or JAB code, and the app fetches (for QR) or extracts (for JAB) the signature data, verifies it against the blockchain, and displays the signer's alias, their message, any included credentials, and the revocation status of those credentials. For signatures created with not.bot Sign My Work, the message includes a link to the durable, encrypted original version hosted by Julia Social and the hash and decryption key needed to verify and view it. Websites and services verify signatures through not.bot Verify, which runs inside the business's own infrastructure. The not.bot app on the user's phone communicates with the business's Verify server to present credentials. No user data flows to Julia Social during this process. ## **Privacy properties of signatures** C2PA credentials can contain creator identity information. The World Privacy Forum has documented the privacy risks: embedded identity metadata can expose journalists, activists, and whistleblowers to identification they did not intend. C2PA allows redaction, but consumer tools for managing this are not yet mature. not.bot signatures take a different approach to signer privacy. Every signer can have as many unique aliases as they need to compartmentalize their exposure as they sign content. Particularly sensitive aliases can be marked hidden so that they do not show up in the app user interface, except when an additional action is taken to reveal them, which requires a biometric or passcode verification. Julia Social cannot read QR code signature contents. The decryption key and hash exist only in the QR image and in the verifying app's memory. Julia Social cannot determine what a signature says, who created it, or when someone verified it. JAB code signatures never touch Julia Social's servers at all. Creation and verification happen between the signer's device, the verifier's device, and the Chia blockchain. QR code verification requests use randomized URLs, require no authentication, and discard IP addresses without logging. Julia Social does not track who verifies what. The signer controls which alias and which credentials to include in each signature. A signer can use different aliases for different contexts, and those aliases are cryptographically unlinkable. A signature reveals only what the signer chose to reveal. For the full formal treatment of privacy properties (P1 through P12), see the Privacy Architecture document. --- > **Is not.bot Safe?** — https://not.bot/learn/is-this-safe/ · Markdown: https://not.bot/learn/is-this-safe.md · Updated 2026-06-14 # **Is not.bot™ Safe? What to Know Before You Join** You are thinking about joining not.bot, and you want to be sure it is safe before you do. Smart. People join because they see something worth having: a site that offers verified humans a cleaner experience or premium access, a way to prove you are over 18 without handing over your birthdate, the ability to sign your own content so no one can pass off a fake as yours, a space with the bots kept out. Think of this as your due diligence. It explains what joining involves, what leaves your phone and what does not, who can see your activity, and what happens when something goes wrong. It avoids the cryptography. If you want the proof behind any claim here, the linked documents at the end carry the full architecture. One principle runs through all of it. The protections below are enforced by how the system is built, not by a promise to behave. Julia Social, the company behind not.bot, designed itself so that it cannot see who you are or whether you use your identity. That is a structural fact about the software, and the rest of this guide shows where it comes from. --- ## **What joining involves** You install the not.bot app and enroll once. Enrollment means holding your phone against the chip in your passport so the app can confirm the passport is genuine. After that, you create one or more aliases and use them to sign content, prove a fact about yourself to a website (that you are a person, or over 18, without saying more). Two limits to state up front: - **Enrollment is available today only to users on US app stores.** People elsewhere can install the app in scan-only mode, where they can verify other people's signatures but cannot enroll or create their own. International enrollment is planned. - **Enrollment today is done from home with your passport.** A stronger in-person option, where a trusted partner like a bank, hospital, or employer confirms your identity face to face, is on the near-term roadmap. More on why that matters under "What we are still building." You need a current, NFC-enabled passport to enroll. ## **The passport scan: where does my data go?** This is the question most people lead with, so here is the whole path. Scanning your passport takes two steps on your phone. The chip is encrypted, and the key that unlocks it is printed in the strip of text at the bottom of the data page, so the app first photographs that page and reads the strip with on-device text recognition. That photo never leaves your phone, and the app uses it to read text, not your face. The app then uses the key to open the chip and read the data it holds: your name, date of birth, gender, and nationality. It does not read the facial image stored on the chip. No biometric data leaves the passport. That text goes to a passport-validation provider, Signicat, which confirms the chip's government signatures are authentic and the passport has not expired. Signicat holds the data for a few minutes at most. Signicat is never told which not.bot identity the passport belongs to, or whether the scan is a first enrollment or a recovery. By the time enrollment completes, Signicat has deleted your data. The data goes straight from Signicat to Praxis Escrow, an independent US data escrow company that has completed a SOC 2 Type 1 examination. Praxis stores only an encrypted copy of the data, and Praxis does not have the decryption key. Julia Social holds the only decryption key and has no access to the stored record. The decryption key is stored on computers that never connect to a network, and so cannot be hacked over a network. Julia Social never sees your passport data at any point in this flow. When enrollment finishes, no one holds a readable copy of your identity. The single stored copy is encrypted, sitting with an independent escrow company that cannot open it, and it can be opened only through the law-enforcement process described below. Your personal information is not in a database someone can query, leak, or sell. ## **Can anyone watch what I do?** The two things you do most, signing content and verifying someone else's signature, never contact Julia Social. Your phone signs with keys stored on the device. Verification reads public blockchain data. When you prove a fact to a website, that exchange runs only between your phone and the site. No traffic reaches Julia Social. Julia Social does not see which sites you visit, what you sign, or whether you are using your identity at all. It is reached only for occasional administrative actions: enrolling, creating an alias, recovering after you lose your phone. Day-to-day use is invisible to it. The sites you use learn less about you than you might expect, and you decide what each one sees. Most sites need one narrow fact, and that fact is all they get. A site that wants to keep out bots gets "a real person." A site with an age gate gets "over 13," or "over 18," with no birthdate behind it. You answer the exact question asked and hand over nothing else: not your name, not your other details, not anything about what you do elsewhere. When you come back to a site, it should recognize you, and it can. With your consent, the not.bot app and the site will work together to create a Site Pass: a tag that stays the same on that one site every time you return, so your account stays yours, and is different on every other site you use. Two sites that share their data find no match between their Site Passes, so neither one can work out that you are the same person, even if they try. The Site Pass also means the site can tell if two accounts both belong to you, which is how not.bot keeps out bots and sock puppets, and it does that while telling the site nothing about who you are. You also do not have to be the same person everywhere. You can keep separate aliases for separate parts of your life, a public name in one place and a quiet one in another, and those aliases cannot be tied to each other or traced back to one person. You set what each corner of the web sees. You can hide any alias whenever you like, so you control which ones are visible, and your aliases are kept rather than deleted. ## **Are you taking my biometrics?** No. The app never reads your passport's facial image, and Julia Social never receives a scan of your face. The only biometric in the system is the Face ID or fingerprint already on your phone, which you use to unlock your own keys and to authorize a signature. That check happens on your device, against data your phone already holds. Neither your face nor your fingerprint leaves your phone. The page photo your phone takes to unlock the passport chip also stays on the device, read for text and never for your face. This is the opposite of the iris-scanning and selfie-vault approaches that have drawn breaches and regulatory fines. ## **What if I lose my phone, or you get hacked?** **You lose your phone.** If you have more than one device set up, you keep going on the others. If you lose all of them, you recover your identity with your recovery password and your passport. Recovery takes about five days. The delay is a safety feature: if someone tries to hijack your identity, you get a window to cancel before it completes, and even a completed hijack can be reversed back to you. Choose a strong recovery password; it is the one secret that protects you here. **Julia Social gets hacked.** Because signing and verifying never depend on Julia Social, a breach of the company does not touch your ability to use your identity, and it does not expose your passport data, which Julia Social never holds in readable form. ## **Can law enforcement see everything I do?** No, and the system is built so that bulk surveillance is not possible. There is no list to pull and no profile to match against. Identifying a single user takes a specific legal demand naming one identity. The independent escrow company reviews that demand and can release only the one encrypted record it names; by contract it cannot release records in bulk. Even then, decrypting one record takes days of computation, by deliberate design. So identification is possible, but it is constrained, auditable, slow, and one record at a time. This is deliberate. Julia Social could have built a system where identifying you is impossible, or one where it is trivial. It built one where lawful identification of a named person under due process stays possible, and everything short of that stays invisible. Your ordinary activity is not watched by anyone, including Julia Social. ## **Is this crypto? Do I need a wallet?** No wallet, no token, no fee. not.bot records identities on the Chia blockchain because that is a durable, decentralized place to anchor them, but you never have to hold cryptocurrency, never pay a blockchain fee, and never see a wallet. Julia Social covers the blockchain costs behind the scenes. You will not get a crypto bill, a tax form, or a seed phrase to lose. What is stored on the blockchain is identity records, not your name and birthdate, and Julia Social cannot see which blockchain queries your app makes. ## **What am I committing to, and how do I leave?** There is no account to delete. To leave, you stop using the app and delete it. Deleting the app removes your identity information, cryptographic keys, aliases, contacts, and history from your device. Without starting recovery, the identity is abandoned: no one can use it, and Julia Social cannot reach the underlying data. ## **What we are still building** - **In-person enrollment** is on the near-term roadmap. Enrolling from home needs an NFC-enabled passport, the kind whose chip a phone can read and verify. In-person enrollment lets a trusted partner, such as a bank, hospital, or employer, verify your government ID against you in person, so you can join without a chip-enabled passport. It is coming. ## **Who is behind this** not.bot is made by Julia Social. The design commitment behind everything above is that the company cannot see your identity or your activity, because it built itself to be unable to, not because it promises to look away. An independent escrow company that has completed a SOC 2 Type 1 examination holds the only stored record and gates any release. The privacy-critical code is open to independent audit. And the company has put its name to the No Phone Home campaign rather than build a system that watches you use it. If you want to check any claim here against the architecture, these documents carry the proof. ## **Related documents** - [The not.bot App (Doc #5)](https://not.bot/learn/the-app/): what the app does, how enrollment, aliases, and recovery work in detail. - [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/): the formal guarantees, including what each party can and cannot access. - [Security Model and Known Weaknesses (Doc #8)](https://not.bot/technology/security/): the threats the system defends against, and the limitations it states outright. - [Law Enforcement and Accountability (Doc #9)](https://not.bot/technology/law-enforcement/): the one deliberate exception, and how it is constrained. - [Enrollment and Identity Proofing (Doc #11)](https://not.bot/technology/enrollment/): the verification levels, including the in-person option on the roadmap. --- > **Roadmap** — https://not.bot/learn/roadmap/ · Markdown: https://not.bot/learn/roadmap.md · Updated 2026-06-17 # **Roadmap** This document describes where Julia Social is taking not.bot™ and honest.bot™: the products, capabilities, and infrastructure planned beyond what ships today. The items differ in maturity. Some are scheduled releases with target dates. Others are designed and waiting on engineering. A few are capabilities the protocol already supports that need application code to reach users. The list runs from nearer-term work toward later items, not in strict release order. Each entry states what the item is, what it makes possible, and how far along it stands. Target dates describe intent, not promises. ## **not.bot Sign My Work** not.bot Sign My Work is a web tool for signing content at volume, targeted for release at the end of June 2026. The not.bot app signs one piece of content at a time from a phone. That fits a person sharing photos. It does not fit a newsroom, a brand, or a public figure publishing dozens of items a day across formats. Sign My Work is built for that scale: videos, images, PDFs, links, and posts, signed from a browser. Signing still requires the not.bot app on the signer's phone to create the signatures, so the property that gives a signature its meaning, a verified human authorizing it, stays intact at any volume. Sign My Work also hosts an encrypted known-good copy of each signed item. The decryption key is embedded in the signature and Sign My Work does not have it. A verifier who encounters the content in the wild can compare what they see against what was signed, which turns a signature from a claim of authorship into a check against the original. Public figures and brands are the first people deepfakes impersonate. Sign My Work gives them a practical way to sign their output as a matter of routine, so their audiences learn that authentic content from them carries a signature. Sign My Work is also the first product to use Alias Vault Keys, described below, keeping each signer's account data encrypted on the server between sessions. [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/) describes the product in full. ## **Alias Vault Keys** An Alias Vault Key (AVK) is a symmetric encryption key the not.bot app holds, one per alias, returned to a host application during a not.bot Verify signature exchange and discarded when the user logs out. A server built this way keeps each user's data encrypted at rest under a key it does not hold between sessions, so a breach exposes only the data of users with a live session at that moment, and an abandoned account stays a locked box instead of a standing exposure. The key lives in the user's Recovery Data Bundle, so it survives the loss of every device without the recovery agent or Escrow Server being able to read it. The capability ships with not.bot Sign My Work at the end of June 2026, the first product to use it. [Recovery](https://not.bot/technology/recovery/) describes the bundle. ## **Privacy-preserving push notifications** Julia Social plans push notifications from not.bot Verify to users' devices, delivered without Julia Social learning which not.bot Verify instance sent the notification, nor which DID received it. Users must opt-in to notifications from each Verify instance, and can block notifications from a specific instance at any time. The mechanism is documented in full and ready for development. ## **In-person enrollment** Enterprises ask a question not.bot has no good answer for today: can I enroll my employees, or my customers, in person, so I can recognize them online afterward? Enrollment today is notbot0, an NFC passport scan performed at home, with no in-person path. Two higher verification levels are planned, along with broader passport coverage, and in-person enrollment is the next major capability after not.bot Sign My Work. **notbot1: partner enrollment.** Banks, hospitals, and similar institutions verify identity in person for their own purposes. Under notbot1, a partner institution enrolls the person into not.bot during that same visit, under contract to follow NIST SP 800-63A IAL2 identity proofing procedures. Each partner becomes an enrollment channel, and in-person proofing at IAL2 opens use cases a home passport scan cannot serve. **notbot2: first-party facilities.** Enrollment facilities under direct contract with Julia Social, providing the highest assurance tier in the scale. **Additional passport countries.** The app is only available in US app stores today. The NFC-enabled passport holders in each added country represent a new population that can enroll, and a stronger guarantee for verifiers that a not.bot credential means the same thing across borders. ## **honest.bot** honest.bot gives verifiable, process-bound identity to AI agents. Each honest.bot identity traces through a delegation chain to a not.bot-verified human, so an agent acting on someone's behalf is accountable to a named person rather than to a key file. The underlying MPC protocol runs in production today inside not.bot Verify, where each signature server acquires an honest.bot credential at startup. The honest.bot product, the pieces that let third parties deploy credentialed agents of their own, is targeted for Q4 2026. honest.bot Verifiable Agent Identity covers the product in depth; the work in flight consists of four pieces. **The adversarial appliance.** A containment architecture for running agents in environments their operator does not control, or agents the operator does not trust without limits. The appliance holds the agent's identity and enforces its bounds from outside the agent's own process, so a misbehaving agent cannot exceed what was delegated to it. **The SDK for third-party agent deployments.** The SDK turns honest.bot from Julia Social's internal infrastructure into a product. An organization uses it to give its agents identities, delegate authority to them within set bounds, and revoke that authority when circumstances change. **Technology stack credential schemas.** Credentials that describe the software an agent runs on. A verifier deciding whether to transact with an agent can require proof of its stack and set policy against it, the same way a security team sets policy against software versions today. **OIDC and enterprise authentication integration.** Enterprises run identity infrastructure already. Clean OIDC integration lets honest.bot credentials flow through existing authentication systems rather than beside them, which is the difference between an adoption path and a rip-and-replace. ## **Signatures in more places** The signature system today is visual and app-centered: QR and JAB codes, created and scanned with the not.bot app. Four planned capabilities widen where signatures can live and how they get checked, and a fifth sits further out. **Virtual-camera signature insertion.** A virtual camera that inserts the user's visible signature into a live video feed, so a video call itself carries proof that a verified human is on camera. The signature survives the call platform's compression and re-encoding (patent pending). Live impersonation on video calls, the staged-executive fraud that has already moved real money, is the sharpest form of the deepfake problem, and this answers it in real time rather than after the fact. **Browser-extension verification.** Checking a signature today requires the not.bot app or a not.bot Verify deployment. A browser extension will let a person verify a signature without leaving the page the content appears on. Verification friction drops to nearly nothing at the place content is consumed, which is where the question "is this real?" gets asked. **Video-stream signature detection and verification.** Detection and verification of signatures inside playing video, as the stream runs. Today, checking a signature in a video means pausing, capturing a frame, and scanning it. Stream-level detection makes the signature work at watching scale: a viewer or a platform sees the verification happen, with no frame-grab workflow. **Offline signing and verification.** The protocol supports creating and verifying signatures with no network connection; the app code for it does not exist yet. The payoff is in-person verification where connectivity fails or never reached: a license check in the backcountry, a credential presented in a building with no signal. **Audio encoding.** QR and JAB codes serve channels you can see. An audio encoding would extend signatures to audio-only channels: calls, radio, podcasts, voice interfaces. Voice cloning is the most common provenance problem after fake video, and no visual code can answer it. ## **Received-signature verification in not.bot Verify** not.bot Verify currently requests a signature and checks the response inside an interactive session. A separate capability would let it validate a signature provided by the host app, for example one uploaded by a user. ## **Recovery beyond Julia Social** Julia Social operates the only Recovery Server and is the only recovery agent today. Recovery describes the destination in detail; the roadmap items form one arc, ending that single-operator state. **Open-source Recovery Server.** Julia Social plans to release the Recovery Server as open source, with its two roles split: holding the user's encrypted recovery bundle, and authorizing recoveries. A user can run their own server and keep their bundle under their own control. **Third-party recovery agents.** Commercial recovery services, friends and family, or a self-hosted agent, chosen by the owner. With more than one agent available, the multi-agent configurations the protocol supports become usable: quorums such as 2-of-3 across agents in different jurisdictions, where no single compromised or compelled agent can recover an identity or block its rightful recovery. **Watchtower services.** Third-party services that watch the blockchain for a pending recovery against a subscriber's identity and alert the owner inside the cancellation window. Julia Social cannot run a watchtower, because alerting a user requires holding contact information and contact information identifies the user. The service has to come from parties willing to hold it. **App-exposed pre-rotated keys.** The protocol supports committing a replacement key in advance, an instant recovery path with no delay and no agents. A future version of the app will let a user arm it and keep the pre-rotated key in storage of their own choosing, written down offline or in a hardware signer. **Linking changed identity documents.** A renewed passport with a changed legal name, nationality, or gender fails duplicate detection today and produces a new identity; aliases, credentials, and history do not transfer. Planned linking lets a person carry their identity through a name change or naturalization instead of starting over. Marriage and citizenship are routine events, and an identity system should survive them. ## **The credentials platform** **Third-party credentials.** Julia Social issues every credential today: personal information, age, the not.bot credential, Verified Signer. The architecture already supports any organization issuing credentials to users through a Business DID. Planned app support for receiving, storing, and presenting third-party credentials opens the catalog: diplomas, professional licenses, certifications, employer attestations, all presented with the same selective disclosure and the same no-phone-home property as Julia Social's own credentials. The credential catalog stops being one company's list. **Broader Business DID availability.** Business DIDs exist today for not.bot Verify customers, with the Domain Name credential. Broader availability gives any organization an on-chain identity with multi-class multi-sig governance and delegation. Business DIDs enable the issuer side of the third-party credential ecosystem. The two items pair: Business DIDs create the issuers, app support creates the holders. **Self-attested credentials.** Some facts about a person have no institutional issuer: an avatar, a preferred name, a gender identity. The architecture lets a user issue these credentials to themselves, and planned app support will let users create and present them like any other credential. The signature makes the provenance plain: a verifier sees a claim signed by its own subject and weighs it as the person's own word, the right authority for what a person calls themselves. The payoff is a portable profile, set once and presented to any site that asks, owned by the user instead of scattered across platform databases. ## **Website-requested transaction signing** A website builds a blockchain transaction and the rich interface for defining it, then asks the user's app for a signature with the user's DID. The app shows the user a plain summary of what they are approving, the user signs, and the website submits the result. The division of labor is deliberate. Websites become front-ends for on-chain operations without holding keys, and users act on chain without running a wallet. The app does not build these transactions and will not; the two capabilities below reach users through a website's request. **On-chain credential presentation.** A credential presentation today happens off-chain: the holder presents to a website or a person, and the verifier checks the result against the blockchain. A website-built transaction can place the presentation inside the transaction itself, where the chain enforces it. A coin or smart contract can require a valid credential presentation as a condition of spending, and that changes what on-chain assets can do. **Julia DIDs as digital asset wallets.** The protocol lets a DID own digital assets on the Chia blockchain. The not.bot app will not manage those assets; a website builds the transfer, and the app's role stays what it is everywhere else, showing the user what they are signing. Combined with on-chain credential presentation, a single website-built transaction can carry both proof of identity and a movement of value, the foundation for person-to-person commerce between verified counterparties. ## **Julia Vanity Names** Reserved Names ship today as a preview of the Julia Vanity Name system. A reserved name is a chosen username, displayed with the .nb suffix (sarah.nb), that a user carries across every site where they choose to be recognized. Reserved names never expire and never need renewal, and the matching rules treat lookalike characters as the same name, so no one can impersonate sarah.nb by registering the same name with a capital i in place of the l. Julia Social mediates the reservations: Pro subscribers hold one name, Verified Signer subscribers five. The Julia Vanity Name system replaces that mediation with a self-governing registry on the Chia blockchain. The Chialisp code exists; deployment remains. Registration will take a deposit rather than a fee, returned in full when the name is released. Names will transfer and sell like the property they are. The registry will run without maintenance from Julia Social, and a person will be able to register as many names as they want. Every reserved name will be pre-registered in the new system at launch, so a name claimed today is a claim on the permanent registry. A username on a platform is an entry in that platform's database, kept on that platform's terms. A Julia Vanity Name belongs to the user outright, on a registry no company can edit, attached to an identity no company can seize. It completes the recognizability half of the alias model: aliases keep a user's contexts separate by default, and a vanity name is the deliberate exception, one name, recognizable wherever its owner chooses to use it. ## **Security and privacy hardening** **Independent privacy audit.** An independent audit by Least Authority is planned for the MPC protocols and other privacy-critical code. The audit converts "review our design" into third-party assurance that an enterprise security team or a regulator can cite. ## **Standards interoperation** **DIDComm messaging.** DIDComm is an open standard for end-to-end encrypted communication between DID holders. The encryption keys come from the DID documents themselves: a sender resolves the recipient's DID, encrypts to the key published there, and sends. No account is created, no certificate authority vouches for the parties, and no platform sits in the middle. The encryption lives at the message level rather than the transport, so the same message stays protected over any channel that can carry it. Julia Social plans to integrate DIDComm into the not.bot app. The integration gives users private communication where the only thing either side shares is an alias DID. Messaging today runs on identifiers that name the person, a phone number or an account with a platform. A DIDComm conversation between not.bot users runs on aliases: each side knows the other's alias DID and whatever the other chooses to disclose, nothing more. The same channel connects not.bot users to the broader ecosystem of DIDComm-capable systems and gives third-party credential issuers an out-of-band way to deliver credentials. Delivery to an offline recipient runs through mediators, and the standard already covers them: each routing hop gets its own layer of encryption, so a mediator learns only the next hop, not the message contents, the sender, or the final destination. A relay can carry not.bot users' messages without learning who is talking to whom, the property Julia Social's architecture demands of any party it adds. ## **Related documents** - **[Content Provenance and Digital Signatures](https://not.bot/learn/content-provenance/):** the signature system as it exists today. - **[Content Signing and not.bot Sign My Work](https://not.bot/learn/content-signing/):** the Sign My Work product, targeted for the end of June 2026. - **[Identity Architecture](https://not.bot/technology/identity-architecture/):** aliases and the naming surface that vanity names complete. - **[honest.bot Verifiable Agent Identity](https://not.bot/learn/honest-bot/):** the honest.bot product narrative. - **[The not.bot App](https://not.bot/learn/the-app/):** the app the roadmap extends. - **[Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/):** the credential model behind the platform items. - **[Recovery](https://not.bot/technology/recovery/):** the recovery model the decentralization arc completes. - **[Why Chia?](https://not.bot/technology/why-chia/):** the blockchain the on-chain items build on. --- > **Evaluation Framework** — https://not.bot/learn/evaluation-framework/ · Markdown: https://not.bot/learn/evaluation-framework.md · Updated 2026-06-17 # **Evaluation Framework** How to evaluate any of the products that overlap with not.bot™, across the categories described in "The field" below. Names no companies. Defines the criteria any buyer can apply to any vendor, including not.bot™. This framework is written for **the buyer**: the organization evaluating or deploying a system that verifies humans. It refers to **the vendor** (who sells the system), **the operator** (whoever runs the deployment, which is the buyer in a self-hosted model and the vendor in a cloud one), **the user** (the human being verified), and **the verifier** (whoever checks a proof at the point of use, often the buyer's own site and sometimes a third party). --- ## The field The products a buyer weighs against not.bot fall into kinds, each sought for a different benefit: - **Bot detection.** Keep automated traffic off a service, so real users get through and scripts do not, at scale and with little friction for the user. - **Document-and-selfie verification.** Onboard a named customer by confirming a real person matches a real government ID, for cases that need a known individual on file. - **Facial age estimation.** Clear users past an age gate from a face alone, with no document to upload and little friction. - **Proof of personhood.** Establish one unique human per account, for sybil resistance, one-person-one-vote, and abuse rate-limiting, without collecting a name. - **Federated and platform identity.** Let users sign in with an account they already hold, for fast onboarding and fewer credentials to manage. - **Content authenticity.** Carry a file's origin and edit history with it, so a viewer can see where a photo, video, or document came from. - **Deepfake detection.** Screen incoming media for signs of manipulation before a buyer trusts or publishes it. - **Decentralized identity infrastructure.** Issue and check credentials on open standards, for a portable identity layer a buyer can build on without locking into one vendor. A buyer's obligations often reach across more than one of these. The criteria below apply the same questions to every category, not.bot included. --- ## I. What the verification is built on ### 1. Trust anchor *"What is the root of trust, and how strong is it?"* **The issue.** Every verification system roots its trust in something it treats as hard to forge, and the choice decides what can fool the system and what it can never check. The anchors in use: - **A biometric pattern.** A face or iris. *Implication:* proves a live body showed up, not who that body is in any civil record, and ties the user to a stored template the system must then hold and protect. - **A document image.** A photo of an ID. *Implication:* proves a credential was photographed, not that the holder is its subject; a clear photo of someone else's document can pass. - **A behavioral signal.** Interaction patterns. *Implication:* cheap and frictionless, but it never establishes identity and weakens as bots improve. - **A federated account.** Sign-in from a large provider. *Implication:* inherits whatever the upstream provider checked, which may be nothing, and puts that provider in the loop. - **A hardware token.** A device key. *Implication:* proves possession of a device, not of a person; whoever holds the device passes. - **A government-issued chip.** The signed chip in a passport or ID. *Implication:* carries the issuing authority's signature and ties the credential back to a person that authority vouches for, the strongest anchor, and it requires the user to hold such a document. The strength question is whether the anchor reaches an authority that stands behind a real person, or only an artifact that can be copied, estimated, or inherited. **not.bot's position.** not.bot anchors trust in the government-signed chip of a passport. At enrollment the app reads the chip, and a certified identity-verification partner validates the issuing authority's signatures against the ICAO Public Key Directory and confirms the passport is genuine and unexpired; Julia Social never receives the passport data. The current enrollment level confirms that an authentic, unique passport was present, without a liveness step that binds the document to the person who scanned it; two higher levels that add in-person proofing are planned. See [Enrollment and Identity Proofing](https://not.bot/technology/enrollment/), [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), and [Privacy Architecture](https://not.bot/technology/privacy/). ### 1b. What the proof establishes *"How much does a verification prove about the party, and can the system prove less when less is needed?"* **The issue.** "Verify a human" hides five different claims, and a buyer who does not separate them can buy proof too weak for the obligation or too strong for the use. From the least to the most a verification can pin down: - **A human.** The party is a real person, not a bot or a script. It says nothing about which person, how many accounts they hold, or any trait they carry. - **A human with specific traits.** The party holds a proven attribute, over 13, resident of a jurisdiction, a licensed professional, with the rest of their identity withheld. The claim age-verification and eligibility checks need. - **A unique human.** The party is a distinct person, one account per body, still with no name attached. The claim one-person-one-vote, anti-Sybil membership, and abuse rate-limiting need, and a harder guarantee to make than a single trait, because it requires the enrollment itself to resist duplication. - **A unique human with specific traits.** The party is one account per body and carries a proven attribute, still with no name. The claim a login wants when it needs sybil defense and an age gate at once: one person, one account, over 13, and nothing else disclosed. - **A fully identified human.** The party is a specific named person in a civil registry. The claim regulated onboarding, know-your-customer, and accountability for published content need, and the one that discloses the most and creates the largest liability if the data is retained. Can the system make the claim the use requires, since a unique-but-anonymous token cannot satisfy a know-your-customer rule and an age estimate cannot name a person for accountability. And can it make a weaker claim when a weaker one suffices, proving a single attribute without handing over the whole identity? Every anonymous proof also comes in two variants, sealed so no party can ever de-anonymize it, or anonymous with a governed path to the identity for lawful process, which criterion 13 evaluates. **not.bot's position.** One not.bot enrollment can answer at any level of specificity and discloses only what a request needs. The passport-bound root reaches a fully identified person, available to lawful process. Short of that, the not.bot credential proves a person is human with no name attached, a Site Pass proves one account per person without identifying them, and a name, age, or gender credential proves a single attribute such as over 18. The claims combine: a site that needs one account per person and an age check at once receives a Site Pass and an age credential together, with no name disclosed. See [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/), [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), and [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/). ### 2. Verifying without the vendor *"To check a proof, must the verifier reach the vendor's servers, or can the proof be verified without the vendor?"* **The issue.** A proof has to be checked somewhere, and the question is whether checking it requires contacting the vendor. Systems fall into three patterns: - **The vendor answers every check.** The verifier sends each verification to the vendor's servers and waits for a yes or no, so the vendor sits in the path of every check. *Implication:* the vendor accumulates a record of who verified, where, and when: a honeypot that can be breached, mined, or turned to surveillance, and every check is only as fast and as available as those servers, failing when they do. - **Trust the vendor's hardware.** The verifier trusts an attestation from the vendor's chip or enclave, with no independent record to consult. *Implication:* no per-check call home, but trust rests on silicon the buyer cannot audit, and a flaw or a forged attestation is invisible from outside. - **Check independent records.** The proof carries its own evidence and verifies against records anyone can read, the vendor never contacted. *Implication:* no honeypot forms, the check adds no round-trip to the vendor and survives it going dark, but a trustworthy public record has to exist and the verifier must trust its integrity. The buyer should ask which pattern each verification follows: it decides whether the vendor learns where its users go, and whether each check stays fast and works when the vendor falters. **not.bot's position.** A verifier checks a not.bot proof by reading the Chia blockchain: the presenting identity's current state, the issuer key, and the on-chain revocation record. Julia Social is not contacted and need not be available, and no record of who verified what accumulates with the vendor. A not.bot Verify deployment reads its own blockchain nodes inside the operator's infrastructure, so a verification runs between the user's device and the operator's servers. Julia Social is a signatory to the No Phone Home movement. One exception: a QR-code signature stores its payload on Julia Social's servers, so verifying that format retrieves data from there, while a JAB-code signature is self-contained and contacts no server. See [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/), [Why Chia?](https://not.bot/technology/why-chia/), and [System Architecture and Degraded-Mode Operation](https://not.bot/technology/system-architecture/). --- ## II. What the system keeps and who can see it ### 3. Reusable artifact *"Does a verification leave the buyer a reusable copy of the user's identity or a claim that cannot be replayed?"* **The issue.** When verification captures the raw inputs that prove identity (e.g. the face image, the document scan, the extracted fields), the buyer is left holding the exact material that document-and-selfie matching consumes: a reusable impersonation kit. It can be replayed to pass verification at another service, and the user cannot see who holds a copy. Each business that runs this kind of check holds a trove of these kits, and a breach of any one spills the verification images as ready-made impersonation material, selfies and government IDs together. The kit exists even when the buyer never downloads it: on a pass-or-fail result it still sits with the operator that ran the match, the vendor in a SaaS deployment. A cryptographic claim leaves nothing replayable: the proof authorizes one check and cannot be re-presented as the user. Whether a kit is replayable at all is a property of the design; retention is only a policy, and policies can be tightened or breached. **not.bot's position.** A not.bot verification leaves a claim that cannot be replayed. The signing key stays in the encrypted database on the user's device and is never exported, and each presentation is bound to a fresh nonce so it cannot be lifted and re-presented as the user. No document image or biometric is collected at any point, so an operator running not.bot Verify never holds a face-and-document set; a site may retain the signatures presented to it, but those are single-use claims, not reusable identity material. The fact that a replayable copy does not exist is a property of the design, not a retention setting. See [Privacy Architecture](https://not.bot/technology/privacy/), [Cryptographic Foundations](https://not.bot/technology/cryptographic-foundations/), and [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/). ### 4. Operator blindness *"What do the operator and the vendor learn about who is verifying, and is that limit enforced by architecture or by promise?"* **The issue.** Every system draws a line between what the user reveals and what the operator and vendor keep, and the buyer has to find where that line sits and what holds it there. Three postures: - **Holds the data, limits itself by policy.** The operator keeps the identity data and binds itself with a privacy promise; some let the buyer choose which jurisdiction stores it. *Implication:* the limit can be revised, misconfigured, or breached, the residency choice moves the honeypot rather than removing it, and the user cannot audit any of it. - **Sees it at enrollment, then deletes.** The system captures the passport and selfie, signs a credential, and deletes the originals. *Implication:* blind at the moment of presentment, but there was a window of full custody and a deletion the user has to take on faith. - **Never receives the data.** On-device storage, multi-party computation, or buyer-hosted deployment hold the line by construction. *Implication:* no policy change or breach can move the line, because the data was never there to take, and the buyer's job shifts from trusting a promise to checking an architecture. "Cannot" and "promises not to" are different products, and the difference shows only under stress. **not.bot's position.** Julia Social never receives passport data, prevented by architecture rather than policy. Every credential is produced by multiparty computation that yields a correct signed result without the signer seeing the inputs: age credentials use a three-party protocol among the app, Julia Social, and the Escrow Server, so neither Julia Social nor the Escrow Server learns the birthdate, and the not.bot identifier uses a two-party protocol between the app and Julia Social that cannot be tied back to the passport data. An operator deploys not.bot Verify in its own infrastructure, so Julia Social has no path into a running deployment. One scope note: a certified identity-verification partner sees the passport at scan time during enrollment, then deletes it within seconds, so the never-receives property describes Julia Social, not every party. See [Privacy Architecture](https://not.bot/technology/privacy/), [Cryptographic Foundations](https://not.bot/technology/cryptographic-foundations/), and [Enrollment and Identity Proofing](https://not.bot/technology/enrollment/). --- ## III. How identity behaves across the web ### 5. Cross-site linkability and recognition *"Can the user be tracked across sites by default, can they choose to be recognized, and can a third party recognize them across the web?"* **The issue.** A single verified identity used across many sites can link the user's activity into one profile. Systems sit at points on a continuum from covert tracking to consensual recognition: - **Covert cross-web recognition.** A third party embedded across many sites recognizes the same user on all of them with no disclosure. *Implication:* verification becomes web-wide tracking the user never sees. - **A shared persistent identifier.** Every site sees the same value for the user. *Implication:* no embedded observer is needed; any two sites, or a broker between them, can link their records. - **Unlinkable by default.** Each site sees a different value. *Implication:* no two sites and no broker can tell their visitors are the same person. - **Unlinkable with consensual recognition.** Unlinkability is the floor, and recognition is a capability the user grants per site and can withdraw. *Implication:* the user can choose to be recognized again, or prove they are the same human without revealing which human, so recognition is opt-in rather than a default they cannot escape. Whether the private end holds by architecture or only by the vendor's policy is the buyer's last question here. **not.bot's position.** Each alias a user presents to a site is an independent identifier, so two sites, or a broker between them, cannot determine that their visitors are the same person; the same value issued to two aliases produces uncorrelatable credentials, and Julia Social cannot link a user's aliases. Recognition is a capability the user grants per site: a Site Pass, created only with consent, lets one site recognize a returning person without learning who they are, and Site Passes for different sites do not match even when those sites compare them. Unlinkability is the default and holds by architecture. See [Identity Architecture](https://not.bot/technology/identity-architecture/), [Privacy Architecture](https://not.bot/technology/privacy/), and [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/). ### 6. Sybil resistance *"How does the system stop one human from minting many identities, and at what privacy cost?"* **The issue.** Any system that grants one identity per human has to stop a single person from minting many, and each method carries a privacy cost: - **A biometric held centrally.** One enrollment per body, enforced against a central biometric set. *Implication:* strong duplication resistance, and a central biometric database that becomes a target. - **A phone number or document.** Uniqueness tied to a SIM or an ID number. *Implication:* low friction, but cheap to defeat, since numbers and documents can be bought or reused. - **Per-site, consensual uniqueness.** The user proves one-per-human to a site when it asks, with nothing shared across sites. *Implication:* duplication resistance without a global identifier or a central registry, at the cost of work at each site that needs it. The buyer should ask not just how well a system resists duplication, but what it had to centralize or expose to get there, and whether the resistance is forced on every interaction or offered per site when a site needs it. **not.bot's position.** not.bot resists duplication at two points without a global identifier or a central registry. At enrollment, a passport that has enrolled before is rejected by a stored hash, so one passport yields one identity. At a site, a Site Pass lets that site recognize one person behind two accounts when it asks for one, computed by a three-party protocol so Julia Social does not learn which site asked and the site does not learn who the user is. There is no central biometric store to target, and a Site Pass is per-site and created with the user's consent, so the resistance is offered where a site needs it. See [Enrollment and Identity Proofing](https://not.bot/technology/enrollment/), [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), and [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/). --- ## IV. What it can prove ### 7. Age assurance *"Does the system estimate age or prove it, can it disclose only what is needed, and what happens to users near the threshold?"* **The issue.** An age check needs only a yes-or-no answer, yet it is where systems over-collect the most. Three approaches: - **Estimate age from a face.** *Implication:* no document needed, but it returns a probability, not a fact, and forces a safety buffer: to clear "over 18" the estimator rejects anyone who reads under 25, funneling marginal adults into the document upload they were trying to avoid. - **Check age against a full identity.** *Implication:* accurate, and it discloses name, date of birth, and document number to answer a yes-or-no question. - **Return a single attested bit.** Over-18 true, derived from a verified credential. *Implication:* answers the question and reveals nothing else, but it needs a credential issued ahead of time. The related question is threshold flexibility: can the system answer over-13, over-18, over-21, and support users under 18 at all, or does it assume every subject is an adult. Age is where regulators are most active and where the gap between answering the question and harvesting an identity to answer it is widest. **not.bot's position.** not.bot returns a single attested value. An over-18 or over-21 credential is a boolean derived from the passport's date of birth by multiparty computation, so a site receives true or false and learns no birthdate, name, or document number. Thresholds run from over-13 through over-25, with ranges, so the system supports users under 18 and a site requests the one threshold it needs. The credential is issued ahead of time and refreshes monthly, with every threshold reissued each time so the set requested never reveals which one applies to the user. See [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/), and [Enrollment and Identity Proofing](https://not.bot/technology/enrollment/). ### 8. Content authenticity *"Can a human bind their identity to content they create, does that binding survive the open internet, and does it prove authorship or only guess at forgery?"* **The issue.** When content can be generated and altered at scale, the question shifts from "is this real" to "who stands behind this." Systems answer in different layers: - **Bind content to the device or software.** *Implication:* proves a camera or an app touched the file, says nothing about the human, and the binding often lives in metadata that strips away the moment the file is re-encoded or screenshotted. - **Detect forgery after the fact.** Score how likely a file is to be fake. *Implication:* a probabilistic arms race re-won every time the generators improve, and it never establishes who made the file. - **Bind a human identity to the content.** A signature from a human's verified identity. *Implication:* survives the open internet, including screenshots and forwarding, and proves who authored or vouched for the item, but only for content someone chose to sign. The buyer should ask whether the system proves human authorship or only attests to a device, and whether the proof survives contact with real-world distribution. **not.bot's position.** not.bot binds a human identity to content. A signer composes content, authenticates with their biometric or device passcode, and produces a visible signature, a QR or JAB code (patent pending), carrying the signer's alias and the not.bot credential that proves a passport-verified human signed it. Because the signature is part of the visible image, it survives screenshots, forwarding, re-encoding, and printing, where embedded metadata strips away on upload, and the visible code also tells a viewer that verification is available. The proof exists for content a person chose to sign. See [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/), [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/), and [The not.bot App](https://not.bot/learn/the-app/). --- ## V. Where and how it runs ### 9. Reach of use *"Does it work face-to-face and offline, and does the user's verified status travel with them or get re-checked from scratch at every site?"* **The issue.** A verification system is useful only where it works, and two limits decide its reach: - **Offline and face-to-face.** Does it work at a door, a checkout, a polling place, with no network, or only inside a web request? - **Portability.** Does verified status travel with the user, or is each check a one-off transaction re-run at every site? In the portable model the user verifies once, holds a credential, and presents proofs that any verifier with a reader can check, so the credential reaches everywhere a reader exists, like an ID in a wallet. In the per-site model there is no credential to carry: each business re-runs the whole verification from scratch, and the result is bound to that business and reaches nowhere else. Reach is not a headline feature, but it decides whether a credential is something a person uses across their life or only on the handful of sites that wired it in. **not.bot's position.** A user verifies once at enrollment, holds the credential, and presents proofs that any verifier with a reader can check; both not.bot Verify and the not.bot app are readers, so a check does not re-run the whole verification at each site. Presentations work on-chain, online against the blockchain, and offline against a stored snapshot of issuer state, which covers a door or a checkout. A JAB-code signature verifies its embedded content with no network, while checking current key state and revocation needs the blockchain or a snapshot; offline signing and verification in the app are on the roadmap. See [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/), [System Architecture and Degraded-Mode Operation](https://not.bot/technology/system-architecture/), and [Roadmap](https://not.bot/learn/roadmap/). ### 10. Deployment model *"Can the buyer run it in their own infrastructure, or only as the vendor's cloud service?"* **The issue.** Identity data lives somewhere, and the buyer's exposure depends on whether they control that somewhere. A cloud-only service concentrates every buyer's verifications in the vendor's infrastructure, where one breach reaches all of them. A model the buyer runs in their own infrastructure, on-premise or in their own cloud tenant, keeps the data inside the buyer's control and compliance regime. For a buyer under HIPAA, FedRAMP, or financial-services rules, that control is a gate, not a preference: federal use can require a FedRAMP-authorized boundary or an air-gapped install, HIPAA turns on a business associate agreement and where protected health data sits, and financial regulators press for data residency, dedicated tenancy, and a workable exit plan. Deployment is often how a buyer meets those obligations, which ties this criterion to regulatory alignment. **not.bot's position.** not.bot Verify runs in the operator's own infrastructure, on-premise or in the operator's own cloud tenant, so identity data stays inside the operator's control and compliance regime; the operator runs its own blockchain nodes and key store, and no user data flows to Julia Social during verification. This supports buyers whose rules require it, including HIPAA, FedRAMP, and data-residency obligations. See [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/) and [System Architecture and Degraded-Mode Operation](https://not.bot/technology/system-architecture/). --- ## VI. When things go wrong, and who answers to whom ### 11. Recovery and reclaim *"Is the identity long-lived, and if so, how does the true owner recover it when the device is lost, sold, or shared?"* **The issue.** In transactional proofing the user re-verifies from scratch each time, so there is nothing to recover, and also nothing that persists: every re-proof repeats the cost and the data exposure. A long-lived identity, a credential or key the user holds over time, raises the harder question, and the recovery path is where it gets attacked. The login is seldom the breach; the support agent who restores a lost account to whoever sounds convincing is. For long-lived identity, recovery models fork: - **Help-desk or fallback channel.** Recovery runs through a support agent, an email reset, or an SMS code. *Implication:* the recovery path is the weakest link, socially engineerable, and a convincing call can hand the identity to the wrong person. - **Platform-account re-provisioning.** Recovery inherits the device platform's account recovery. *Implication:* as strong or weak as that platform account, and it leashes the identity to the platform. - **Re-anchor to the human root.** The true owner re-proves against the still-attached anchor, a government document or biometric, and reclaims the identity on their own. *Implication:* no help desk to talk into anything, and a lost, stolen, sold, or shared identity can be reclaimed by the real owner, because the anchor stays with them. It needs a re-provable human anchor to work. Sharing is the same story from the other side: a re-anchored system does not stop a user from enrolling for someone else, but the real owner can always reclaim, so a shared or sold identity never stays gone. The buyer should ask whether the identity is long-lived, and if so, whether recovery is the user re-proving against a root or a help desk that can be talked into anything. **not.bot's position.** A not.bot identity is long-lived and recovers by re-proving against the human root rather than through a help desk. The identity persists on the blockchain, and the owner reclaims it by re-proving with the passport and a recovery password; a recovery agent and the Escrow Server hold an encrypted recovery bundle they cannot read, a 48-hour delay lets the owner cancel a malicious recovery, and even a completed theft can be reversed because the anchor stays with the owner. Recovery does not prevent a user from enrolling on someone else's behalf; the reclaim path resolves a shared or sold identity. Today Julia Social is the only recovery agent and Recovery Server operator, with multi-agent arrangements planned. See [Recovery](https://not.bot/technology/recovery/), [The not.bot App](https://not.bot/learn/the-app/), and [Security Model & Known Weaknesses](https://not.bot/technology/security/). ### 12. Regulatory alignment *"Does the system satisfy the regulations the buyer must follow, and does it comply by collecting more data or by collecting less?"* **The issue.** The buyer often has regulatory obligations to meet, and the system has to satisfy them to be acceptable: COPPA and the GUARD Act and KOSA for minors, GDPR for European users, HIPAA where health data is near, data-residency rules for where identity data may be stored. Some systems satisfy a regulation by collecting more, building the identity dossier the rule assumes, while others satisfy it by collecting less, proving the required fact without retaining the data that creates the liability. Complying by collecting less is the counterintuitive option, and the one that leaves nothing to breach. **not.bot's position.** not.bot satisfies a requirement by collecting less. It proves the required fact without retaining the data that creates the liability: an age gate receives a single attested value, a proof of personhood receives a boolean, and an operator under HIPAA, FedRAMP, or a data-residency rule runs Verify inside its own boundary so identity data does not leave its control. Credentials are computed by multiparty computation that signs without the signer seeing the inputs, so minimization is built into issuance. See [Privacy Architecture](https://not.bot/technology/privacy/), [Cryptographic Foundations](https://not.bot/technology/cryptographic-foundations/), and [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/). ### 13. Lawful access and unmasking *"When a proof is anonymous, can a lawful authority ever reach the identity behind it, and can the buyer accept a system where the answer is a permanent no?"* **The issue.** Most privacy-preserving verification is anonymous by design: a zero-knowledge proof shows the claim is true and keeps no link between the credential and the civil identity, so no party, and no court, can connect them. That is a feature for the user and a problem for the buyer who answers to a regulator, a safety obligation, or a court. Can the buyer's setting accept a proof that no lawful authority can ever de-anonymize, behind which a serious abuser stays out of reach for good? Some settings can, many cannot. Three postures answer it: - **Unmasking is impossible.** No party holds the link between the credential and the civil identity. *Implication:* maximal privacy, and no lawful path, so a serious abuser stays out of reach for good. - **Unmasking is mandatory.** The operator always holds the link. *Implication:* serves regulated and safety-critical uses, and exposes every user to whoever can breach the operator. - **Unmasking is governed.** Anonymity for everyday use, and a deliberate, auditable path to unmask the identity exists for lawful process. *Implication:* lawful reach without standing exposure, but only if the governance is real and not a backdoor by another name. This cuts both ways by reader: an enterprise in a regulated sector wants a lawful path, a privacy-maximalist wants it impossible. The capability that lets anonymity and lawful reach coexist is rare; a buyer should not assume a privacy-preserving system has it. **not.bot's position.** not.bot keeps everyday use anonymous and provides a governed path to the identity behind a proof for lawful process. Identification starts from a specific signature, requires a valid US legal demand, needs the cooperation of both Julia Social and the independent escrow agent, and then takes days of per-record computation on air-gapped hardware; no single party holds the link, and bulk identification is not possible, because there is no database mapping users to identities and each request handles one signature. The result is lawful reach without standing exposure. See [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/) and [Privacy Architecture](https://not.bot/technology/privacy/). ### 14. Adoption risk *"Once a buyer commits, will the vendor last, what does the system cost, and must the buyer pay in a cryptocurrency?"* **The issue.** Buying a verification system is a bet on the vendor, not just the technology. A few risks to weigh: - **Durability.** Will the vendor still be operating in a few years, and how much of what the buyer builds depends on it continuing to run? An established vendor is sometimes the safer bet. - **Leverage.** Once a buyer has built on a system, switching is costly, so the vendor's power to raise prices or change terms has teeth. This risk is much the same across vendors. - **Cost.** Per-user pricing runs from commodity bot-checks at the low end to full identity verification at the high end, and the same check can cost many times more under one architecture than another. The cheapest option is not always the right one, but cost belongs on the checklist. - **Token exposure.** Some systems require the buyer to pay in a cryptocurrency rather than ordinary money, or pull the buyer into a token economy a crypto-averse board will not accept. A buyer should ask whether adopting the system means participating in cryptocurrency at all. **not.bot's position.** A buyer pays for not.bot in ordinary currency. A not.bot user holds no token, pays no blockchain fee, and runs no wallet, because Julia Social funds the on-chain operations; adopting not.bot does not require participating in a cryptocurrency, though the identity records sit on a blockchain. See [Why Chia?](https://not.bot/technology/why-chia/). ### 15. Operational assurance *"How much of the vendor's operations and data handling can the buyer verify, and how much must they take on faith?"* **The issue.** The buyer cannot watch the vendor run, so the real question is how much of its operations and data handling can be checked, and how much rides on the vendor's word. Three postures: - **Trust us.** The vendor publishes little and holds few outside attestations. *Implication:* nothing to verify, so the buyer's only recourse is the vendor's word. - **Certified but closed.** The vendor carries third-party audits, SOC 2, ISO 27001, and the like, over a system that stays proprietary and unauditable from outside. *Implication:* independent proof that controls exist, over a black box the buyer still cannot inspect. - **Open and attested.** The protocol or implementation is open and documented, and operations are backed by certification, the vendor's own or its subprocessors'. *Implication:* the buyer can inspect how the system works and confirm its operations are audited, the strongest assurance and the rarest. The buyer should weigh how much they can verify against how much rides on faith, and treat "trust us" as the posture that has to be made up for everywhere else. **not.bot's position.** not.bot is open and attested. The did:julia method is specified in public, the Chialisp code that implements it is open source, the not.bot Verify SDK is open source, and this documentation set lets a buyer inspect how the system works. Operations rely on certified subprocessors: the identity-verification partner that validates the passport at enrollment holds ISO/IEC 27001:2022 certification and is an eIDAS Qualified Trust Service Provider, and the escrow agent that stores the encrypted records has completed a SOC 2 Type 1 examination. Julia Social holds no certification of its own; the assurance comes from the open protocol, the public documentation, and the certified subprocessors. The multiparty-computation protocols have not yet had an independent security audit, and one is planned. See [did:julia Technical Specification](https://not.bot/technology/did-julia-specification/), [Privacy Architecture](https://not.bot/technology/privacy/), and [Enrollment and Identity Proofing](https://not.bot/technology/enrollment/). --- > **About Julia Social** — https://not.bot/learn/about-us/ · Markdown: https://not.bot/learn/about-us.md · Updated 2026-06-17 # About Julia Social Julia Social builds digital identity that proves a person is real without learning who they are. The company makes not.bot™, a cryptographic identity people carry on their phones; not.bot™ Verify, the server software businesses run to check that identity inside their own infrastructure; and not.bot™ Sign My Work, a tool for public figures and brands to sign their content so audiences can tell it is genuine. honest.bot™, on the roadmap, extends the same identity to AI agents, so a responsible human stands behind every automated action. The company started with a question that AI has made urgent: how will anyone know what is real when the internet fills with deepfakes and bots? Answering it means giving people a way to prove they are human, and giving everyone else a way to check, without building one more database of who did what. The company takes its name from Julia in George Orwell's *1984*, the character who holds on to a private life under a regime that watches everything. The name carries the company's first principle: protecting people's privacy starts with protecting it from Julia Social itself. ## Why privacy > "Internet infrastructure must not be built around honeypots and gatekeepers." > — Ken Griggs, Founder and CEO A technology becomes infrastructure when it achieves credible neutrality. Cisco's routers move traffic without reading it or holding an opinion about it. Oracle and Postgres store data without knowing what is in it, and on a customer's own servers the database vendor sees none of it. People build on this equipment because they trust it to stay out of the way and out of the data, and that neutrality is what lets one technology become a shared default. Identity is the hard case. To prove who you are, a system has had to learn who you are and then keep the knowledge, so identity could not stay neutral. The cost shows up in familiar forms: databases that store identities and become targets the moment they exist, and a small set of sign-in providers that users must route through. The arrangement works until attackers breach the database or a provider changes its terms. Julia Social set out to bring credible neutrality to identity. The company confirms that someone is a real, unique human without learning who they are and without keeping anything that would identify users in case of a breach. Julia Social built the system so it cannot see who uses it, which is why the founders describe their first principle as protecting people's privacy from Julia Social itself. ## How blind identity works Blind identity is hard to build, which is why it is not already the default. Julia Social uses multi-party computation so that no single party, the company included, ever holds enough to reconstruct a person's identity. Identity data stays on the person's own device. Businesses run not.bot Verify inside their own infrastructure, so user data never reaches Julia Social during a check, the way a database vendor sees nothing of what a customer stores on its own servers. The result is identity that behaves like the trusted layers of the internet: useful, current, and blind to the data it carries. The [Overview](https://not.bot/learn/overview/) and [Privacy Architecture](https://not.bot/technology/privacy/) describe the architecture in full. ## The team ### Founders **Ken Griggs, Founder and CEO.** Ken started Julia Social in 2024 after three years building on the Chia blockchain at Chia Network, where he was VP of Customer Success. At Chia he invented DataLayer, a decentralized data system now carried forward as DIG by a separate team, and holds two patents for it. He was the technical lead on the group that convinced the World Bank to choose Chia for the Climate Action Data Trust, the registry that now records more than 95% of the world's carbon-credit projects, and he wrote the whitepaper that made the technical case. He found and disclosed a critical vulnerability in the TibetSwap DeFi exchange before anyone could exploit it. Before Chia, Ken spent seven years in Deloitte's Innovation Lab, where he led development of high-assurance accounting software built to the security and quality bar a Big Four brand demands. Earlier he spent more than a decade in speech recognition at Nexidia, where his work on Nexidia Align contributed to a technical Emmy, and he holds six patents from that work. He also published the first design for a decentralized name service on Chia, the idea behind not.bot's Julia Vanity Names. Ken holds a BS in Computer Science from Georgia Tech and an executive MBA from Emory's Goizueta Business School. **Bill Kesselring, Co-Founder and VP of Business Development.** Bill builds and funds companies. He spent a decade as a general partner at GMG Capital Partners, where he helped raise $250 million for early-stage technology companies, and he has founded and led ventures through acquisition, including Kenai Systems, a web-services security company acquired by Forum Systems. Before Julia Social he was Chief Revenue Officer at Tozny, a zero-trust security platform built on cryptography developed with DARPA, NIST, and Galois. That work put him at the center of the problem Julia Social solves: giving organizations strong identity and encryption without asking them to trust a vendor with their data. At Julia Social he leads product direction and go-to-market for not.bot and honest.bot. Bill holds a BS in Business Administration from San Jose State University. **James Hoerr, Co-Founder and Engineering Lead.** James builds production systems from zero and ships them. He founded Galactechs, an engineering consultancy behind multiple infrastructure projects, and led engineering at Evergreen Systems, where the team shipped a Chia-powered hardware and cloud platform and brought in more than $5 million in sales. He built and scaled a multi-million-dollar AI datacenter running more than 800 GPUs for production AI workloads. He is a builder in the Chia ecosystem and the creator of Druid Garden and the Chia FastFarmer. At Julia Social he leads engineering, turning the privacy architecture into shipping software across the not.bot app, not.bot Verify, and the did:julia infrastructure. ### Partners, advisors, and contributors **Ram Jeyaraman** is co-founder and CTO of Datacaliper. He partnered with Julia Social to build not.bot, and his team carried much of the app's development. **Rob Wiltbank**, CEO of Galois, advises Julia Social on cryptography and was an early convert to its approach to privacy. **Grant Cermak** advised Julia Social from the start and helped shape its earliest decisions. **Santhosh Kumar and Zaina Fathima** led development of the not.bot app and have built many kinds of user-facing applications. ## Where we're going Julia Social is building identity as public infrastructure: open where it needs to be trusted, blind where it needs to be safe. not.bot Sign My Work launches first, honest.bot follows, and over time Julia Social decentralizes recovery and opens the credential platform to outside builders. The [Roadmap](https://not.bot/learn/roadmap/) lays out the sequence. --- > **Human Verification and not.bot Verify** — https://not.bot/learn/human-verification/ · Markdown: https://not.bot/learn/human-verification.md · Updated 2026-06-14 # **Human Verification & not.bot™ Verify** Your site has a bot problem. CAPTCHAs used to help. They stopped working when AI learned to solve them faster than humans. Behavioral fingerprinting works until the bot fingerprints a real browser session and replays it. Device attestation narrows the gap, but attestation proves a device exists, not that a person is using it. not.bot Verify is server software you deploy inside your own infrastructure. It replaces these workarounds with a cryptographic answer: proof that an enrolled human, holding their own device, authenticated with their biometric or device passcode at the moment of the request. No bot, script, or AI can produce one. The user's not.bot app handles the cryptographic exchange with your Verify servers. Your site configures which claims to request. The user reviews the request and either approves it or declines. When verification succeeds, your backend receives a signed response containing the requested claims. The entire exchange stays within your infrastructure and the user's device. No traffic hits Julia Social. ## **Three problems, one integration** Not.bot Verify can request any combination of three different kinds of data from a user: ### **Proof of humanity** A valid not.bot verification requires a real passport-verified human, on their enrolled device, authenticating with FaceID, TouchID, or their device passcode at the moment your site sends the request. The response carries a `notbot0` credential proving the user passed identity proofing during enrollment. The cryptographic proof is unforgeable. No bot can produce a valid signature from a key it does not hold, and each verification includes a fresh nonce tied to your specific request, preventing replay. ### **One person, one account** One person creates ten email addresses and claims your new-customer discount ten times. Another runs a bot farm posting fake reviews. A scalper grabs forty pairs of limited-release sneakers through forty accounts. The common thread: one human pretending to be many, and your site has no way to tell. This problem is called a Sybil attack, and it is growing rapidly across the internet, enabled by AI. Site Passes provide a strong defense against Sybil attacks. A Site Pass is a token unique to one human on your site. The same person always produces the same Site Pass for your site, regardless of which alias or account they use. A different person produces a different Site Pass on your site. You store the Site Passes you have seen; a duplicate means the same human is back. For each person / site pair, there can only be one Site Pass, guaranteed by math. Promo-code abuse, fake reviews, free-trial cycling, scalping, airdrop farming, survey manipulation, and multi-account fraud all become impossible when your site can recognize that ten "different" accounts belong to one person. And bots can’t even get in at all. The privacy properties matter here. Three parties compute the Site Pass through multiparty computation: the user's app, your Verify servers, and Julia Social. The protocol prevents Julia Social from learning which site generated the request, and prevents your site from learning the user's real identity. If two sites collude and compare their Site Passes, the comparison reveals nothing, because each site's passes are cryptographically distinct. Your users get one-account enforcement without cross-site tracking. ### **Age and attribute verification** You can request specific claims about a user. The most common are age thresholds: `AgeOver18`, `AgeOver21`, or any threshold from 13 to 25\. The user's age credentials are derived from their passport through a three-party multiparty computation among the not.bot app, Julia Social, and the Escrow Server (operated by Praxis, an independent escrow agent). Neither Julia Social nor the Escrow Server learns the user's birthdate during this process. The credentials expire monthly and refresh through the same MPC. Your site learns the answer to the question you asked. If you request `AgeOver18`, you receive a boolean: true or false. You do not learn the user's actual age, birthdate, or name. If you request `AgeOver21` and the user is 19, the credential value is false and the user can decline the request entirely. Beyond age thresholds, you can request age range brackets (five-year and ten-year), birthdate information, nationality, gender, and name fields. The user sees the full set of claims you requested and decides whether to respond. Your site receives the claims you asked for, nothing more. ## **Verification levels** The not.bot verification level tells you how much confidence to place in the person behind a set of claims. Each level represents a different strength of identity proofing during enrollment. **Notbot0** (available now): The user scanned the NFC chip in a government-issued passport. The app read the chip, and a certified identity-verification partner validated the chip's digital signatures against the ICAO Public Key Directory and confirmed the passport was genuine and unexpired; the Escrow Server (operated by Praxis) confirmed the passport had not been used to create another not.bot identity. No liveness check is performed at this level. **Notbot1** (planned): The user completed identity proofing at a third-party enrollment partner: a bank, hospital, or similar institution. The partner follows NIST SP 800-63A Identity Assurance Level 2 (IAL2, in-person) procedures under contractual obligation. Julia Social does not audit these partners. The enforcement mechanism is consequence-based: if Julia Social suspects substantial fraudulent issuance, it revokes all credentials that partner issued by melting the partner's issuer key singletons on the Chia blockchain. All affected users must re-enroll elsewhere. **Notbot2** (planned): The user completed identity proofing at a first-party facility contracting directly with Julia Social. The levels are cumulative. A Notbot1 holder also holds Notbot0. A Notbot2 holder holds all three. Each level is a distinct verifiable credential with its own URI (`notbot://./v1/notbot0`, `notbot://./v1/notbot1`, `notbot://./v1/notbot2`). **Guidance for verifiers:** Request the lowest level your use case requires. Most verifiers will request notbot0. Requesting a higher level shrinks the pool of users who can interact with your site. ## **Available claims** Every enrolled user, regardless of verification level, holds the same set of presentable claims. The verification level describes the strength of the identity proofing behind those claims; it does not gate access to claim types. **Bot detection:** `Notbot0`, `Notbot1`, `Notbot2`. Request one or more to confirm the user's enrollment level. **Age thresholds:** `AgeOver13` through `AgeOver25`, plus `AgeOver100`. Each proves the user meets or exceeds the specified age without revealing the actual age. The value is a boolean. **Age ranges:** Five-year brackets (`AgeRange20To24` through `AgeRange95To99`) and ten-year brackets (`AgeRange20To29` through `AgeRange90To99`). The user's bracket credential is true for the bracket they fall within and false for all others. **PII fields:** `FirstName`, `GivenNames`, `FamilyName`, `Gender`, `Nationality`, `BirthDate`, `BirthDay`, `BirthMonth`, `BirthYear`. These are derived from the user's passport data. The user sees which PII fields your site requested and can decline the entire request if they are uncomfortable sharing them. **Site Pass:** `SitePass`. A per-user-per-site pseudonymous identifier. Enable it when you need one-person-one-account enforcement. The same human always produces the same Site Pass for your site. **honest.bot™:** `honestbot`. Verifies the presenting process holds a valid honest.bot credential. Used when the counterparty is an AI agent rather than a human. The full claim URI list is in `shared/claim_properties.txt` in the [Julia Web SDK repository](https://github.com/julia-social/julia_web_sdk). ## **The user's experience** A visitor to your site encounters a verification request in one of two ways. **On mobile:** Your site presents a universal link, which can be a button in your app or a tappable link in a mobile browser. The link opens the not.bot app. The app displays your site's domain name (cryptographically verified against your business DID's domain credential), the claims you requested, and any message you attached to the request. The user selects which alias to respond with, reviews the requested claims, and either approves or declines the entire request. Approval requires authentication (FaceID, TouchID, or device passcode). The app completes the cryptographic exchange with your Verify servers and returns the user to your site. **On desktop:** Your site presents a QR code. The user scans it with their phone, which opens the not.bot app. The rest of the flow is the same. If the user does not have the not.bot app installed, the link redirects to the appropriate app store. The user sees what you are asking for before they respond. Approval is all-or-nothing: the user responds with the full set of requested claims, or declines the request. There is no partial approval of individual claims. Alias selection gives the user control over which identity they present to your site. If the user has visited your site before, the app pre-selects the alias they used last time, even if that alias is hidden. If the user has never visited your site, the app defaults to creating a new alias. The user can override either default and pick any existing alias. Your verification request can also specify which alias the user must respond with; if the user does not want to use that alias, they can decline. If the user does not have that alias, the app will auto-decline the request. ## **The verification flow** Your backend integrates the Julia Web SDK, a server-side library available in Rust, JavaScript (Express), Python (FastAPI), Java (Spring MVC), and Dart (shelf). The SDK adapter mounts routes into your web framework and handles the cryptographic exchange between the user's app and your signature servers. You write the callbacks that decide what to do with the result. The flow: 1. Your frontend calls `GET /signature/notbot` on the SDK adapter. The adapter starts a session with one of your signature servers and returns a request ID. 2. Your frontend builds a universal link URL from the request ID and presents it as a button or tappable link (mobile) or QR code (desktop). 3. The user's not.bot app opens and completes the cryptographic exchange with your signature server through the SDK adapter. Your backend code does not participate in this exchange. 4. When verification succeeds, the adapter calls your `onSuccess` callback with the verified response and the user's session. The response contains the user's alias DID, the claims you requested, the Site Pass (if enabled), a timestamp, and the full cryptographic presentation. 5. Your frontend polls for completion and updates the UI. The exchange is direct between the user's phone and your servers. No packets reach Julia Social. Your signature servers use their own private keys (stored in your OpenBao instance) to sign the interaction. Each signature you collect embeds a complete copy of the request that produced it: your signature server's DID, its domain-name credential, the nonce, and the claims you asked for. Your server signed that request, so every verified response countersigns the exact request it answered. This binds the user's signature and your request into one record that neither party can repudiate, and it lets you reconstruct, for any stored signature, which of your servers requested it and what it asked for. No tooling extracts this embedded request today; it rides inside every signature as a latent property. The SDK is open source, available here: [https://github.com/julia-social/julia\_web\_sdk](https://github.com/julia-social/julia_web_sdk) A minimal integration in JavaScript: ```javascript const signatureAdapter = createExpressSignatureAdapter({ signatureClient: createSignatureClient(), requestedClaims: [ClaimProperties.Notbot0, ClaimProperties.AgeOver18], requireSitePass: true, onSuccess: async (verifyResponse, session) => { session.juliaSignatureVerification = verifyResponse; }, }); app.use(signatureAdapter.router); signatureAdapter.attachWebsocketHandlers(httpServer); ``` ## **Your infrastructure, your data** not.bot Verify runs inside your data center or cloud account. You deploy four components into your Kubernetes cluster: an admin service, one or more signature servers behind a load balancer, Chia blockchain nodes, and an OpenBao vault holding your DID keys. You provide PostgreSQL and Keycloak. All four Verify components sit behind your WAF and within your existing security perimeter. They do not expose new public endpoints that you need to protect separately. The Julia Web SDK that connects your application backend to your signature servers is open source, so your security team can audit it before deployment. No user data flows through Julia Social’s servers. The two data flows that reach Julia Social are aggregate integers: a monthly active user count (once per hour, for billing) and a successful-verification count (once per hour, for diagnostics). No user identifiers, IP addresses, request details, or signature payloads accompany either number. ### **Julia Social is not a supply-chain risk** Three questions matter when you evaluate a vendor dependency: What happens to my site if their servers go down? What happens to my performance if their servers are slow? What happens to my data if they get breached? **Availability.** Julia Social's servers going down does not affect your ability to verify users. Your signature servers handle all verification traffic. They contact Julia Social once at startup to acquire an honest.bot credential, then operate with no further Julia Social involvement. If Julia Social is unreachable, running signature servers continue to serve verification requests. Your site stays up. The only operation that blocks is starting new signature servers, which resumes as soon as connectivity returns. **Performance.** Julia Social's server performance has no effect on your verification latency. The cryptographic exchange runs between the user's phone and your signature servers. Julia Social is not in the request path. Your signature servers support autoscaling behind a load balancer to meet your traffic demands, and the scale ceiling is the number of signature DIDs you mint in the admin interface. **Breach.** If Julia Social's systems are compromised, no customer data is exposed. Julia Social does not hold your DID keys, your user records, your verification logs, or any content from your verification requests. Julia Social receives two integers per hour from your deployment. An attacker who breaches Julia Social gains access to aggregate usage counts. That is the full extent of the data at risk. ### **Key protection** Your DID private keys live in OpenBao and never leave it. Keys are generated inside OpenBao through the Chiakeys plugin, are never written to disk in cleartext, and are never exported. All BLS signature operations execute inside OpenBao. Your signature servers send signing requests to OpenBao and receive signed results. The key material never touches your application code, a disk, or your network. ### **Site privacy** Julia Social does not know which users visit your site. The verification exchange runs between the user's phone and your servers. Julia Social cannot see your verification requests or read the responses, and has no way to determine which not.bot users interact with your deployment. The Site Pass MPC protocol prevents Julia Social from learning which site generated a given request. Julia Social's visibility into your Verify operations is limited to the two hourly aggregate counts. ### **Regulated industries** The customer-hosted deployment model matters for organizations that cannot route identity verification through a third party. Healthcare organizations bound by HIPAA, financial institutions subject to data residency requirements, and government agencies pursuing FedRAMP can deploy Verify within their own compliance perimeter. No Business Associate Agreement with Julia Social is required because no protected data flows to Julia Social. Cloud-only verification services cannot serve these buyers. If your verification vendor intermediates every request through their infrastructure, your user data passes through their systems, their jurisdictions, and their security posture. Not.bot Verify eliminates that dependency. ## **Collect only the data you need** You learn the minimum needed for your use case. You learn the answers to the claims you asked for. If you asked whether the user is over 18, you learn yes or no. You do not learn their age, their birthdate, or their name, unless you included those claims in your request. You cannot connect a user's alias on your site to their aliases on other sites. Aliases are cryptographically unlinkable. Site Passes are per-site; comparing Site Passes across sites reveals nothing. You do not learn the user's verification level unless you asked for it. A user with Notbot1 credentials who receives a Notbot0 request can present Notbot0 without revealing they hold a higher level. ## **Further reading** - [Overview](https://not.bot/learn/overview/) for how Verify fits into the not.bot product family. - [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/) for the signature model that underpins verification. - [Privacy Architecture](https://not.bot/technology/privacy/) for the privacy assertions and data flow analysis. - [Security Model](https://not.bot/technology/security/) for the security assertions and known weaknesses. - The [not.bot Verify: Julia Web SDK Reference](https://not.bot/technology/web-sdk/) for integration documentation. - The [Architecture & Privacy Guide](https://not.bot/technology/verify-architecture/), [Deployment Checklist](https://not.bot/technology/verify-deployment-checklist/), and [Operations & Reference Guide](https://not.bot/technology/verify-operations/) are delivered to Verify subscribers. --- > **Content Signing and not.bot Sign My Work** — https://not.bot/learn/content-signing/ · Markdown: https://not.bot/learn/content-signing.md · Updated 2026-06-17 # **Content Signing & not.bot™ Sign My Work** Your organization publishes under attack. A video-cloned executive moves money. A deepfaked physician sells a "cure" she never endorsed. A fabricated statement in your candidate's name lands the night before the vote. Each attack works for the same reason: the audience has no fast way to tell your real content from a convincing fake, and detection loses ground with every new model. not.bot Sign My Work inverts the problem. Instead of proving fakes are fake, you make it easy to prove the authentic is authentic. You sign what you publish, every time, and the signature is a visible code rendered into the content. Anyone can scan it with the free not.bot app and confirm that a verified human authorized to act for your organization signed it. Sign everything you publish, and your audience can dismiss anything unsigned in your name as fake. not.bot Sign My Work is the hosted member of the not.bot product family, made by Julia Social. It is targeted for launch at the end of June 2026. ## **How signing works** not.bot Sign My Work runs on top of the not.bot app, so every human signer starts in the app. You enroll once by scanning your passport (in-person enrollment is planned), which creates a phone-held identity that proves you are a real, unique human without revealing who you are. From that identity you create an alias, which is a separate working identity, and dedicate it to signing for your organization. That alias is what not.bot Sign My Work knows you by. You log in to not.bot Sign My Work with the alias. A login request reaches the not.bot app, you confirm the login request, and you are in. No password required: your not.bot alias is your login. You sign under a Verified Signer badge, not the bare alias. A badge is a human-readable line your organization issues, such as "Editor @ dailyherald.com," and it is the identity a verifier reads. One alias can carry several badges, so a communications team member's signing alias might hold a badge for each executive they post for and one for the company itself, and they would pick the badge that fits each piece of content. The organization sets each badge up once. Signing one item is quick. You upload the finished content, and not.bot Sign My Work stores it encrypted. A signature request comes to your phone, and you confirm you want to sign. You'll have the chance to see the content in the app to verify it's the intended content. From there you choose how the code reaches the content. not.bot Sign My Work can render the QR into the content, and you download the result or post it straight to a connected platform. Or you download the bare signature QR and place it into the content with whatever tool you already use. Either way, anyone can scan the visible code on your content. ## **What you can sign** Five content types at launch. not.bot Sign My Work stores an encrypted copy of the original, the signature carries the decryption key, and a QR rendered into the published artifact is the verification surface. - **Video.** Limited to 75 minutes / 16 GB per video. - **Images.** - **Posts and threads.** Signed as one bundle: the ordered post texts plus attached images. - **PDFs.** A printed copy stays verifiable, which an embedded e-signature cannot offer. - **Links.** Sign a URL, such as a donation page or payment address, so your audience can confirm the destination is yours before they click. Every distinct piece of content should get its own signature. Reformatting content does not need a new signature. Significant edits need their own signature. ## **The known-good copy** When you sign through not.bot Sign My Work, an encrypted copy of the original is stored at a permanent address. The unique decryption key is embedded in the QR signature. Even Julia Social, the company behind not.bot and not.bot Sign My Work, cannot decrypt the content without the decryption key in the QR code. not.bot Sign My Work keeps your QR signatures encrypted as well, readable only from inside your own logged-in session. A verifier who scans your signature can pull up the original in the not.bot app, decrypted on their own device, and compare it against whatever version they have received. If it matches, the signature is good. If it does not match, the verifier knows the signature has been copy-pasted out of the real document and into something else. The copy they access through the app is the unsigned original, your content as uploaded before any QR was rendered onto it. If the content in the app does not match the content to which the signature was attached, the verifier knows the signature is invalid. Storage is perpetual and priced into signing, not your subscription. A signed video stays verifiable after you stop paying, because its hosted copy is funded at the moment you sign it. ## **Verifying a signature** Verification needs only the free not.bot app. A QR scanned by a phone without the app routes to the app store, so every signature in the wild is also an invitation into the verification ecosystem. On a scan, the verifier sees the Verified Signer badge of the human that created the signature, the organization-assigned line such as "Editor @ dailyherald.com". The badge is the identity the audience reads. The alias beneath it, its petname, reserved name, and identifier, is available on request, not shown by default. One more tap opens the hosted original, decrypted on the verifier's device, for comparison against whatever version they found. A signature valid when created stays valid until voided, so a newsroom's ten-year archive does not rot when staff move on. A voided signature shows "voided" and the date. A deleted signature's QR doesn't scan at all, so an orphaned code cannot be pasted onto unrelated content to borrow authority. ## **Who uses not.bot Sign My Work, and how** The same loop serves organizations of every size, and signing becomes the last production step before anything ships: produce, approve, sign, post. **The solo creator or public figure.** A physician, entertainer, journalist, or athlete who frequently posts videos uses not.bot Sign My Work as an organization of one. Record the video, open the not.bot Sign My Work web app on their device, pick the file, type the caption while it uploads, tap *Sign & Post*. The not.bot app opens showing what a verifier will see; glance, touch the sensor, pocket the phone. not.bot Sign My Work renders the branded end-card with the QR, publishes to the connected platform, and pushes a confirmation when it is live. About six taps and one biometric or passcode per video, with the upload as the only wait. not.bot Sign My Work's first publishing integration is Instagram, and more are planned. For every other platform, you download the signed content and post it yourself. **The communications team.** A brand, newsroom, or campaign desk publishing dozens of items a day works from desktop browsers, where "nothing ships unsigned" becomes routine. Each item requires one phone interaction to create the signature, and the signed content flows back into the schedulers, ads managers, and publishing tools the team already uses. A crisis statement can go from staged to published in minutes, signed. Paid creatives are a sharp case: a dark ad never appears on a public feed, so the in-creative QR is the only authenticity surface a targeted ad has. **The accountability signer.** Organizations that sign to take responsibility, such as AI-content disclosures, compliance statements, and chain-of-custody attestations, treat the signature as a record. Signatures stay valid as of their signing time, voiding is timestamped repudiation that preserves the record, deletion is slow and attributed, and the full signing history exports to CSV for auditors. ## **Organizations, roles, and onboarding** not.bot Sign My Work has two roles. - **Admins** manage settings, billing, invitations, brand templates, and oversight. They are identified by email. Admins cannot sign content. - **Members** sign. A Member is identified by their not.bot alias. not.bot Sign My Work does not have the Member's email, name, or other personal information. **Verified Signer badges are how an organization authorizes its signers.** Organizations do not sign; their people do, under a badge the organization provides. The setup needs no corporate identity of its own and no server: 1. Each authorized signer creates a dedicated alias in the not.bot app. 2. The organization publishes that alias's identifier on web real estate it controls, such as its site or a verified social account. Publishing proves control, since only example.com's owners can put content on example.com. 3. Julia Social verifies the publication and issues a Verified Signer badge to the alias, with a human-readable line such as "Customer Support at ExampleCompany.com" or "Editor @ dailyherald.com." 4. Every signature made through not.bot Sign My Work carries that badge. One alias can hold more than one badge: the organization repeats the publication step for each entity the alias signs as, and the signer chooses among them at signing time. The meaning of a not.bot signature is precise: a human authorized to sign on behalf of the organization signed this. It is never a claim of personal authorship. A campaign staffer signing under "Joe Candidate @ joecampaign.org" produces what a press release is, made cryptographically checkable. **Offboarding is one immediate action.** Remove a Member and their membership ends and revocation of their badge begins. Everything they signed stays valid, so the organization's signed history survives staff turnover untouched. ## **The signing experience** **No passwords exist, in any role.** There is nothing to phish, leak, stuff, or reset. Members log in with a signature: a request reaches the not.bot app, the app surfaces the work alias first as a guard against picking a personal one, and a biometric or device passcode completes it. Member sessions persist for 30 days, sliding forward on each signature, so a dormant session expires and an active signer stays logged in. Admins log in by a single-use email magic link plus a mandatory second factor. **Mobile is an installable web app.** An icon on the home screen, full screen, with push notifications, and nothing to install from an app store beyond the not.bot app the signer already has. One-time setup covers enrolling in the app, adding not.bot Sign My Work to the home screen, connecting a publishing platform, and choosing an end-card template. **The ceremony shows verifier parity.** What the app displays for review is what a future verifier will see: the badge and the content reference. **Sign-and-download is universal.** Every signed artifact, and the bare QR for teams that composite in their own tools, is always downloadable for any platform, scheduler, ads manager, or print shop. Direct-publish integrations remove steps where Julia Social can build them; they do not limit where you publish. Instagram-direct is the first integration: connect once over standard OAuth, and the stored token is encrypted so that only your own active session can use it. A breach of not.bot Sign My Work cannot post as you. ## **What sets not.bot Sign My Work apart** **A human signs every item.** not.bot Sign My Work holds no signing keys and signs nothing on anyone's behalf. Every signature is produced by a verified human on their own device. There is no automated signing, no API key that produces signatures, and no service account. not.bot Sign My Work's job is to make that human act take seconds. **The signature survives the open internet.** Signatures are QR codes rendered into the content: a branded end-card on a video, a trailer image on a thread, a stamp on a PDF. Platforms strip metadata. They do not strip pixels. Screenshots, re-encodes, re-uploads, and printouts keep the signature scannable. The code also tells a viewer that verification is available, which a hidden watermark does not do. **not.bot Sign My Work cannot read uploaded content.** The originals not.bot Sign My Work stores for verification are encrypted, and not.bot Sign My Work never keeps the decryption keys. The keys travel inside the signatures, held by you. An attacker who steals every byte of not.bot Sign My Work's storage gets encrypted blobs with no way to open them. ## **Record discipline for compliance** For buyers who sign as a documented control, the record behavior is the draw. **Voiding** is the low-friction safety valve. The signing Member can void their own items, and an Admin can void anything in the organization. The signature will show as voided to verifiers and the record that it existed remains. **Deletion** is the guarded act. Only Admins can delete signatures and associated data. Deletion is reversible for 90 days, with the content hidden from everyone yet restorable in place. Every deletion lands in a daily digest to all Admins, attributed. After 90 days the content and signature payload are purged, and a metadata tombstone survives in the audit record. **Audit export** gives Admins the organization's complete signing-activity record as CSV: every item's signing alias, timestamps, status, void and delete actions with actor and time, and tombstones. It is built for the SOC 2, HIPAA, and SOX conversation, where "we sign everything" needs to be a documented control. **Spend control** lets an organization set a monthly video-minute cap and optional per-Member caps. Members see remaining quota at upload, Admins are alerted at 80 percent, and the cap blocks with a plain message rather than a surprise bill. ## **Privacy and security for due diligence** Each property below is enforced by how the system is built, not by a policy. **A total breach of Sign My Work yields no route to any content.** An attacker stealing all of not.bot Sign My Work's storage gets only encrypted blobs and no keys. The maximum exposure is bounded operational metadata: organization names and settings, brand templates, public Member alias identifiers and their membership status, item titles and types and timestamps and statuses, void and delete history, Admin email addresses, and billing records. No content, no thumbnail, no signature message, no key, no usable session, no Member email, and no cryptographic link between two aliases or between a human and an alias is in that set. **Plaintext media never touches a disk.** Unencrypted content exists only in server memory, only while your own request or publish job is being processed, and is wiped when that window closes. Even thumbnails are generated in your browser and stored encrypted; not.bot Sign My Work's servers never decode your media. **Sessions are split-key.** Showing you your own encrypted data needs a value in your browser cookie and a record on the server, each useless alone. Logging out or being offboarded destroys the server part at once, which makes any stolen cookie inert. **Honest disclosures.** Item titles and other operational metadata are stored in plaintext so the dashboard, deletion digest, and audit export can function; keep content out of titles, since the title is the one free-text field stored unencrypted. The roles one alias signs under are linkable to each other in public, though never to the human, so an organization that wants role separation uses one alias per role. In an organization of one, not.bot Sign My Work's own billing records plus the single published alias support an inference tying the payer to the signing alias; a signer whose safety depends on no such link should use the not.bot app's on-device path with app-store billing. not.bot Sign My Work is not an anonymity system against its own records or legal process. ## **How not.bot Sign My Work fits with Verify and the not.bot family** Where not.bot Verify is server software a business deploys in its own infrastructure to verify users, not.bot Sign My Work is hosted by Julia Social: no servers, no deployment, no key management. You bring a browser and the not.bot app. not.bot Sign My Work's own backend is a not.bot Verify customer. ## **Availability and requirements** - **Launch target: end of June 2026.** Until then, not.bot Sign My Work is "coming soon". - **For signing:** the not.bot app on iOS or Android with a passport-enrolled identity, and a browser. Mobile video signing works best as the installed web app; push notifications need iOS 16.4 or later. - **For verification:** the free not.bot app, with no account of any kind. - **For organizations:** control of web real estate on which to publish not.bot aliases, an email address per Admin, and a card for billing. - Hosted by Julia Social. Support: support@julia.social. ## **Further reading** - [Overview](https://not.bot/learn/overview/) for how not.bot Sign My Work fits into the not.bot product family. - [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/) for the signature model that underpins not.bot Sign My Work. - [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/) for the enterprise verification product not.bot Sign My Work's backend runs on. - [Use Cases: Content Signing](https://not.bot/learn/use-cases-content-signing/) for the catalog of signing scenarios. - [Privacy Architecture](https://not.bot/technology/privacy/) and [Security Model](https://not.bot/technology/security/) for the privacy and security assertions across the platform. - [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/) for the credential model behind Verified Signer badges. - [Roadmap](https://not.bot/learn/roadmap/) for what comes after launch. --- > **The not.bot App** — https://not.bot/learn/the-app/ · Markdown: https://not.bot/learn/the-app.md · Updated 2026-06-14 # **The not.bot™ App** The not.bot app is your identity on your phone. You enroll once, create as many aliases as you need, and use them to sign content, prove things about yourself to websites, and verify other people's signatures. Your personal information stays on your device. Julia Social, the company behind not.bot, cannot access it. This document covers what you experience as a user: enrollment, aliases, signing, scanning, verification requests from websites, contacts, recovery, and the settings you control. For the privacy architecture and security model underlying these features, see [Privacy Architecture](https://not.bot/technology/privacy/) and [Security Model & Known Weaknesses](https://not.bot/technology/security/). The app is available on iOS and Android worldwide. Android devices require hardware security (a Trusted Execution Environment) equivalent to the iOS Secure Enclave. ## **Enrollment** You enroll by scanning the NFC chip in your passport. Hold your phone against the data page of a current, NFC-enabled passport. The app reads your name, date of birth, gender, and nationality from the chip's data group 1 (DG1). It does not read your facial image (DG2). A certified identity-verification partner validates the chip's digital signatures against the ICAO Public Key Directory, confirming the passport is genuine and unexpired. After enrollment, the app creates your root DID (decentralized identifier) on the Chia blockchain and generates your first alias with a random petname and a unique LifeHash. Your first alias has all personal information fields and age credentials enabled by default. You land on the home screen ready to create and scan signatures. Enrollment is currently available to users on US app stores. Users in other regions can download the app and use scan-only mode: they can verify other people's signatures, browse their contacts, and view history, but the Join and Me icons are disabled, and they cannot create signatures or manage aliases. International enrollment support is in progress. ## **Aliases** An alias is a separate identity. You can have as many as you need, and each one operates independently. Your professional alias, your anonymous alias, an alias for a forum you visit once. No one, including Julia Social, can connect your aliases to each other or back to you. The unlinkability is cryptographic, enforced by the architecture of the DID system itself. Aliases can never be deleted. You can hide them. Each alias has three identifying elements: **A petname** arrives at creation. Petnames are three-word combinations like "endlessly-altruistic-whale," generated from the alias's 32-byte DID using the [petname](https://github.com/dustinkirkland/petname) algorithm. The algorithm has over two billion possible combinations. You do not choose your petname. Because every copy of the app generates petnames the same way from the DID, anyone who knows your DID can derive your petname without you needing to share it separately. **A LifeHash** is a small, colorful geometric pattern generated from the alias's 32-byte DID using the [LifeHash](https://lifehash.info/) algorithm. Each alias produces a distinct LifeHash. Two aliases with identical LifeHashes are the same alias. Different LifeHashes mean different aliases. As with petnames, every copy of the app generates the same LifeHash from the same DID, so you can recognize an alias at a glance across different contexts without the signer needing to share their LifeHash separately. **A private nickname** is a label you choose, visible only on your device. It helps you tell your aliases apart in the app. Nobody else sees it. ### **Creating an alias** Tap "Create New Alias" on the Me tab. Enter a private nickname, choose whether to hide the alias (more on that below), and configure sharing settings. The app assigns a petname and generates a LifeHash. Free users can create up to five aliases. Pro and Verified Signer subscribers can create unlimited aliases. Unlike your first alias, new aliases have all personal information fields and age credentials disabled by default. The first time you enable credentials on a new alias, the app warns you to be careful about sharing personal information. ### **Hidden aliases** You can mark any alias as hidden. A hidden alias disappears from the app's normal interface. Revealing hidden aliases requires biometric authentication (FaceID, TouchID) or the device passcode. The app re-hides them when it closes and periodically while open. If someone picks up your unlocked phone, they see your visible aliases. The hidden ones, and the signatures created with them, stay invisible unless you choose to reveal them. ### **Reserved names** Reserved names replace the petname with a name you choose: "alice-smith.nb" or "techwriter42.nb." They use a .nb suffix and allow letters, numbers, and underscores, from 3 to 25 characters. The system prevents visual-confusion collisions: uppercase I, lowercase l, and digit 1 are treated as equivalent, as are uppercase O and digit 0\. Underscores are ignored in comparisons. Names that could be confused with petnames are prohibited. Reserved names are first-come, first-served. You do not need to prove you are the person or entity the name suggests. A reserved name does not expire and does not require renewal. Propagation across the system takes up to 10 minutes. Reserved names are a preview of the planned Julia Vanity Name system, which will operate autonomously on the blockchain with deposit-based registration, name transfer, and independence from Julia Social's infrastructure. Pro subscribers receive one reserved name. Verified Signer subscribers receive five. ### **Verified Signer badges** A Verified Signer badge links your alias to a specific social media account. When you sign content with a badged alias, the signature displays the badge (for example, "Verified Signer: @notbot\_official at x.com") instead of the petname or reserved name. The qualification process: 1. Tap "Request Verified Signer Badge" on the Edit Alias screen. 2. The app generates the alias DID in the format `did:julia:<32-bytes-base58-encoded>`. 3. Post the DID text on your social media account. 4. Submit the public URL of the post to Julia Social. 5. Julia Social confirms the post within 24 to 48 hours. The same alias can carry badges for multiple platforms. A badge provides cross-platform recognition: a journalist who signs articles, social posts, and press releases can present the same verified identity across all of them. Verified Signer badges require a Verified Signer subscription ($9.99/month). ## **Signing content** A not.bot signature is a cryptographic proof that a verified human reviewed and approved something. You compose a message, authenticate with your biometric or device passcode, and the app produces a signed image you can attach to photos, documents, or social media posts. For video, the signature is a QR code. ### **Creating a signature** 1. Tap "Create Signature" on the home screen. 2. Select which alias to sign with. The app defaults to your first alias; you can switch. 3. If the selected alias has a Verified Signer badge, choose whether to include it. 4. Write a message describing what you are signing. Be specific. "I authorize this transaction" is more useful than "ok." 5. Optionally include personal information: first name, family name, age. Each field toggles independently. These values come from your enrollment data stored on your device. 6. Tap Next. The app prompts for your biometric or device passcode. 7. The app generates the cryptographic signature and displays the finished image. The finished signature appears as a JAB code by default. JAB codes are large, colorful grid patterns that encode the full signature payload directly in the image. These visible signatures (patent pending) survive distribution channels that strip invisible metadata: a screenshot, a forwarded photo, or a re-uploaded image still carries the signature. JAB codes support up to 250 characters in the message and up to three credential claims (beyond the base not.bot credential). You can toggle to a QR code view if you have a Pro or Verified Signer subscription. QR codes are smaller and more recognizable; the signature data is encrypted and uploaded to Julia Social, with the decryption key embedded in the QR code itself (Julia Social cannot read the data). QR codes do not have the message length or credential limits that JAB codes have. If you select more credentials or write a longer message than the JAB code format supports, the app notifies you that only the QR code version will be available. Free users create JAB code signatures. Pro and Verified Signer subscribers create both JAB and QR code signatures. Tap Share to send the signature through the standard sharing options (AirDrop, Messages, email, or any installed app). The signature is a PNG image, typically around 10 KB. Signatures cannot be revoked once created. The message you write is permanent. ## **Scanning and verifying signatures** You do not need a not.bot identity to verify signatures. Download the app and scan. Tap "Scan Signature" on the home screen. Three input methods: **Camera.** Point your phone at a physical signature or a signature displayed on another screen. **Photos.** Select a screenshot or saved image from your photo library. **Paste.** Scan a signature image from the clipboard. The app extracts and verifies the cryptographic signature against the Chia blockchain. A successful verification displays: - "not.bot verified" confirmation - The signer's alias identity (petname, reserved name, or Verified Signer badge) - Creation and scan timestamps - The full message the signer composed - Any personal information the signer chose to include (name, age) If the signer is in your contacts, the scan result shows the contact name in green. If the signer has a Verified Signer badge, the badge appears in a teal panel with the linked social account. After scanning, you can add the signer to your contacts. ## **Contacts** The not.bot contact list is private and local to your device. The app does not read your phone's contact list, does not upload contacts anywhere, and does not share contact data with Julia Social or anyone else. Contacts are stored encrypted on the Recovery Server, and shared across all of your devices. You build your contact list by scanning signatures. After scanning a signature, you can create a new contact or add the scanned alias to an existing contact. One contact can have multiple aliases associated with it (the same person might use different aliases in different contexts). Each contact entry shows the contact name, the number of signatures you have scanned from them, the number of known aliases, the last scan date, and any personal information they have shared in their signatures. ## **History** The History tab has two views. **My Signatures** lists signatures you created, sorted by date with the most recent first. Each entry shows the alias name, the message, the date and time, and icons indicating whether personal information or age claims were included. A green left border identifies the creating alias. **Scanned Signatures** lists signatures you scanned from others. Each entry shows the signer's name (contact name if saved, or alias name), the message, the date and time, and property icons. A blue left border distinguishes scanned signatures from created ones. ## **Web verification requests** Websites that run not.bot Verify can send verification requests to your app. The experience differs depending on the device: **On mobile,** the website presents a universal link as a button or tappable link in a mobile browser. Native apps can present the same link as a button within the app. Tapping it opens the not.bot app. The app displays the requesting site's domain name (cryptographically verified against the site's business DID), the claims the site requested, and any attached message. You select an alias, review the request, and approve or decline. Approval requires a biometric or device passcode. **On desktop,** the website presents a QR code. You scan it with your phone, and the flow continues in the app the same way. If you do not have the not.bot app installed, the link redirects to the appropriate app store. If you have visited the site before, the app pre-selects the alias you used last time, even if that alias is hidden. If this is your first visit, the app defaults to a new alias. You can override either default and pick any existing alias. A site can also specify which alias you must respond with; if you decline to use that alias, you can reject the request. Approval is all-or-nothing. You respond with the full set of requested claims or decline the request. There is no partial approval. The verification exchange happens directly between your phone and the site's servers. No traffic reaches Julia Social during the exchange. ### **Site Passes** A Site Pass is a token unique to you on a given site. You produce the same Site Pass for that site every time, regardless of which alias you use. A different person produces a different Site Pass. The site stores Site Passes it has seen; a duplicate means the same human returned. Site Passes enable one-person-one-account enforcement without revealing your identity. Three parties compute the value (your app, the site's Verify server, and Julia Social), and the protocol prevents Julia Social from learning which site generated the request. If two sites compare their Site Passes, the comparison reveals nothing, because each site's passes are cryptographically distinct. Creating a Site Pass requires your consent. The site's verification request specifies whether a Site Pass is required; you see this before you approve. ### **Credential claims** A site can request specific facts about you. The most common are age thresholds: over 18, over 21, or any threshold from 13 to 25\. Your age credentials are derived from your passport through a three-party multiparty computation among the not.bot app, Julia Social, and the Escrow Server (operated by Praxis, an independent escrow agent). Neither Julia Social nor the Escrow Server learns your birthdate during the process. The credentials expire monthly and refresh through the same MPC. Beyond age, sites can request age-range brackets, nationality, gender, and name fields. You see the full set of claims before you respond. ## **Subscription tiers** **Free.** Up to five aliases. Create JAB code signatures. Scan both JAB and QR code signatures. **Pro ($1.99/month).** Free features plus one reserved name, unlimited aliases, and QR code signature creation. **Verified Signer ($9.99/month).** Pro features plus unlimited Verified Signer badges and four additional reserved names (five total). Canceling preserves your identity, aliases, reserved names, and existing signatures. You lose the ability to create new aliases beyond five, create QR signatures, or request new Verified Signer badges. ## **Multi-device** You can use up to five devices with the same not.bot identity. The Devices screen in the More menu lists all paired devices by name. ### **Adding a device** On your existing device: 1. Open the Devices screen and tap "Add Device." 2. Authenticate with your biometric or device passcode. 3. Enter a name for the new device. 4. The app displays a JAB code and instructions to scan it from the new device. On the new device: 5. Install the not.bot app and open the Devices screen. 6. Tap "Add as New Device." The app opens the camera. 7. Scan the JAB code displayed on the first device. 8. Enter your recovery password. 9. The app fetches your aliases, credentials, and settings from the Recovery Server. Signature history does not transfer between devices. Each device keeps its own history of signatures created and scanned on that device. Aliases, contacts and certain other information is shared across your devices. ### **Resetting devices** Reset clears all devices except the one you are using. Open the Devices screen, tap "Reset Devices," and authenticate with your biometric or device passcode. Reset is a rekey operation. The app changes the cryptographic keys controlling your root DID and alias DIDs on the blockchain, which requires interaction with the Recovery Server. The root DID rekeys immediately, rendering all other devices unusable. Alias DIDs rekey over the following 24 hours. While an alias is waiting to be rekeyed, it appears with a red bar on the left in any alias list, indicating it is unavailable. (The same red-bar indicator appears during recovery while alias DIDs are being restored.) When someone opens the app on a device that was reset out, the app detects that its keys are no longer valid. It offers two options: recover onto this device (using the recovery flow) or add the device back to the multi-device set (using the add-device flow). If the user adds the device back to the same user's set, signature history on that device is preserved. If the user attempts to add it to a different user's set, the app returns an error. If the user does not recover or re-add the device, the app stays on this prompt. To start over from scratch on that device, the user must delete and reinstall the app. ## **Recovery** Recovery restores your identity after you lose all your devices. The process takes approximately five days and requires your recovery password (set during enrollment or changed in the app) and authorization from your Recovery Server operator. Recovery proceeds in stages. Your root DID recovers first, completing 48 hours after initiation if no one cancels. Over the next 24 hours, your alias DIDs are submitted for recovery; each alias takes 48 hours. You can use the app once your first alias completes, while remaining aliases show as pending. The 48-hour delay is a safety mechanism. If someone initiates a malicious recovery (using a stolen passport and guessed password), the legitimate owner has 48 hours to cancel it. Canceling requires authorization from a Recovery Server operator at a verification level equal to or higher than the original enrollment level. Even if a malicious recovery completes, the legitimate owner can recover the identity back to themselves. Julia Social is currently the only Recovery Server operator. The plan is to open-source the Recovery Server and support third-party operators, including 2-of-3 multi-agent arrangements where any two of three chosen agents are required to authorize recovery. ## **Settings** The More menu provides access to settings that control privacy, network, and support features. ### **Network** Three options for blockchain access: **Public nodes** connects directly to the Chia network through publicly available nodes. The app displays connected node count and addresses. This is the default, as it best protects users' privacy. Julia Social cannot see which blockchain queries you make. **Julia Social** routes blockchain queries through Julia Social's infrastructure. This node is often faster than public nodes and can provide a better user experience. **Private nodes** connects to nodes you specify. Best for advanced users or organizations running their own Chia infrastructure. ### **Privacy** **Show Hidden Aliases** reveals hidden aliases and their signatures. Requires a biometric or device passcode to enable. Aliases re-hide when the app closes. **Enable Data Collection** controls anonymous telemetry. Off by default. When enabled, the app collects anonymous usage statistics. It does not collect identifying information about you or about the signatures you scan. The app never collects crash logs, to avoid any risk of capturing sensitive user data. ### **Support** Access to diagnostic tools (log viewing and clearing), the support email ([support@julia.social](mailto:support@julia.social)), enhancement suggestions ([better@julia.social](mailto:better@julia.social)), recovery documentation, and your root DID. The root DID is the foundational identifier for your identity on the blockchain. You should never need it during normal use, but it is available for troubleshooting and support interactions. The not.bot App log does not include any identifying information. The log is never sent directly to Julia Social. If you choose to view it, you can download it at any time. If you choose to share it as part of working with Support, you can download it, review it, and then send it to Support. You can also clear the log at any time. ## **Leaving not.bot** There is no formal account deletion feature. Your identity is a decentralized identifier on a public blockchain; it cannot be erased. Deleting the app removes all local data from your device: your enrollment information, your aliases, your contacts, your history. Without initiating recovery, the identity is abandoned. Nobody can use it, and Julia Social cannot access the underlying data. If you want to return, install the app and go through the recovery process using your passport and recovery password. ## **Related documents** - [Overview](https://not.bot/learn/overview/), the landing page for the technology documentation - [Content Provenance & Digital Signatures](https://not.bot/learn/content-provenance/), how signatures work and why visible signatures matter - [Human Verification & not.bot Verify](https://not.bot/learn/human-verification/), the enterprise buyer's guide to not.bot Verify - [Privacy Architecture](https://not.bot/technology/privacy/), what each party can and cannot learn - [Security Model & Known Weaknesses](https://not.bot/technology/security/), testable security claims and known limitations - [Identity Architecture](https://not.bot/technology/identity-architecture/), how DIDs, aliases, and ownership work; the identity model continues in [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/), [Delegation and Organizational Identity](https://not.bot/technology/delegation/), and [Recovery](https://not.bot/technology/recovery/) --- > **honest.bot: Verifiable Agent Identity** — https://not.bot/learn/honest-bot/ · Markdown: https://not.bot/learn/honest-bot.md · Updated 2026-06-10 # **honest.bot™: Verifiable Agent Identity** People talk about AI agents as if they are individuals. They give them names. They describe what "the agent" did. They delegate tasks the way they would to a new hire. The metaphor is powerful, and it is wrong. An AI agent is a process. It might run on one server or fifty. It might be a single instance or one of thousands sharing the same credentials. It has no persistent self, no legal standing, and no capacity for accountability. If it sends an email it should not have sent, nobody can prove which process did it, who authorized it, or whether the "agent" that sent the email is the same "agent" the user configured an hour ago. The gap between what people assume about agents and what agents are will define the next generation of security failures. honest.bot closes that gap. ## **The missing security principal** Enterprise identity systems are built on a concept called a security principal: a unique, identifiable entity that authenticates, receives authorization, and generates an audit trail. A user account is a security principal. A service account is a security principal. A certificate-bearing device is a security principal. An AI agent, as deployed today, is not a security principal. It borrows credentials from the human who configured it. It authenticates to downstream services using the human's OAuth tokens, the human's API keys, the human's session cookies. The downstream service cannot distinguish the agent's actions from the human's. No audit trail, policy engine, or access control system can reliably differentiate "the human did this" from "the human's agent did this." This is the equivalent of handing your badge to a contractor and having every door log your name when they walk through. honest.bot makes every agent a proper security principal. Only one process in the world can have a particular honest.bot-credentialed, cryptographically verifiable identity. It authenticates on its own behalf. It carries its own permissions. It generates its own audit events. And its authority traces, through a cryptographic delegation chain, back to a specific alias of a not.bot™-verified human. ## **How honest.bot works** Julia Social and the agent produce the honest.bot credential through multiparty computation (MPC). When an agent process starts, it and Julia Social jointly compute a value that neither party can derive alone. That value becomes the agent's credential. Julia Social confirms that no other process holds a credential for the same identity. The MPC binds a secret to the running process's memory in a way that cannot be extracted from the credential itself. A verifier confirms the credential by performing the same MPC interaction with the agent. If the agent holds the original secret, verification succeeds. No traffic goes to Julia Social during verification. The verifier and the agent handle it between themselves, plus a blockchain check that the credential has not been revoked. Verification produces cryptographic proof that the presenting process is the one and only current holder of its identity. A second process attempting to present the same credential fails the MPC because it does not possess the secret. This is process binding, and it solves a problem that key-based identity cannot. A private key can be copied to ten servers, and all ten can assert the same identity at the same time. An honest.bot credential cannot. The guarantee is not "whoever has this key is the agent" but "this specific running process, right now, is the agent." For ephemeral, replicable, distributable processes, this is the correct binding. ## **What an agent presents** An honest.bot presentation answers four questions, each expressed as a standard `did:julia` verifiable credential: **Who is this agent working for?** The delegation chain traces the agent's authority back to one specific alias of an accountable not.bot-verified human. The chain is included in every presentation. **What is this agent permitted to do?** Capability credentials enumerate the agent's permissions. Each credential is scoped by property and value, time-bounded, and revocable. **What task has this agent been assigned?** A task credential describes the agent's current mandate. Verifiers can check whether a requested action fits the stated purpose. **What technology is this agent using?** A technology stack credential, issued by the platform operator, attests to the runtime, model, and tooling. This credential is non-delegatable: the agent can present it but cannot pass it to another agent. These are ordinary `did:julia` credentials. There is no parallel credential system for agents. The full power of Julia Social's credential infrastructure, including antecedents, subdelegation control, property limitation, time-bounding, and mass revocation, applies to agent governance with no modification. ## **Delegation and attenuation** An orchestrator agent delegated authority by a human can subdelegate narrower slices to specialist sub-agents. A research agent gets read access to a specific data source. A purchasing agent gets spending authority on a specific set of coins. A drafting agent gets permission to create documents but not to send them. Each sub-agent receives only the permissions it needs, and each permission is narrower than or equal to the one the orchestrator holds. This attenuation is a cryptographic constraint, not mere policy. A verifier receiving a presentation from a sub-agent can inspect the full chain and confirm that every delegation falls within the scope of its parent. If an orchestrator issues a credential beyond its own scope, the credential fails verification. Revocation cascades. If a sub-agent misbehaves, its parent revokes the delegation. If the parent is compromised, the root human voids the parent's delegation, and every credential downstream of it dies. A single blockchain transaction can directly revoke up to 512 credentials at once, against a revocation bitfield that holds up to 131,072 separately-revocable credentials, and indirectly revoke many more. ## **Agents as adversaries: containment architecture** honest.bot defines the identity layer. Containment, making sure the agent cannot bypass its identity, is a separate problem. Julia Social's implementation is the adversarial appliance: a confidential virtual machine (AMD SEV-SNP or Intel TDX) that treats the agent inside it as the adversary with the presumed intent to bypass containment. The appliance runs four cooperating services alongside the agent. An ingress daemon accepts input from only one authenticated not.bot owner or that human’s delegates. An identity daemon holds the signing key, sealed to the VM's attestation measurements, accessible only through a signing operation over a Unix domain socket. The agent can inspect the credentials it holds, but can never see the private key. An MPC gateway is the agent's only path to the outside world: it provides a server to the agent, and attaches at least its honest.bot and delegated not.bot credentials to every outbound transaction call. An audit daemon maintains an append-only log of every action, anchored to the appliance's attested identity. The agent inside the VM cannot directly reach the internet. It cannot open arbitrary sockets. It cannot read the signing key. Its only way to interact with external services is through valid MCP tool calls, routed through the gateway. The architecture distinguishes enforcement (host firewall, confidential VM, protocol termination, cryptographic verification at counterparties) from convenience (disabled tools, system prompt instructions, model tendencies). Enforcement holds even if the agent is fully compromised by prompt injection, poisoned tool results, or adversarial fine-tuning. ## **MCP-I: the emerging protocol layer** The Model Context Protocol (MCP) gives agents a standardized way to connect to external tools and data sources. MCP-I (https://modelcontextprotocol-identity.io/) extends MCP with cryptographic identity and delegation, enabling agents to prove who they represent and what they are authorized to do. MCP-I defines the protocol-layer questions: how an agent proves identity, how delegation credentials travel with requests, how edge services verify agent authority, and how audit logs capture agent actions. honest.bot's adversarial appliance MCP gateway supports two types of downstream endpoint: MCP-I servers that accept honest.bot presentations directly, and gateway servers that translate honest.bot assertions into conventional credentials (API keys, OAuth tokens) for services that do not yet understand agent identity. MCP and MCP-I address how agents connect. honest.bot addresses what they connect with: a process-bound identity that proves uniqueness, a delegation chain that proves authority, and a containment architecture that prevents bypass. The protocol layer and the identity layer are complementary. MCP-I without a strong identity layer routes requests but cannot guarantee who is making them or that the requester is a single, unique process. honest.bot without a protocol standard requires custom integration at every service boundary. ## **Governance and auditability** Security principals generate audit trails. If your agent framework cannot produce one, regulators and customers will notice. honest.bot generates audit material at every layer. **Identity lifecycle.** Every credential issuance and every delegation event is cryptographically signed. A compliance team can reconstruct who authorized which agent, when, with what permissions, and when those permissions were revoked. **Runtime actions.** The adversarial appliance's audit daemon logs every inbound request, every agent action, every outbound call, and every signing operation in an append-only log. Signed checkpoints anchor the chain to the appliance's attested identity. **Delegation provenance.** Every honest.bot presentation includes the full delegation chain. An auditor examining a specific agent action can trace authority from the acting sub-agent, through the orchestrator, back to the human who initiated the chain. **Single human owner.** Every honest.bot container accepts input from only one not.bot-verified human. Honest.bot agent behavior cannot be altered by commands or context provided by any third party. An honest.bot agent is an extension of that one human’s identity. This audit trail serves compliance, but it also gives organizations a concrete answer to the question regulators and customers will ask: when your agent did X, who was responsible? honest.bot's answer is a cryptographic chain that any party can verify independently. ## **Human accountability: the non-negotiable root** Every honest.bot delegation chain terminates at a not.bot-verified human. The system does not permit autonomous agents with no accountable root. An agent has no legal standing and no capacity for consequence. It cannot be sued, fined, or imprisoned. Accountability must rest with a person who can bear those consequences. honest.bot makes the relationship between agent and accountable human explicit and verifiable. Any verifier, at any point, can inspect the presentation and determine who is responsible. The delegation chain uses aliases, not real-world identities. The accountable human is identified by a specific not.bot alias, preserving the privacy architecture described in the [Privacy Architecture](https://not.bot/technology/privacy/). If law enforcement needs to identify the person behind the alias, the same legal process described in [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/) applies. ## **How people think about bots, and what they get instead** People think of bots the way they think of employees. Each bot has a name. It does things on your behalf. You trust it with specific tasks and expect it to stay within bounds. You want to know what it did while you were away. If it breaks something, you want to know which bot did it. Current agent infrastructure delivers none of this. Most agents authenticate with borrowed credentials. Multiple agents can share a single identity. An agent's "name" is a UI label, not a verifiable identity. No service on the receiving end can tell whether it is talking to the agent the user configured, a copy of that agent running on a different server, or a different agent entirely using the same API key. honest.bot delivers the model people already assume. Each agent is a unique, identifiable entity. It has its own credential that no other process can use. Services receiving its requests can verify its identity, check its permissions, trace its authority back to a specific human, and log its actions under its own identity rather than its owner's. "My bot, doing my tasks, accountable to me" is how the system works, not a convenient fiction about what the system does. ## **Where honest.bot fits in the landscape** The industry is converging on the recognition that agents need identity. NIST launched its AI Agent Standards Initiative in February 2026, publishing a concept paper on agent identity and authorization. The initiative asks whether existing identity standards (OAuth, SPIFFE, OpenID Connect) can be adapted for agents. Products and frameworks are emerging from multiple directions. **Existing IAM adapted for agents.** Some companies are extending enterprise identity management to treat agents as first-class security principals within existing OAuth and OIDC frameworks. This approach has the advantage of compatibility with deployed infrastructure. It inherits a limitation: these systems bind identity to keys and tokens, not to running processes. Two instances sharing the same token are indistinguishable. Delegation is constrained by OAuth's single-hop model, and multi-hop delegation chains remain an unsolved problem in the standard. **Verifiable credentials for agent authentication.** Others are applying decentralized identity and verifiable credentials to agent-to-user and agent-to-agent authentication. Agents present verifiable credentials to prove their identity. Users present verifiable credentials to share data with agents under explicit consent. These solutions address the authentication question with standards-based credentials, but do not provide process-binding. The credential proves that an agent possesses a valid credential, not that the presenting process is the unique current holder. **Specification-layer efforts.** MCP-I adds identity and delegation semantics to the MCP protocol. It defines how agents prove identity, carry delegation credentials, and subject themselves to edge verification. AgentDID, a recent academic proposal, explores decentralized identifiers for autonomously created agents with self-managed identities. Both address the protocol question. Neither specifies a mechanism for proving that a given process is the sole current holder of its identity. **Where honest.bot differs.** honest.bot is the only system that provides all of the following: process binding through MPC (not key binding), verification without contacting the issuer, delegation chains that terminate at a verified human, cascading revocation, a containment architecture that enforces identity even against a compromised agent, and a shared identity infrastructure with human identity (the same `did:julia` system, the same blockchain, the same credential primitives). The distinction that matters most is process binding. Every other system in the landscape binds agent identity to a credential or key that can, in principle, be presented by any process that holds it. honest.bot binds identity to a specific running process through MPC. The credential cannot be extracted, copied, or shared. If the process terminates, the credential becomes available for reissuance, but no other process can use it in the interim. ## **Production today, product tomorrow** honest.bot's core mechanism is in production. Every not.bot Verify signature server acquires an honest.bot credential at startup. No two Verify servers in the world can hold the same credential at the same time. The not.bot app verifies the Verify server's honest.bot credential on every interaction, without contacting Julia Social. This is a working deployment of the MPC protocol, the credential issuance flow, the revocation mechanism, and the verification protocol. The honest.bot product, the SDK, the adversarial appliance, and the ability for third parties to deploy their own honest.bot-credentialed agents, is targeted for Q4 2026 deployment. The product is in development. The scope extends beyond LLM-based agents. Any automated process, whether an RPA bot, a trading algorithm, a legacy integration service, or an IoT controller, can be an honest.bot-credentialed entity. The framework applies wherever accountability for automated action matters. ## **Further reading** For the identity infrastructure that honest.bot shares with human identity, see [Identity Architecture: DIDs, Aliases, and Ownership](https://not.bot/technology/identity-architecture/) and [Delegation and Organizational Identity](https://not.bot/technology/delegation/). For the human accountability model that anchors every delegation chain, see [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/). --- *honest.bot™ is a trademark of Julia Social. The visible-signature technology used across the not.bot product family is patent-pending.* --- > **not.bot Use Cases: Index** — https://not.bot/learn/use-cases/ · Markdown: https://not.bot/learn/use-cases.md · Updated 2026-06-14 # **not.bot™ Use Cases: Index** This index is the top-level catalog of not.bot use cases: each use case in one line, grouped by category, with links to the six detail documents that give each its full treatment. The catalog grows as new use cases surface. --- ## **Mechanisms** The use cases draw on a small set of underlying mechanisms. The definitions here are referenced from each detail document. **Signature.** A cryptographic stamp on content or an action, gated by a biometric or device passcode at the moment of signing, bound to a passport-verified human. Visible as a QR or JAB code embedded in the content. **Site Pass.** A per-human, per-site identifier derived through multiparty computation. The same human cannot create two Site Passes for the same site even using different aliases. **Credential.** A verifiable claim issued by an identity (human or Business DID) about another identity. Credentials carry validity windows, scope, and revocation rules. Holders present credentials to verifiers on a selective basis. **Alias.** A separate identity under the same passport-verified human, cryptographically unlinkable to the human's other aliases. Lets a person maintain different presentations across different contexts. **Business DID.** An organizational identity governed by human signers through delegation. Actions under a Business DID trace back to a specific human key-holder. --- ## **Categories** ### **Enterprise** → [Enterprise Use Cases](https://not.bot/learn/use-cases-enterprise/) - **Human-level permissions auditing.** Map all permissions a specific human holds across systems without operational reconciliation. - **Prevent account sharing.** Bind authentication to biometric or device-passcode verification of a passport-verified human. - **Comprehensive offboarding.** Close all accounts associated with a departing human in one operation. - **Banning across an organization.** Surface a banned human at next authentication attempt, regardless of agency or business unit. - **Physical access control.** Replace badges and key fobs with cryptographic identity gated by a biometric or device passcode at each door read. - **Cross-system authorization.** Issue permission credentials to employees through Business DIDs. - **Time-limited vendor and contractor access.** Built-in expiration removes the offboarding ticket. - **Hiring and recruiting.** Verifiable employment history, education, certifications, and reference letters. - **Customer service authentication.** Replace knowledge-based authentication with cryptographic identity at support contacts. - **Supply chain attestations.** A verified human signs at each handoff for chain of custody. ### **Content signing** → [Content Signing Use Cases](https://not.bot/learn/use-cases-content-signing/) The unifying thesis: once a person signs every piece of content they publish, unsigned content is fake by default. Defensive archetypes: - **Influencers.** Protect sponsor revenue against deepfake competitor endorsements. - **Politicians.** Defend against deepfake-driven voter manipulation. - **NIL.** College athletes and teams protect monetizable likeness from AI generation. - **Journalists.** Protect the trust position that deepfakes exploit. - **Business leaders.** Close the stock-manipulation attack window. - **Celebrities.** Defend against reputational, financial, and sexual exploitation. - **Authors.** Counter AI-generated books in known authors' names. - **Musicians.** Counter AI-generated tracks in artists' voices. - **Voice actors.** Establish authenticity against AI clones of professional output. - **Creators on YouTube, TikTok, Twitch, Substack.** Same dynamic as influencers, broader scope. - **Legal documents.** Travel-with-document signatures verifiable outside any platform. - **Software releases.** Signed commits and releases with consumer-grade UX. - **Brand-issued content.** Verifiable origin point for marketing and announcements. - **Pseudonymous-but-verified writing.** Same human across articles, identity not disclosed. - **AI-generated content disclosure.** Human signs to take responsibility for AI output. Licensing model: - **Likeness licensing for public figures.** Authorized AI studios sign generated content with valid license credentials. - **Animated character licensing.** IP rights-holders issue usage credentials for their characters. - **Posthumous likeness licensing.** Estates issue credentials for deceased celebrity likeness. - **Voice-only licensing.** Audiobook and dubbing applications, pending audio signature support. - **Athlete game licensing.** Game studios license athlete likenesses with cryptographic enforcement. ### **Verified humanness** → [Verified Humanness Use Cases](https://not.bot/learn/use-cases-verified-humanness/) - **CAPTCHA replacement.** Cryptographic answer to "are you human?" replacing image puzzles and behavioral profiling. - **Sybil defense.** One-human-one-account at the protocol layer through Site Passes. - **Surveys and polls.** Sybil defense plus verified humanness plus demographic credentials without PII. - **Catfishing prevention on dating apps.** Verified humanness with selective identity disclosure. ### **Credentials** → [Credential Use Cases](https://not.bot/learn/use-cases-credentials/) Marks of distinction: - Diplomas and degrees. - Professional certifications. - Industry and academic awards. - Conference attendance. - Course completions. - Athletic achievements. - Video-game achievements. - Military service records. - Loyalty program status. Qualifiers: - Background check status. - Credit score brackets. - Income and employment verification. - Bondability. - Insurance coverage. - Professional license status. - Driver's license validity. - Security clearance levels. Self-attested (the signature lets the end recipient validate that each claim reads as the user wrote it): - Avatar and bio. - Pronouns. - Sexual orientation (dating context). - Hobbies and interests. - Relationship status. - Lifestyle claims. - Portable profile data. Plus: - **Age verification.** MPC-derived from passport data, presented as a signed boolean for the requested threshold without revealing birthdate. ### **Trust surface** → [Trust Surface Use Cases](https://not.bot/learn/use-cases-trust-surface/) Signed links and signed action prompts: - Parking, transit, and metered payment QR codes. - Restaurant menu QR codes. - Wi-Fi connection QR codes. - Charity donation QR codes. - Crypto payment QR codes. - Tip and service-worker payment codes. - Event and conference signage. - Museum and tourist information codes. - Vaccination and health-pass QR codes. - Real estate yard-sign QR codes. Authorized agent verification: - Manufacturer authorized repair. - Pharmaceutical authorized distributors. - Software authorized resellers. - Authorized parts dealers. - Franchise authentication. - Insurance authorized adjusters and contractors. - Authorized used-car dealers. - Charity authorized fundraisers. - Realtor brokerage authentication. - Tax preparer authentication. Marketplaces and gig economy: - Verified seller and buyer identity. - Banned-seller enforcement that survives account recreation. - Verified reviews tied to verified purchases. - Portable seller reputation. - Counterfeit-listing prevention. - High-value transaction buyer verification. - In-person handoff mutual verification. - Driver and customer mutual verification. - Background check status as qualifier credential. - Profile-to-person identity matching at handoff. ### **Industry verticals** → [Industry Verticals Use Cases](https://not.bot/learn/use-cases-industry-verticals/) - **Telehealth.** Two-sided verification: patient verifies provider, provider verifies patient. - **Financial services KYC.** Compliance-grade identity verification without PII storage. - **Insurance fraud prevention.** Signed claims, beneficiary verification, signed witness statements. - **Real estate transactions.** Verified parties at each step close the wire fraud surface. - **Remote online notarization.** Cryptographic identity replaces webcam ID checking. - **Crowdfunding.** Verified creator, sybil defense, verified beneficiary. - **Job boards.** Verified human candidates and employers, anti-AI-spam differentiation. - **Childcare and dependent care drop-off.** Time-limited authorization credentials for pickup. - **Estate planning and digital inheritance.** Signed directives, post-mortem credential transfer. - **Academic integrity.** Signed homework and exam submissions verify human engagement. - **Remote exam proctoring.** Signed exam sessions verify the test-taker is the enrolled student. - **Confidential source protection.** Verified humanness for journalist sources without identity disclosure. --- > **not.bot Use Cases: Enterprise** — https://not.bot/learn/use-cases-enterprise/ · Markdown: https://not.bot/learn/use-cases-enterprise.md · Updated 2026-06-14 # **not.bot™ Use Cases: Enterprise** This document covers enterprise authentication, authorization, hiring, and operational use cases. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. --- ## **The unifying problem** Existing enterprise identity systems map permissions to accounts, then attempt to associate accounts with humans through HR records, SCIM, and downstream connectors. The mapping is operational and breaks under shadow IT, contractor pipelines, and account sharing. not.bot moves the human-to-permissions binding into the authentication layer itself. Existing analogs include identity governance platforms, platform authenticators, HR-driven offboarding workflows, and contractor management vendors. Each approximates a property that not.bot delivers as a native feature of the authentication itself. No existing authentication product offers these as inherent properties. Existing enterprises approximate them by stacking IDPs, IGA tools, HR systems, and background-check vendors through cross-system reconciliation. not.bot is the first authentication product where these capabilities fall out of the cryptographic identity model itself. --- ## **Authentication and access** ### **Human-level permissions auditing** Today's identity governance tools attempt a "person view" of permissions by reconciling accounts across systems. The reconciliation breaks whenever an account exists outside the integrations or whenever a human controls multiple accounts. With not.bot, each authentication carries an unforgeable human identity claim through Site Passes. The complete set of permissions a particular human holds becomes a query rather than a reconciliation project. Auditors get a definitive person-view instead of a best-effort reconstruction. **The business value:** Audit preparation that takes weeks of cross-system reconciliation today compresses to a single query. SOX, HIPAA, and SOC 2 audits become faster and more reliable. Security teams can identify orphaned permissions and over-provisioned accounts in real time rather than discovering them in post-incident forensics. Organizations that run hundreds of SaaS applications can answer "who has access to what?" with confidence for the first time. ### **Prevent account sharing** Users share credentials when deadlines or business needs make it expedient. Even occasional sharing collapses the permissions model because no one can say with confidence who has access to what. Platform authenticators implementing the FIDO2 standard get close by gating credentials with biometric authentication on a device. The device can still be handed over with the biometric tied to that device rather than to the human. not.bot binds authentication to biometric or device-passcode verification of a passport-verified human. The credential cannot be passed to another person. **The business value:** Shared accounts are a leading vector for insider threat incidents and compliance failures. Regulators treat account sharing as a control deficiency. Eliminating it closes audit findings, reduces insider-threat exposure, and gives security teams a definitive answer to "who did this?" after any incident. In regulated industries (healthcare, financial services, defense), this is a requirement that current tools can approximate but cannot guarantee. ### **Comprehensive offboarding** When an employee leaves, every account they touched needs to close. Today's offboarding depends on the same operational HR-driven mapping as auditing and breaks the same way. Banning the human's identity in the company namespace makes every account that authenticates through not.bot unusable in one operation. **The business value:** Incomplete offboarding is one of the most common findings in security assessments. Lingering access costs organizations an average of weeks of remediation after each departure, creates breach exposure windows, and generates compliance findings. One-operation offboarding eliminates the entire category. HR, IT security, and compliance teams stop chasing account closures across dozens of systems and move the process from a multi-day checklist to a single action. ### **Banning across an organization** A contractor fired for cause at one division and re-hired through a different agency at another division is a routine large-organization failure. HR blacklists fail through name variations, agency changes, and gaps in documentation; non-I-9 hires are the weakest case. With not.bot Site Passes scoped to the organization, the banned human's identity surfaces at the next attempt to authenticate, regardless of which agency or business unit re-engaged them. The check happens at authentication time rather than after the fact. **The business value:** Large organizations spend significant resources investigating and remediating cases where terminated individuals return through different channels. The cost includes re-onboarding, re-investigation, potential liability exposure, and the original problem that triggered the ban recurring. Catching the banned individual at the door instead of after re-engagement eliminates this entire cycle. For organizations with contractor pools in the thousands, the savings compound with each hiring cycle. ### **Physical access control** Badges and keycards are bearer tokens. Whoever holds the badge gets in. Keycards get lent, stolen, and cloned. Mobile wallet credentials improve on this by binding to a device, but the device can be unlocked and handed off, and the credential ties to the device rather than the human. not.bot binds access authority to a passport-verified human. The door requires a biometric or device passcode at each read. Audit logs record the actual entrant, not the badge holder. Additional capabilities the cryptographic model enables: - Instant revocation by melting a credential singleton, with no waiting for offline panels to sync. - Narrow time-limited visitor passes signed by an employee who remains accountable for the visitor. - Signed audit trails resistant to tampering by anyone with admin access to the PACS. **The business value:** Physical security breaches traced to shared, stolen, or cloned badges represent a persistent liability for corporate campuses, data centers, and sensitive facilities. Defense contractors, pharmaceutical manufacturers, and financial institutions face regulatory requirements for individual-level access accounting that badge systems cannot provide. not.bot delivers individual-level audit trails that satisfy the strictest regulatory frameworks while reducing the operational cost of badge management, replacement, and investigation. --- ## **Authorization** Authorization differs from authentication. Authentication says who you are. Authorization says what you can do. Today each system runs its own permission model (directory groups, identity-provider entitlements, cloud IAM roles, application-specific roles) and they drift out of sync. ### **Cross-system authorization with single-point revocation** The Business DID issues authorization credentials to the employee's identity. The credential travels with the human across systems. When the employee authenticates to a downstream system, they present the relevant authorization credential. Concrete examples: - A nurse's hospital privileges credential presented to the EHR. - A lawyer's case-specific access credential presented to document management. - A consultant's client-engagement credential presented to collaboration tools. - A radiologist's read-authority credential presented to PACS systems. Revocation happens once at the credential layer (melt the singleton, or flip the revocation bit) and propagates to every system the credential reaches. This connects to human-level permissions auditing: that one is about visibility; this one is the issuance and lifecycle mechanism that makes the visibility work. **The business value:** Permission sprawl across systems is a top-five finding in most enterprise security assessments. Organizations today manage each system's permissions in isolation, creating inconsistencies that widen over time. A single credential layer reduces the number of permission-management surfaces from dozens or hundreds to one. Revocation that propagates across all systems in real time eliminates the gap between "permission revoked" and "access removed" that attackers exploit in lateral-movement campaigns. ### **Time-limited vendor and contractor access** Credentials with built-in expiration dates handle the contractor lifecycle that drifts in legacy systems. The credential expires; no offboarding ticket required. This eliminates the common pattern of vendor accounts that linger for years after the engagement ends. **The business value:** Vendor and contractor accounts represent one of the largest categories of stale-access risk in enterprise environments. Many organizations discover active contractor accounts months or years after engagements ended. Automatic expiration removes an entire class of forgotten-access vulnerabilities without requiring any human action at contract end. --- ## **Hiring and recruiting** Background check status, employment verification, education credentials, professional licensure, reference letters signed by the references themselves. The hiring process today depends on slow, expensive, and bypassable verification services. AI-generated resumes flood applicant tracking systems, and remote-work claims invite geographic and identity fraud. Verifiable credentials at each step reduce time-to-hire and improve verification quality. A candidate presenting a degree credential signed by the issuing university, an employment credential signed by their previous employer, and a professional license credential signed by the licensing board removes the need for the hiring company to chase down references and call registrars. Candidates with verified credentials stand out against the AI-generated resume tide. **The business value:** Background verification costs $50-$200 per candidate through third-party services and takes days to weeks. A mid-size company hiring 500 people per year spends six figures on verification alone, plus the productivity cost of delayed start dates. Verifiable credentials shift verification from an asynchronous investigation to an instant cryptographic check. Hiring managers get higher confidence, faster, at lower cost. For industries where credential fraud carries safety risk (healthcare, aviation, education), the value extends beyond cost savings into patient and public safety. For job boards as platforms (where the buyer is the platform operator rather than the hiring company), see [Industry Verticals Use Cases](https://not.bot/learn/use-cases-industry-verticals/). --- ## **Customer service authentication** Knowledge-based authentication ("what's your mother's maiden name") breaks under data breaches and social engineering. Banks, telecoms, insurers, and utilities lose money and customer trust to account takeover through their support channels. Cryptographic identity at each customer service contact closes the impersonation surface. The customer signs in to the support session. The agent verifies the customer's identity at session start. Sensitive actions (address changes, beneficiary updates, large transfers) require fresh signatures rather than knowledge questions. **The business value:** Account takeover through social engineering of customer service agents costs financial institutions billions per year. Each incident carries direct fraud loss, investigation cost, customer remediation, and reputational damage. Replacing knowledge-based authentication with cryptographic identity eliminates the most common attack vector for phone-channel and chat-channel fraud. Customer satisfaction improves too: verified customers skip the "security questions" friction that legitimate callers find tedious. --- ## **Supply chain attestations** A verified human at each handoff signs for chain of custody. Pharmaceutical supply chains, food safety regulation, regulated chemicals, defense procurement, conflict-mineral certification, and high-value logistics benefit from per-handoff cryptographic attestation tied to verified humans rather than account-level credentials that get shared across shifts. The audit trail traces back to specific humans rather than to "warehouse account 47." When a contamination, theft, or compliance failure happens, the investigation has a verified chain to follow. **The business value:** Supply chain contamination events, diversion incidents, and compliance failures trigger investigations that cost millions and take months. The investigation stalls at the point where an account-level credential was shared across a shift and no one can determine which human handled the product. Per-handoff human attestation compresses investigation timelines, strengthens regulatory compliance (FDA DSCSA, EU FMD, DoD DFARS), and creates a deterrent effect: the knowledge that each handoff is cryptographically attributed to a specific person reduces the incentive for diversion and tampering. --- > **not.bot Use Cases: Content Signing** — https://not.bot/learn/use-cases-content-signing/ · Markdown: https://not.bot/learn/use-cases-content-signing.md · Updated 2026-06-17 # **not.bot™ Use Cases: Content Signing** This document covers content signing applications across creator types, content categories, and licensing models. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. [Content Signing & not.bot Sign My Work](https://not.bot/learn/content-signing/) describes the product these use cases run on. --- ## **The defensive thesis** Once a person signs every piece of content they publish, unsigned content is fake by default. The signature regime inverts the deepfake economy. Detection becomes unnecessary because verification is positive rather than negative. Audiences participate in the defense. Followers who recognize unsigned content as suspect become a distributed immune response that catches deepfakes before they go viral. Platforms that surface signature status in their UI amplify the effect. The first batch of signed content establishes the baseline. Each subsequent signed asset reinforces it. The archetypes below share this mechanism but vary in stakes, adversaries, and beneficiaries. --- ## **Defensive archetypes** ### **Influencers protecting sponsor revenue** Influencer revenue depends on trustworthy association with the products they endorse. Deepfakes that show the influencer praising competitors, attacking the sponsor, or in misconduct that never happened destroy that trust and the revenue with it. Signing sponsored content protects both the sponsor relationship and the influencer's ability to monetize their following. Sponsors gain a verifiable channel to confirm their campaigns are running through the actual influencer rather than an impersonator. **The business value:** The influencer marketing industry generates over $20 billion a year. Deepfakes that impersonate influencers threaten both the influencer's income and the sponsor's brand. A signed content regime protects the revenue stream for both parties while giving sponsors verifiable proof of campaign delivery. Influencer agencies can offer signed content as a premium service tier that commands higher rates. ### **Politicians defending against deepfake-driven manipulation** Deepfakes manufacture statements, endorsements, and behavior the candidate did not produce. The technique is potent for foreign influence operations because attribution to the originating actor is hard. A signed-by-default communications regime lets supporters and journalists dismiss unsigned clips as fake on sight. Campaigns that establish a signing baseline early in a cycle gain protection that compounds as the cycle progresses. **The business value:** A single deepfake released at the right moment can shift an election's trajectory. Campaigns that sign all official communications create a verification baseline that inoculates against October surprises. The protection extends to the party, the PAC, and allied organizations that adopt the same signing practice. Foreign adversaries lose the ability to fabricate statements that survive first contact with an informed audience. ### **NIL (Name, Image, Likeness)** College athletes and teams now monetize their NIL. AI generation undercuts the entire revenue stream by producing images, videos, and merchandise designs at zero marginal cost. Athletes already understand the licensing concept through "officially licensed merchandise" tags on physical goods. not.bot signatures are the digital equivalent: a cryptographic certificate of authenticity that travels with the content. Universities issuing NIL credentials to their athletes can attest to the contractual relationship at the same time. **The business value:** The NIL market crossed $1 billion within two years of becoming legal. AI-generated athlete content dilutes the value of legitimate NIL deals by flooding the market with unauthorized material. Signed NIL content protects both the athlete's earning power and the brand's investment. Athletes who sign their endorsements create a verifiable premium that unsigned content, real or fake, cannot match. ### **Journalists defending their position of trust** Sanjay Gupta's likeness was hijacked to sell Alzheimer's pills. Anderson Cooper has been used in similar schemes. Journalists hold a position of trust, and that trust is the asset deepfakes exploit. Signed reporting, signed appearances, and signed bylines let viewers verify what comes from the journalist. Networks that establish signing as a standard for their on-air talent create a defense that protects both the journalist's reputation and the network's credibility. **The business value:** News organizations' primary asset is audience trust. A deepfake that uses a trusted journalist's face to sell fraudulent products or spread disinformation damages the journalist's reputation, the network's brand, and the credibility of journalism itself. Signing costs a fraction of the legal fees networks spend pursuing deepfake takedowns, and works in seconds instead of weeks. ### **Business leaders defending against stock manipulation** A fake statement from a CEO can move a stock ten percent in either direction before the company can respond. The actor who creates and times the viral clip captures most of the value before the correction. Signed communications close the attack window by making the official channel verifiable in real time. Investor relations teams, market makers, and journalists can verify a CEO statement on the spot rather than waiting for the company to issue a denial. **The business value:** Stock manipulation through fake executive statements is a growing threat as deepfake quality improves. A ten-percent swing on a $50 billion company represents $5 billion in market cap movement triggered by a fabricated video. Signed executive communications protect shareholder value, reduce the response window from hours to seconds, and give the investor relations team a verification tool that closes the gap between false report and correction. ### **Celebrities defending against reputational, financial, and sexual exploitation** Oprah selling diet pills she has nothing to do with. Scarlett Johansson voicing causes she never supported. Taylor Swift as the most-deepfaked human in history, including non-consensual sexual imagery distributed at scale. The exploitation runs across reputation, finance, and sexual imagery. Consistent signing converts the burden of proof: the public expects signed content from these figures, and unsigned content carries no credibility. Celebrities establishing signing baselines early gain the strongest protection. **The business value:** Celebrity brand value, built over decades, can be destroyed in hours by deepfake content. Legal enforcement is slow and cross-jurisdictional. Signing creates a first line of defense that works before lawyers get involved. For talent agencies and management firms, signing protects the entire client roster's earning power. The non-consensual sexual imagery dimension adds a personal safety value that transcends economics. ### **Authors** AI-generated books in known authors' names flood Amazon. The cases of Brandon Sanderson and Jane Friedman made the news. Most authors' cases never do. Signed manuscripts, signed publication metadata, and signed cover-and-title pages give readers a verification path that survives the listing platform's failure to police submissions. Publishers issuing signing infrastructure to their author rosters protect their catalog. **The business value:** Fake books cannibalize real sales, damage the author's reputation, and erode reader trust in the platform. Publishers lose revenue when readers buy counterfeit titles and then leave negative reviews that suppress the real book's ranking. Signed publication metadata gives retailers an automated way to distinguish real from counterfeit listings, and gives readers confidence before they buy. ### **Musicians** AI-generated tracks in artists' voices reached the inflection point with the fake Drake/Weeknd song. Streaming platforms struggle to take down impersonations fast enough. Signed releases and signed performance recordings establish authenticity at the source. Labels and distributors that integrate signing into their release pipelines provide their artists with the defense without requiring per-artist setup. **The business value:** The music industry's revenue depends on artists' identities being exclusive to their work. AI-generated impersonation tracks divert streaming revenue, confuse recommendation algorithms, and erode the scarcity that drives concert demand. Signed releases let streaming platforms auto-flag unsigned tracks claiming to feature signed artists. Labels that adopt signing across their roster protect their entire catalog in one integration. ### **Voice actors** The voice acting profession competes with AI clones of voice actors' own voices. Established voice actors find their work undercut by services that train on their performances and then sell the resulting models. Signed performances let casting directors, audiobook producers, and game studios verify which voice work came from the actual performer. Performance contracts can require signed delivery, creating a record that travels with the work. **The business value:** Voice acting is a $4+ billion industry. AI voice cloning threatens to eliminate the premium that experienced performers command. Signed performance delivery gives casting directors proof of authenticity and gives performers a contractual enforcement tool. Studios that require signed delivery protect themselves against liability claims from performers whose voices were used without authorization. ### **Creators on YouTube, TikTok, Twitch, Substack** Same dynamic as influencers but broader, including the long tail of creators who lack the legal resources of larger figures. Signed content on these platforms gives creators a defense that scales without legal staff. Platforms that surface signature status in their UI accelerate adoption among creators who would otherwise see signing as friction. **The business value:** Millions of creators earn their living on these platforms. Most cannot afford legal representation to fight deepfakes and impersonation. Signing gives independent creators the same verification power that large media companies spend hundreds of thousands per year to enforce through legal channels. For the platforms themselves, surfacing signature status differentiates their creator ecosystem and reduces the content-moderation burden of chasing impersonation reports. ### **Legal documents** Contracts, filings, attestations, notarized statements, and signed declarations carry signatures today through e-signature platforms. Those platforms require the recipient to participate in the same ecosystem and do nothing for documents distributed outside it. not.bot signatures travel with the document and verify outside any platform (patent pending). Legal teams gain document integrity that survives the document moving through email, cloud storage, and printing. **The business value:** E-signature platforms handle signatures within their own ecosystems. Documents that leave those ecosystems (forwarded via email, stored in a different system, printed and re-scanned) lose their verification chain. not.bot signatures are embedded in the document itself and verify against the signer's identity regardless of where the document travels. Law firms, corporate legal departments, and courts gain tamper-evident documents that work in any context. ### **Software releases** Signed commits and signed releases address the supply-chain attack vector that the XZ backdoor exposed. PGP exists for this purpose with thirty years of evidence that consumers will not adopt it. not.bot provides the same property with consumer-grade UX. Open source maintainers gain a verifiable human attribution path for each commit. A bad-actor maintainer's commits become identifiable as the same human across projects, even under different account names. **The business value:** Software supply chain attacks cost the global economy billions per year. The XZ backdoor demonstrated that a single compromised maintainer can threaten critical infrastructure. Signed commits tied to verified humans raise the barrier for long-game infiltration attacks, give downstream consumers a verification path they will use (because the UX works), and let open source foundations identify patterns of suspicious contribution across their project portfolios. ### **Brand-issued content** Marketing materials, product launches, and official corporate announcements gain a verifiable origin point. Brand impersonation campaigns lose effectiveness once consumers expect signed content from the official channel. The Business DID infrastructure pairs with content signing here: the brand's Domain Name credential travels with the signature, so consumers can confirm both the human signer and the company they represent. **The business value:** Brand impersonation costs companies billions per year through fake promotions, counterfeit products, and fraudulent customer communications. Signed brand content gives consumers an instant verification check, reduces the burden on brand-protection teams chasing takedown requests, and builds a consumer expectation that accelerates across the brand's audience. Each piece of signed content reinforces the standard and makes unsigned impersonation less effective. ### **Pseudonymous-but-verified writing** A journalist publishing under a pen name signs each article with the same alias. Readers verify that all articles came from the same human without learning the human's identity. Aliases survive the user's legal name changing. Substack writers covering sensitive political topics, security researchers protecting their identity, and writers in jurisdictions with hostile press environments all benefit. **The business value:** Pseudonymous publishing is growing as more independent writers cover topics that attract retaliation. Readers need to trust pseudonymous sources, and publishers need to verify that a single consistent human stands behind a body of work. Aliases give pseudonymous writers the credibility benefits of a verified identity without the exposure risks, expanding the pool of writers willing to cover sensitive subjects. ### **AI-generated content disclosure** A human signs AI-generated content to take responsibility for it. The signature attests to human accountability for what the AI produced, not to human authorship. Useful for compliance with AI-disclosure regulations (the EU AI Act, emerging state laws in the US) and for creators who want to be transparent about their tools without surrendering attribution. The signature acts as a meaningful "I stand behind this output" declaration. **The business value:** AI-disclosure regulation is arriving in multiple jurisdictions. The EU AI Act carries enforcement teeth. Organizations generating AI content at scale need a compliance mechanism that is lightweight, verifiable, and auditable. A human signature on AI-generated output satisfies the "human accountability" requirement without requiring manual review of each piece of content. Publishers and agencies that adopt this model gain regulatory compliance and audience trust at the same time. --- ## **Licensing model** A different signing pattern: a third party signs content under a credential the original person granted them. The licensor issues a verifiable credential authorizing specific use. The licensee's signatures on generated content carry the credential. Verifiers see the licensee's signature plus the embedded license credential. Scope dimensions the credential can encode: - Identity of the licensed likeness or character - Permitted content categories (advertising, entertainment, parody) - Permitted contexts (specific products, specific brands, specific platforms) - Prohibited contexts (no political content, no adult content, no competitor brands) - Validity window - Revocation conditions This converts a fight (rights-holders chasing unauthorized AI generators) into a market (rights-holders selling licenses, AI studios buying them). Public figures gain a new revenue stream from generative AI rather than a defensive cost center. AI studios gain an operating model that does not depend on hoping no one sues. Platforms that surface license credentials gain content authenticity at scale without making editorial judgments themselves. ### **Likeness licensing for public figures** A celebrity, athlete, or other public figure licenses their likeness to an AI studio for content generation. The studio generates and monetizes content, signing each piece with proof of valid license. The licensor receives a portion of proceeds. **The business value:** Generative AI creates a new asset class from existing likeness rights. Instead of spending on enforcement, rights-holders collect licensing revenue from the same technology that threatens them. Talent agencies can negotiate AI-likeness rights alongside traditional endorsement deals, expanding the total addressable market for each client. Studios that license gain legal certainty that unlicensed competitors cannot match. ### **Animated character licensing** A studio that owns a beloved animated character issues usage credentials for it to specific licensees. The licensee's signature carries the credential, and audiences distinguish authorized derivative work from unauthorized use. The model parallels existing physical-merchandise licensing; the credential is the digital "officially licensed" tag. **The business value:** Character licensing generates billions per year for IP holders. The digital equivalent of "officially licensed" tags protects those revenue streams as content moves online. IP holders can issue, scope, and revoke digital licenses with the same granularity they apply to physical merchandise, and the enforcement is cryptographic rather than legal. ### **Posthumous likeness licensing** Estates of deceased celebrities (Carrie Fisher in Star Wars, James Dean in announced films, deceased musicians with "new" releases) face active legal battles over likeness use. The estate issues credentials. Authorized productions sign with them. Unauthorized resurrection fakes become identifiable. This intersects with NIL because college contracts now include posthumous provisions. **The business value:** Posthumous likeness rights are one of the fastest-growing areas of entertainment law. Estates need a mechanism to authorize specific uses while blocking unauthorized ones. Verifiable credentials give estates granular control over how a deceased person's likeness appears, in which contexts, and for how long. Studios gain legal certainty that protects their investment in productions featuring deceased performers. ### **Voice-only licensing** A subset where the credential authorizes voice synthesis but not visual likeness. Useful for audiobook narration, dubbing, and voice acting where the original performer is unavailable or deceased. This use case becomes workable once audio signatures ship. Audio encoding appears in the [Roadmap](https://not.bot/learn/roadmap/) as far-future work. **The business value:** Audiobook narration, dubbing, and voice assistant markets generate billions per year. Licensed voice synthesis opens new revenue for performers (including posthumous revenue for estates) while giving producers a legal path to AI-generated voice content. The credential model prevents the unauthorized voice cloning that performers and their unions are fighting in courts today. ### **Athlete game licensing** EA Sports paid college athletes for the first time in 2024 after years of legal action over uncompensated NCAA likeness use in video games. The same credential model covers this: athlete licenses likeness to game studio, each in-game appearance carries the license credential. **The business value:** Sports video games represent a multi-billion-dollar market. The NCAA likeness litigation demonstrated that athletes deserve compensation for their digital likenesses. Verifiable license credentials automate the compliance chain from athlete authorization through game-studio usage, making it auditable and enforceable without per-athlete legal review. Game studios, leagues, and athletes all benefit from a licensing infrastructure that scales across thousands of player likenesses per title. --- > **not.bot Use Cases: Verified Humanness** — https://not.bot/learn/use-cases-verified-humanness/ · Markdown: https://not.bot/learn/use-cases-verified-humanness.md · Updated 2026-06-14 # **not.bot™ Use Cases: Verified Humanness** This document covers verified humanness applications: CAPTCHA replacement, sybil defense, surveys and polls, and catfishing prevention. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. --- ## **The unifying property** These use cases share a common need: distinguish real humans from bots, and distinguish one human from another, at the protocol layer rather than through behavioral inference. The mechanism stack: - **Verified humanness:** each authentication binds to a passport-verified human at the cryptographic layer. - **Site pass:** one-human-one-account per site, derived through MPC, unforgeable. - **Selective disclosure:** the user reveals the specific claims the verifier asks for and nothing else. Adversarial AI has destroyed the older defenses. Image CAPTCHAs solve at human-or-better rates. Behavioral profiling raises privacy concerns and ships browsing data to third parties. The economics now favor not.bot's approach: cryptographic answers to humanness questions cost less to deploy and verify than continuous adversarial-AI arms races. --- ## **CAPTCHA replacement** What CAPTCHA tries to prevent: - Automated account creation - Credential stuffing and password-spray attacks - Web scraping and data harvesting - Comment, review, and forum spam - Ticket and inventory scalping - API abuse and rate-limit evasion - Survey and poll fraud - Click fraud in ad networks - Form-submission abuse - Layer-7 DDoS amplification CAPTCHA fails on every dimension. Image CAPTCHAs solve faster than humans can. Behavioral CAPTCHAs profile users in ways that raise privacy concerns. Accessibility is poor: blind users, motor-impaired users, and users on low-end devices fail challenges legitimate users should pass. Friction is universal; nobody enjoys picking traffic lights. not.bot replaces "are you a human?" with a cryptographic answer instead of a behavioral guess. A confirmation on the phone, gated by a biometric or device passcode, verifiable. Each presentation binds to a specific passport-verified human, so the cost of running an automation farm becomes the cost of acquiring real passports, several orders of magnitude above what behavioral CAPTCHA imposes. **The business value:** CAPTCHA costs every website that deploys it. The direct costs include licensing fees for the paid behavioral tiers. The indirect costs are larger: conversion-rate drops of 10-40% when legitimate users abandon forms rather than solve puzzles, accessibility lawsuits from disabled users who cannot complete challenges, and privacy complaints from users whose browsing behavior gets shipped to third-party analytics. not.bot eliminates all three cost categories. Conversion rates improve because the friction drops to a quick confirmation on the phone. Accessibility becomes a non-issue. Privacy improves because no behavioral data leaves the user's device. --- ## **Sybil defense** The shared mechanism is the Site Pass: a per-human, per-site identifier derived through MPC. The same human cannot create two Site Passes for the same site, even using different aliases. Concrete attack categories this prevents: - Loss-leader and promo-code abuse (one $20-off-first-order per human, not per email) - Free-trial cycling - Inventory sniping and scalping (sneaker drops, console launches, concert tickets, limited-edition collectibles, iPhone launches) - Fake reviews - Astroturfing and review brigading - Online poll and survey manipulation - Airdrop and incentive farming (crypto, rewards programs) - Smurfing in online games (multi-account abuse of matchmaking) - Wait-list and beta-program manipulation - Referral program abuse (self-referral rings) - Petition and online-vote manipulation - Subscription trial-and-cancel cycling - Customer-service abuse (multiple accounts to escalate the same complaint) **The business value:** Multi-account abuse costs platforms and retailers billions per year. Promo-code abuse alone runs into hundreds of millions across e-commerce. Scalping operations capture value from both the retailer (brand damage, customer frustration) and the consumer (inflated secondary-market prices). Fake reviews undermine the entire recommendation economy; Amazon, Yelp, and Google spend enormous resources trying to detect and remove them. Site passes eliminate the economic model behind all of these attacks by making one-human-one-account a mathematical guarantee rather than a policy to enforce. Platforms that deploy sybil defense recover the revenue lost to abuse and restore the signal quality that legitimate users depend on. --- ## **Surveys and polls** The use cases: market research, academic research, political polling, customer satisfaction surveys, employee engagement, product feedback, A/B testing, beta testing, and focus groups. The shared problem: data corruption before analysis begins. Bot responses, fake panel members, click farms, single humans operating multiple panel accounts, AI-generated responses from real humans gaming incentives, demographic fraud. Pew, Nielsen, Ipsos, Gallup, and academic survey researchers all publish about response quality decline. The decline accelerates as AI tools lower the cost of fabricating responses. not.bot offers three properties at the same time: 1. Sybil defense via Site Pass: one human, one response per survey. 2. Verified humanness: bot responses are impossible at the authentication layer. 3. Demographic credentials without identity disclosure: panels recruit by age bracket, nationality, gender, and verification level without storing PII. **The business value:** Market research firms charge premiums for high-quality panel data. Response-quality decline threatens the value proposition of the entire survey research industry. A research firm offering not.bot-verified panels can charge premium rates because the data integrity is guaranteed by cryptography rather than estimated from statistics. Academic researchers gain IRB-friendly data collection (no PII stored) with higher response validity. Political pollsters gain protection against coordinated manipulation campaigns that distort public polling results. For any organization making decisions based on survey data, the difference between 90% valid responses and 99.9% valid responses can change the conclusion. --- ## **Catfishing prevention on dating apps** Selective disclosure is the operative property. The user proves humanness, age threshold, and gender to the platform without revealing name, address, or birthdate. Aliases let users maintain a dating-app identity tied cryptographically to a real human without exposing identity to the platform or other users. The platform gains sybil resistance (one human, one account per platform) and verified-real-person assurance for matched users. Threats addressed: - Fake profiles using stolen photos - AI-generated personas that don't correspond to a real person - Multi-account abuse (banned users returning under new identities) - Demographic misrepresentation (age, gender) - Romance scams that depend on the scammer's anonymity The user gains protection without surrendering identity to the platform. The platform gains the trust property without becoming a custodian of sensitive identity data. **The business value:** Dating apps generate over $6 billion a year, and fake profiles are the top complaint across the industry. Tinder, Bumble, and Hinge spend significant engineering and moderation resources fighting fake accounts. Romance scams cost victims over $1.3 billion per year in the US alone (FTC, 2023). Verified-human profiles differentiate a platform as a premium experience, justify higher subscription pricing, and reduce the moderation burden. Users who trust the platform stay longer and pay more. Platforms that offer "verified only" matching tiers create a competitive moat that unverified competitors cannot replicate. --- > **not.bot Use Cases: Credentials** — https://not.bot/learn/use-cases-credentials/ · Markdown: https://not.bot/learn/use-cases-credentials.md · Updated 2026-06-14 # **not.bot™ Use Cases: Credentials** This document covers verifiable credentials: marks of distinction, qualifiers, self-attested claims, and age verification. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. --- ## **The unifying property** The user holds credentials issued by third parties via Business DIDs and presents them to verifiers on a selective basis. The credential is a signed claim about the holder, with its own validity window, scope, and revocation rules. Today's analog is the wallet of physical IDs and certificates, the resume that nobody verifies, and the LinkedIn profile that anyone can fill with anything. Verification services exist for narrow slices; they are slow and expensive. Most claims people make about themselves go unchecked. The not.bot credential model gives each credential cryptographic backing while keeping privacy properties (selective disclosure, no PII surrender for routine checks) that the physical and online analogs lack. --- ## **Marks of distinction** Achievements the holder accumulates and presents for credit. Most are unverifiable claims today. ### **Diplomas and degrees** The issuing university signs a credential to the graduate's identity. The employer verifies without contacting the registrar. The credential survives institutional changes, mergers, and shutdowns better than centralized verification databases. **The business value:** Diploma fraud costs employers and institutions billions in misallocated hiring decisions, reputational damage, and downstream liability. The centralized clearinghouse model processes tens of millions of verification requests per year, each taking days. Instant cryptographic verification replaces multi-day processes with a single check, cuts verification costs to near zero, and makes diploma mills non-viable because employers can distinguish verified credentials from fabricated ones. ### **Professional certifications** PMP, CFA, CISSP, AWS, Cisco, Microsoft, medical board certifications, bar admission. The certifying body issues credentials with renewal cycles and revocation paths. Continuing education hours, recertification windows, and lapsed-status flags all carry through the credential lifecycle. **The business value:** Certifying bodies spend significant resources running verification hotlines and web portals. Employers spend days waiting for verification responses. Lapsed certifications go undetected for months or years. Verifiable credentials with built-in expiration and revocation automate the lifecycle, reduce the certifying body's operational cost, and give employers real-time confidence that a certification is current rather than stale. ### **Industry and academic awards** Pulitzers, Oscars, Grammys, industry recognitions, scholarly honors. The awarding body signs a credential to the recipient's identity. The recipient presents the credential as proof rather than as a citation. ### **Conference attendance** Proof-of-attendance for continuing-education credit, networking validation, and ticket transfer protection. The conference organizer signs credentials to attendees. ### **Course completions** Coursera, Udemy, edX, internal corporate training programs. The course provider signs completion credentials. Useful for skill-based hiring where formal degrees matter less than specific competencies. **The business value:** The skills-based hiring movement is shifting employer attention from degrees to demonstrated competencies. Verifiable course completions let candidates prove specific skills without depending on the platform to keep a verification portal running forever. Employers hiring for cloud engineering, data science, or cybersecurity roles can verify claimed Coursera or AWS training credentials in one check rather than taking the candidate's word for it. ### **Athletic achievements** Race finish times, belt rankings in martial arts, scuba certifications, climbing certifications, sailing licenses. The certifying body signs credentials with appropriate validity windows for skills that lapse without practice. ### **Video-game achievements** Ranked tiers, tournament results, speedrun records, rare completions, veteran status in long-running titles. The publisher signs achievement credentials to the player's identity. The player presents them anywhere: other games, streaming profiles, tournament registrations, communities that gate entry on demonstrated skill. **The business value:** Gamers spend money and thousands of hours earning achievements that today live inside one publisher's account system and die with it. Verifiable achievement credentials turn those accomplishments into portable property, and players will pay for that permanence. Publishers gain a revenue line (signed achievement credentials as a premium feature), a retention hook, and an anti-smurfing signal, since a player's verified history travels with them. Esports organizers gain instant verification of qualifying results, and the credential outlives the publisher's servers. ### **Military service records** Branch, rank, dates of service, decorations, MOS qualifications. The Department of Defense or its modern equivalent signs credentials to veterans. Reduces the recurring fraud surface where civilians claim military service for benefits, employment, or social capital. **The business value:** Stolen valor is a persistent problem that costs both legitimate veterans (whose accomplishments get diluted) and organizations that extend benefits based on service claims. Verifiable military credentials give employers, benefit programs, and veteran-service organizations instant verification of service records. The VA alone processes millions of benefit claims per year; cryptographic verification of service status streamlines the intake process. ### **Loyalty program status** Frequent flyer tier, hotel elite status, retail loyalty levels. The program operator signs status credentials with validity windows that match earning periods. Status matching across programs becomes a credential exchange rather than a manual verification process. **The business value:** Hotel chains and airlines spend millions per year processing manual status-match requests. A verifiable loyalty credential automates the process: the customer presents their signed status from one program, and the receiving program grants the match on the spot. Customer acquisition from competitor programs becomes frictionless, and the fraud risk from fabricated status claims drops to zero. --- ## **Qualifiers** Time-bound status checks that gate access. The privacy advantage matters most here. Today's pattern is wholesale data disclosure: verifying a credit score means surrendering the full credit report. With not.bot, the verifier asks "credit score above 700?" and gets a signed boolean. The verifier learns one bit and nothing else. ### **Background check status** Clean or not. The CRA signs the status without disclosing the underlying records. Employers, landlords, and platforms that run background checks today gain the screening property without the data-handling burden. **The business value:** Background check vendors charge $30-$100 per check and take 3-7 business days. A portable, pre-verified status credential flips the model: the candidate runs one check and presents the result to multiple employers. Employers get faster hiring. Candidates avoid repeating the same check for each application. The CRA gains a recurring credential-refresh revenue model rather than a one-shot transaction. ### **Credit score brackets** Above 700, above 750, above 800. The credit bureau signs the bracket without disclosing the score or report. Lenders, landlords, and high-value transaction counterparties get the signal they need. **The business value:** Apartment applications require full credit reports, exposing Social Security numbers, account details, and payment histories to every landlord and property manager in the applicant's search. A signed bracket credential (e.g., "credit score above 720") satisfies the landlord's screening need while eliminating the PII exposure that makes apartment hunting a data breach risk. Property management companies reduce their regulatory burden under the Fair Credit Reporting Act while maintaining screening quality. ### **Income and employment verification** Above threshold, employed at named institution, length of tenure. The employer or income verification service signs. Eliminates the wholesale disclosure of pay stubs and W-2s for routine apartment applications. **The business value:** Apartment applications, mortgage pre-qualifications, and loan applications all require income verification. The current process (upload pay stubs, authorize employment verification calls) exposes detailed financial information to parties who need only a threshold answer. A signed "income above $80,000" credential satisfies the requirement without the exposure. Lenders and landlords get faster verification; applicants gain privacy. ### **Bondability** A surety bond company signs a credential confirming the holder is bondable for a specified amount. Useful for contractors, financial services workers, and others where bondability is a hiring or licensing requirement. ### **Insurance coverage** Auto, professional liability, contractor general liability, malpractice. The insurer signs proof of coverage. Verifiers confirm coverage in force without requiring policy disclosure. **The business value:** Contractors spend hours per week providing proof-of-insurance to general contractors, property owners, and platforms. General contractors verify subcontractor insurance by hand for each project. A signed coverage credential automates the verification loop, reduces project onboarding timelines, and eliminates the risk of accepting expired or fraudulent certificates of insurance. ### **Professional license status** Medical, legal, real estate, contractor, electrician, plumber, CPA. The licensing board signs the status with validity windows. Patients, clients, and customers verify before engaging. **The business value:** Patients searching for a new doctor, clients hiring an attorney, and homeowners hiring a contractor have no efficient way to verify professional licenses. State licensing board websites are inconsistent, hard to navigate, and sometimes months behind. A signed license credential gives consumers instant confidence and gives licensed professionals a competitive advantage over unlicensed operators. ### **Driver's license validity** State DMV signs a credential confirming valid license, class, restrictions, and endorsements without disclosing the full record. **The business value:** Rental car companies, fleet managers, and ride-share platforms verify driver's licenses millions of times per year. Each verification requires manual review of a physical or photographed document. A signed credential automates the check, reduces rental counter wait times, and eliminates the PII exposure of sharing a full license with each verification party. ### **Security clearance levels** Confidential, Secret, Top Secret, SCI compartments. The clearing authority signs the level without disclosing the underlying investigation. Defense contractors and cleared facilities verify without running their own clearance lookups. **The business value:** Cleared personnel are in constant demand across the defense and intelligence sectors. Hiring a cleared candidate today requires weeks of verification through JPAS/DISS. A portable clearance credential lets cleared professionals demonstrate their status to prospective employers on the spot, compressing hiring timelines for roles where clearance is the primary bottleneck. --- ## **Self-attested credentials** The user signs claims about themselves that no third party verifies. The signature is the value. Profile information that reaches a recipient through an intermediary, a platform database, a data broker, an aggregator, may no longer say what the user said. A signed self-attested credential settles it: the end recipient validates the signature and knows the claim reads as the user wrote it, unaltered by anything in between. The information represents the user the way the user chose to present themselves. Consistency and portability follow: the user signs once and presents to many platforms. ### **Avatar and bio** A consistent user-controlled identity image and description that travels across platforms. Eliminates the per-platform setup friction that often causes users to abandon profile completeness. ### **Pronouns** User-attested pronouns that the user signs once and presents to many platforms. The platform gets a consistent declaration; the user controls the claim and updates it once rather than per platform. ### **Sexual orientation** Useful in dating contexts. Signed once, presented when the user chooses. Selective disclosure means a user can present orientation to dating apps without surrendering it elsewhere. ### **Hobbies and interests** Cross-platform interest profiles that the user controls rather than each platform inferring through tracking. Privacy advantage and signal advantage at the same time. ### **Relationship status** Single, partnered, married. The user controls the claim and can update it. Useful for dating contexts and for any platform where relationship context matters. ### **Lifestyle claims** Vegetarian, smoker, drinker, parent, pet owner. Useful in dating, roommate matching, and community contexts. ### **Portable profile data** Any "about me" information the user wants to maintain across platforms without re-entering. The user gets profile portability; platforms get consistent claims that the user has signed. **The business value of self-attested credentials as a category:** Services that receive user data through intermediaries inherit the intermediaries' defects: stale copies and mangled broker records that no longer match the person. A signed credential gives the end recipient proof that the profile data matches what the user wrote, which makes the data worth acting on. Portability compounds the value: users join an average of 7+ social platforms, and re-entering the same profile information on each one creates friction that reduces engagement and profile quality. Portable signed credentials let users carry their profile data to a new platform in one action, which improves the new platform's onboarding completion rate and gives the user a consistent identity across their digital life. For platforms, higher profile completion drives better matching, higher engagement, and stronger network effects. --- ## **Age verification** Age verification earns its own treatment because of regulatory tailwinds and because the mechanism leverages multiple not.bot capabilities at once. Driving forces include KOSA, COPPA 2.0, the SCREEN Act, and the GUARD Act at the US federal level, Texas HB1181 and the parallel state laws, the state-level AI age-verification acts, the UK Online Safety Act, EU age-verification mandates, and existing alcohol, tobacco, and gambling compliance regimes. The regulatory pressure is increasing in every major market. ### **Existing approaches and their failure modes** Document-scanning vendors capture full identity to verify age. This violates the principle of minimal disclosure and creates breach surface. Credit cards as a weak proxy. Cards get borrowed and prove nothing about age. Self-attestation. Users lie. ### **How not.bot delivers age verification** Age claims are MPC-derived from the passport during enrollment. Julia Social never learns the user's birthdate, and Praxis (the independent escrow agent that operates the Escrow Server) does not store in in a way that can be recovered. Age credentials expire monthly and refresh through the same MPC process. As the user crosses age thresholds, new credentials get issued without either party learning when the crossing occurred. The user presents only the threshold the verifier asks for. AgeOver18 returns a signed boolean, not a date. The verifier learns one bit. No PII transfers. No breach surface accumulates. Each age presentation is gated by a biometric or device passcode and bound to a passport-verified human. A verified adult cannot pass their age proof to a child the way they can with a credit card. The full age claim set covers AgeOver13 through AgeOver25, AgeOver100, and 5-year and 10-year range brackets. Verifiers pick the threshold appropriate to their use case. **The business value:** Age verification is becoming a legal requirement in multiple jurisdictions at the same time. Companies that sell age-restricted products or host age-restricted content face a compliance obligation with no good solution today. Document-scanning vendors create data-breach liability. Credit cards don't verify age. Self-attestation satisfies no regulator. not.bot gives these companies a compliance mechanism that satisfies regulatory requirements while protecting user privacy, a combination no competing product delivers. For alcohol, tobacco, and cannabis retailers operating online, age verification is a license-to-operate requirement. For social media platforms facing KOSA and UK Online Safety Act obligations, it determines whether they can serve younger audiences at all. The company that offers compliant, private age verification captures a market that regulation is forcing into existence. --- > **not.bot Use Cases: Trust Surface** — https://not.bot/learn/use-cases-trust-surface/ · Markdown: https://not.bot/learn/use-cases-trust-surface.md · Updated 2026-06-14 # **not.bot™ Use Cases: Trust Surface** This document covers signed links, authorized agent verification, and peer-to-peer commerce. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. --- ## **The unifying property** Any physical surface presenting a digital action is a trust surface. Any commercial relationship where parties cannot verify each other is a trust surface. Any third party claiming authorization from a brand is a trust surface. The "quishing" attack (sticking a malicious QR code over a legitimate one in a parking lot) works because the URL itself cannot be verified by the user. Marketplace fraud works because buyer and seller cannot verify each other. Counterfeit-good schemes work because consumers cannot verify the seller's authorization from the brand. Signed links, signed credentials, and signed transactions convert the trust question from "is this real" (which the user cannot answer) to "is this signer who I expect" (which the user can). --- ## **Signed links and signed action prompts** ### **Parking, transit, and metered payment QR codes** The canonical quishing target. Attackers stick fraudulent QR stickers over legitimate ones in parking lots and at meters. Drivers scan, "pay," and discover later that the operator never received payment. Cards get charged, sometimes recurring. A signed link shows the city or operator as signer before the user follows the link. The signature surface is verifiable; the URL is not. **The business value:** Cities and parking operators lose revenue and face customer complaints from quishing attacks. The fraud scales across thousands of meters and parking lots per city. A signed-link infrastructure protects revenue, reduces customer disputes, and eliminates the manual QR-code-inspection programs some cities have implemented in response. ### **Restaurant menu QR codes** Menu QR codes at tables let attackers redirect to fake ordering systems that capture payment information. The attack surface scaled during COVID-era contactless adoption and never went away. Signed menu links display the restaurant as signer. **The business value:** Restaurants operating digital ordering through QR codes face liability for payment fraud that occurs through substituted codes. Signed links protect customers and shield the restaurant from chargeback losses and reputational damage. ### **Wi-Fi connection QR codes** The fake hotspot vector. A QR code purporting to connect a guest to a hotel or coffee shop network connects them to an attacker's access point. From there the attacker captures credentials and intercepts traffic. Signed Wi-Fi codes show the venue as signer. **The business value:** Hotels, airports, and coffee chains that offer guest Wi-Fi carry liability when fake hotspots capture customer data on their premises. Signed Wi-Fi connection codes protect both the guest and the venue from a man-in-the-middle attack that is difficult to detect and costly to remediate. ### **Charity donation QR codes** A massive disaster-related fraud surface. Fake charity codes appear next to legitimate ones at events, in fliers, and on social media. Disaster events attract thousands of fraudulent solicitations within hours. Signed donation links show the charity as signer. Donors verify before giving rather than after losing the donation. **The business value:** Disaster-relief charities lose both donations (diverted to fraudsters) and donor confidence (the next time a disaster hits, donors hesitate). Signed donation links protect revenue and trust at the moment donors are most willing to give. ### **Crypto payment QR codes** Address swaps in crypto QR codes drain wallets. A user sees what looks like a payment request from a known counterparty and signs the transaction; the address in the QR was substituted. A signed address with the recipient as signer prevents substitution. Verifiers confirm the signer matches the expected counterparty before approving the transaction. **The business value:** Crypto address fraud is irreversible. Funds sent to a substituted address cannot be recovered. For exchanges, payment processors, and merchants accepting crypto, signed payment addresses eliminate the highest-severity fraud vector in the transaction flow. ### **Tip and service-worker payment codes** Workers' tip codes get replaced with fraudulent ones at points of sale. The customer pays the tip, the worker never sees it. The attack hits hardest at the lowest end of the wage scale where tips matter most. Signed tip codes show the worker or employer as signer. ### **Event and conference signage** Conference QR codes for schedules, materials, and networking get spoofed at events. Attendees scan, expect the conference platform, and get phishing pages instead. Signed signage codes show the organizer as signer. ### **Museum and tourist information codes** Information QR codes at attractions get replaced with malicious ones that direct to phishing or scam pages. Tourist destinations are vulnerable because visitors lack local context to recognize substitutions. Signed codes show the institution as signer. ### **Vaccination and health-pass QR codes** Health pass spoofing during the COVID era was widespread. Forged passes appeared in every jurisdiction with a vaccine-mandate regime. Signed health passes with the issuing authority as signer let venues verify before granting access. The signature carries the issuer's identity through the verification chain. **The business value:** Public health authorities and venues enforcing health-pass requirements need a forgery-resistant credential. Signed health passes eliminate the photo-editing and QR-code-forging attacks that undermined every first-generation health-pass system deployed during COVID. The infrastructure is reusable for future public health requirements. ### **Real estate yard-sign QR codes** "Scan to schedule a tour" yard signs get cloned by attackers running fake listing schemes. Prospective buyers schedule tours, share contact information, and become marks for downstream scams. Signed sign codes show the listing brokerage as signer. **The business value:** Real estate brokerages invest in yard signs as a primary lead-generation channel. Fraudulent clones intercept those leads, costing the brokerage potential commissions and exposing prospective buyers to scam operations. Signed QR codes protect both the lead pipeline and the consumer. --- ## **Authorized agent verification** A Business DID issues a credential to another entity authorizing them to act as an agent. The agent displays the credential. Customers verify the chain before transacting. **The category-level business value:** Counterfeiting and unauthorized representation cost brands over $500 billion per year worldwide (OECD). Authorized-agent credentials give brands a digital chain-of-custody mechanism that is verifiable by the end consumer, enforceable at scale, and revocable in real time. Each category below represents a slice of that market. ### **Manufacturer authorized repair** Manufacturer authorized-repair programs for phones and electronics, auto warranty service centers, appliance repair networks. The customer scans a credential at the storefront or website confirming the manufacturer authorized this provider for warranty work. Counterfeit "authorized" repair shops lose their cover. **The business value:** Manufacturers spend millions on authorized-service-provider programs. Unauthorized repair shops that claim authorization damage the manufacturer's brand, void warranties, and expose customers to substandard parts. A verifiable credential gives consumers instant proof before they hand over their device, vehicle, or appliance. ### **Pharmaceutical authorized distributors** Counterfeit pharmaceuticals are a multi-billion-dollar global problem. The WHO estimates ten percent of medicines in low- and middle-income countries are substandard or falsified. Pharmacy supply chain authentication via credentials issued by manufacturers to authorized wholesalers and dispensers gives consumers a verification path to the source. Most relevant for online pharmacy storefronts where consumers cannot inspect physical credentials. **The business value:** The Drug Supply Chain Security Act (DSCSA) requires pharmaceutical traceability in the US. Verifiable distributor credentials complement serialization requirements by authenticating the distributor at each step, not just the package. Manufacturers that issue credentials to their authorized channel gain real-time visibility into distribution-chain integrity. ### **Software authorized resellers** Microsoft, Adobe, Autodesk, and other software vendors operate authorized reseller programs. Buyers verify the reseller credential before purchase to avoid grey-market and counterfeit license keys. **The business value:** Grey-market software keys generate hundreds of millions in losses for software vendors and expose buyers to malware, licensing audits, and support denial. A verifiable reseller credential lets the buyer confirm authorization before purchase and gives the vendor enforcement data on unauthorized channels. ### **Authorized parts dealers** Counterfeit parts in aviation, automotive, and medical devices kill people. The FAA tracks suspected unapproved parts cases; the FDA tracks counterfeit medical devices. Both agencies struggle with detection. OEM credentials issued to authorized parts distributors give buyers a verification path. Critical-safety industries can require credential verification at receipt. **The business value:** A single counterfeit part in an aircraft engine or medical device can cause catastrophic failure. The liability exposure for OEMs, distributors, and end-users runs into the billions. Verifiable parts-dealer credentials reduce liability risk, satisfy regulatory traceability requirements, and give procurement teams confidence that the part is genuine before it enters the supply chain. ### **Franchise authentication** Is this storefront a real McDonald's, Subway, or 7-Eleven? Franchise credentials issued by the corporate parent to legitimate franchisees authenticate the location. Most relevant in jurisdictions where brand impersonation drives revenue without legal recourse for the brand. ### **Insurance authorized adjusters and approved contractors** Post-disaster fraud schemes flood affected areas with fake adjusters and contractors. Homeowners under stress sign agreements with people who claim insurance company authorization that does not exist. Insurance company credentials issued to legitimate field staff and approved contractor networks give homeowners a verification path during the highest-stress moments. **The business value:** Insurance fraud costs the industry over $300 billion per year across all lines (Coalition Against Insurance Fraud). Post-disaster impersonation of adjusters and contractors is among the most harmful and least detectable forms. Verifiable credentials protect both the homeowner and the insurer's reputation at a moment when trust matters most. ### **Authorized used-car dealers** Used-car superstores, vehicle-history certification services, and manufacturer certified pre-owned programs operate authorized dealer networks. Verifiable dealer credentials let buyers confirm the certification chain before driving off the lot. ### **Charity authorized fundraisers** Door-to-door and event-based fundraising scams are persistent. People claiming to fundraise for legitimate charities cannot prove the relationship. Charity credentials issued to authorized fundraising staff and volunteer coordinators let donors verify before giving. ### **Realtor brokerage authentication** Real estate agents present credentials issued by their brokerage. Buyers and sellers verify before signing listing or buying agreements. Most useful for relocations where the consumer lacks local market knowledge. ### **Tax preparer authentication** Seasonal storefronts and pop-up tax preparers (often fraudulent) victimize lower-income filers each year. The IRS publishes warnings; the warnings reach a small fraction of those who need them. Credentials issued by the national tax-preparation chains and IRS-recognized programs let filers verify before handing over W-2s and SSNs. **The business value:** Fraudulent tax preparation costs the IRS billions in fraudulent refunds and costs victims their tax refunds and personal information. Verifiable preparer credentials give the filer a check that takes seconds, protects the IRS revenue base, and gives legitimate preparers a trust advantage over fraudulent competitors. --- ## **Marketplaces and peer-to-peer commerce** eBay, Etsy, Facebook Marketplace, Craigslist, OfferUp, Mercari, Poshmark, Reverb, StockX. Peer-to-peer commerce stacks several capabilities into one application. **The category-level business value:** Online marketplaces generate over $3.5 trillion in annual GMV worldwide. Fraud, fake reviews, and seller anonymity are the primary barriers to growth. Trust correlates with transaction volume: platforms that buyers trust capture more spend. The properties below compose into a trust stack that no existing marketplace offers. ### **Verified seller and buyer identity** Both parties hold not.bot identities. The platform gets sybil resistance and verified humanness. Each party gets confidence that the counterparty is a real person with skin in the game. ### **Banned-seller enforcement that survives account recreation** A seller banned for fraud cannot create a new account under a different name to resume operations. The Site Pass enforces one-account-per-human at the platform level. Permanent bans persist. **The business value:** eBay, Amazon, and Etsy all face the problem of banned sellers returning under new accounts. Each return costs the platform investigation resources, buyer losses, and trust erosion. Permanent bans that work reduce fraud loss, investigation cost, and the reputational damage that repeat-offender sellers inflict on the platform's brand. ### **Verified reviews tied to verified purchases** One review per human per purchased item. Eliminates review farming, paid-review services, and competitor sabotage campaigns. Restores signal value to ratings that have been hollowed out across most major platforms. **The business value:** Amazon estimates that fake reviews cost the platform billions in misdirected consumer spending. Consumers who lose trust in reviews buy less or buy elsewhere. Verified reviews restore the recommendation signal that drives conversion, and they differentiate the platform that offers them from competitors still fighting the fake-review arms race. ### **Portable seller reputation** A reputation credential issued by one platform travels with the seller's identity. A seller with five years of clean history on eBay can present that credential when joining a new marketplace, removing the cold-start penalty for legitimate sellers. **The business value:** Legitimate sellers face a cold-start penalty on each new platform: no reviews, no history, no buyer trust. This favors established sellers and makes it harder for new platforms to recruit quality supply. Portable reputation removes the cold-start barrier, accelerates new marketplace growth, and lets legitimate sellers earn premium pricing on day one instead of after months of rebuilding trust. ### **Counterfeit-listing prevention via authorized-reseller credentials** Listings for branded goods can carry the authorized-reseller credential from the manufacturer. Buyers verify the credential before purchase. Listings without the credential carry no implied authorization. Brands can issue credentials at scale through their Business DID infrastructure. **The business value:** Counterfeit goods on marketplaces cost brands billions and expose platforms to legal liability (SHOP SAFE Act proposals, EU Digital Services Act obligations). Authorized-reseller credentials give the platform an automated way to distinguish legitimate listings from counterfeits, reducing brand-protection complaints and legal exposure while improving buyer confidence. ### **High-value transaction buyer verification** Buyers presenting income or credit credentials qualify for high-value purchases (collectibles, vehicles, jewelry) without the seller running their own credit checks. The buyer's privacy stays intact: the seller learns only that the qualification is met, not the underlying financial details. ### **In-person handoff mutual verification** Facebook Marketplace and Craigslist meetings carry real safety risks. Both parties verify the other's identity through not.bot before meeting. The meeting record itself can be signed by both parties, creating an audit trail if something goes wrong. **The business value:** Safety concerns suppress transaction volume on in-person marketplaces. Users avoid high-value in-person transactions because they cannot verify the counterparty. Mutual verification unlocks categories of commerce (vehicles, furniture, high-value electronics) where buyer hesitation suppresses the platform's GMV. --- ## **Gig economy and on-demand services** Uber, Lyft, DoorDash, Instacart, TaskRabbit, Handy, Rover. Same mutual-verification model as marketplaces, with the in-person component amplifying every concern. **The category-level business value:** The gig economy generates over $400 billion in annual revenue worldwide. Safety incidents and trust deficits are the primary regulatory and consumer barriers to growth. Platforms that prove their workers are verified humans with verified qualifications gain regulatory goodwill, consumer trust, and competitive differentiation. ### **Driver and customer mutual verification** Both parties verify before pickup. The driver confirms the customer is who the app claims. The customer confirms the driver and the vehicle match the trip assignment. ### **Background check status as qualifier credential** The platform issues the driver a credential confirming background check status. Customers can request the credential before accepting the ride or service. Workers can present platform-independent qualifications when joining new platforms. **The business value:** Background check portability reduces the cost of multi-platform work for gig workers and reduces the platform's onboarding cost for workers who have already been verified elsewhere. Workers who can present a verified background credential join new platforms faster. Platforms that accept portable credentials recruit quality supply ahead of competitors still running multi-day background check processes. ### **Profile-to-person identity matching at handoff** The person who shows up matches the app profile. Addresses fake-driver scams that lure passengers into unauthorized vehicles by matching the make, model, and license plate displayed in the app. **The business value:** Fake-driver scams have resulted in serious safety incidents, including assaults and kidnappings. Each incident carries liability exposure, media coverage, and regulatory scrutiny for the platform. Identity matching at handoff eliminates the attack vector where a non-driver intercepts a passenger by displaying a matching vehicle, converting a known safety risk into a verified encounter. --- > **not.bot Use Cases: Industry Verticals** — https://not.bot/learn/use-cases-industry-verticals/ · Markdown: https://not.bot/learn/use-cases-industry-verticals.md · Updated 2026-06-05 # **not.bot™ Use Cases: Industry Verticals** This document covers industry-specific applications across healthcare, finance, real estate, education, journalism, legal services, and consumer platforms. It is part of the not.bot use cases catalog; the [Use Cases Index](https://not.bot/learn/use-cases/) holds the full catalog and the mechanism definitions the use cases draw on. --- ## **Telehealth (two-sided verification)** Patient and provider verify each other. The patient confirms the person on the video is a real licensed clinician at a legitimate practice. The provider confirms the patient is who the chart says, not someone using a relative's insurance. Threats addressed: - **Medical identity theft.** Information gathering for fraudulent billing, prescription harvesting, fake claims. - **Fraudulent telehealth practices.** Fake clinics generating fear-driven prescriptions or referrals to predatory products. - **Chart integrity.** The consultation record ties to a verified human rather than to whatever name was entered at intake. - **Insurance fraud.** Claims billed under one identity for services rendered to another. Provider-side credentials include the practice's Domain Name credential, the clinician's professional licensure as a verifiable claim, and the not.bot signature itself binding the session to a specific human. Patient-side gives the provider a verified human and binds the session record to a real identity for billing and chart accuracy. The session video itself can carry signatures from both parties, creating a tamper-evident record of the consultation. **The business value:** Telehealth fraud cost the federal government over $4.5 billion in a single DOJ enforcement action in 2024. The telehealth market is projected to exceed $380 billion by 2030, and trust is the primary barrier to further adoption. Two-sided verification protects providers from malpractice claims rooted in patient-identity fraud, protects patients from fraudulent providers, and gives payers (insurance companies, CMS) confidence that the billed service was delivered to the right person by a qualified clinician. HIPAA compliance benefits too: the session record ties to verified identities rather than self-reported names. --- ## **Financial services KYC** Account opening, anti-money-laundering compliance, beneficial-ownership disclosure, sanctions screening. Banks today run identity proofing through document-scanning vendors and store the underlying data, creating regulatory and breach risk. not.bot lets banks ask for the specific KYC credentials they need (identity verification level, sanctions clearance, age, jurisdiction) without storing the underlying PII. The bank fulfills its compliance obligations while reducing data-at-rest exposure. Beneficial-ownership disclosure (FinCEN BOI rule, similar regimes elsewhere) gains a credential model where each beneficial owner presents a verified identity credential rather than the bank rebuilding the identity verification chain for each owner. **The business value:** KYC compliance costs the global banking industry over $30 billion per year (Thomson Reuters). Each bank maintains its own copy of customer identity data, multiplying breach surface across the system. not.bot's credential model lets banks verify identity without storing the identity data, cutting compliance costs and breach liability at the same time. Onboarding times for new accounts shrink from days to minutes. For beneficial-ownership disclosure, the credential model eliminates the manual identity-verification chain that each bank runs on its own for each owner of each entity account. --- ## **Insurance fraud prevention** Claims signed by the actual claimant. Beneficiary verification at payout. Witness statements signed by verified humans. Damage photos signed at the time of capture by the policyholder. The insurance industry's fraud losses run into the tens of billions a year. The Coalition Against Insurance Fraud estimates over $300 billion in annual fraud across all lines. Cryptographic identity at each claim touchpoint shrinks the surface for staged accidents, ghost claimants, and fabricated witness pools. Most relevant for digital-first insurers (Lemonade, Root, Hippo) where the entire claim lifecycle runs through apps and the carrier never sees the parties in person. **The business value:** Fraud constitutes 5-10% of claim costs across the property and casualty industry. For a carrier processing $10 billion in claims, that represents $500 million to $1 billion in fraud losses. Signed claims, signed photos, and signed witness statements create a cryptographic evidence chain that deters fraud at submission and accelerates investigation when fraud occurs. Digital-first insurers that integrate not.bot gain a fraud-detection advantage and lower loss ratios, improving combined ratios and profitability. --- ## **Real estate transactions** Buyer and seller identity verification, signed offers, signed disclosures, signed closing documents, lender verification of borrower identity, title company verification of all parties. Wire fraud in real estate runs into billions per year. The FBI Internet Crime Complaint Center tracks real estate wire fraud as a top loss category. The fraud works because the actors involved cannot verify each other through email; an attacker who compromises any party's email can impersonate them at closing. Signed communications and signed parties make the transaction surface verifiable. The closing instruction email from the title company carries the title company's signature; substitution becomes detectable. **The business value:** The average US home sale involves over $400,000 in wire transfers. A single intercepted wire costs the buyer their life savings and costs the title company or lender legal liability that can exceed the transaction value. The FBI reports over $145 million in reported losses from real estate wire fraud a year, and reported losses represent a fraction of actual losses. Signed closing instructions, signed wire requests, and verified party identities at each step close the impersonation vector that makes this fraud possible. Title insurance companies, settlement services, and lenders that adopt not.bot reduce their highest-severity liability exposure. --- ## **Remote online notarization** States have authorized remote online notarization (RON) since the COVID era. Today's RON depends on webcam-based ID checking that has documented spoofing vulnerabilities. Deepfakes raise the spoofing risk further. not.bot replaces the webcam ID check with cryptographic identity verification while keeping the live notary engagement. Document signature, witness signatures, and notary acknowledgment all carry verifiable identity. The notarized document carries signatures that survive outside any platform (patent pending) and verify against the original signers years later. **The business value:** The RON market is growing as states expand authorization and consumers demand remote closings. The primary regulatory objection is identity-spoofing risk. not.bot eliminates the spoofing vector that legislators cite when opposing RON expansion, which could unlock RON authorization in holdout states. For RON platforms, cryptographic identity verification is a competitive differentiator and a regulatory compliance asset that webcam-based alternatives cannot match. --- ## **Crowdfunding** Three trust problems exist today: 1. Anonymous project creators with no accountability. 2. Disaster-related crowdfunding scams that flood every news cycle. 3. Medical fundraising fraud where the named patient does not exist or never sees the money. not.bot composes verified-human creator identity, one-human-one-campaign sybil defense (a banned creator stays banned across re-attempts), and verified beneficiary credentials. A person fundraising for cancer treatment can present a verified medical credential without disclosing the diagnosis to the public. Platforms gain a defensible trust story that today's leading platforms cannot match. Donors gain confidence that the campaign creator and beneficiary are real and that funds reach the intended recipient. **The business value:** GoFundMe alone processes over $10 billion in donations. Trust is the single largest determinant of whether a donor gives or scrolls past. Verified campaigns convert at higher rates because donors can confirm the creator and beneficiary are real. Platforms that offer verified campaigns reduce their fraud-investigation burden, improve donor retention, and build a trust-based competitive moat. After every disaster, the platform that can say "our campaigns are verified" captures donor trust while competitors drown in fraud reports. --- ## **Job boards** LinkedIn, Indeed, ZipRecruiter, Monster, specialized vertical job boards, and emerging AI-driven hiring platforms share a worsening trust collapse: - Fake candidates with AI-generated resumes apply at scale. - Fake employers post listings to harvest applicant data or run advance-fee scams. - AI-generated cover letters and interview answers undermine signal. - Identity fraud has surged for remote-work claims. Verified-human candidates present verifiable employment history, education, and certification credentials. Verified employers present Domain Name and Business DID credentials so candidates know the listing is real. The platform gains a defensible quality story to differentiate against the AI-spam decline curve. Quality on most major job boards is collapsing; the platform that establishes a verified-only tier captures the candidates and employers who want to escape the noise. **The business value:** Job boards generate over $30 billion in annual revenue worldwide. The revenue model depends on employers paying for access to quality candidates, and candidates trusting that listings are real. Both sides of the marketplace are degrading: employers waste time on AI-generated applications, and candidates waste time on fake listings. A verified-only tier restores signal quality and justifies premium pricing. Recruiter tools on the major boards run $500-$1,000+ per month; a verified tier that eliminates fake candidates makes those tools worth more, not less. For specialized boards (healthcare, legal, engineering), verified credentials become table stakes as AI-generated applications overwhelm screening capacity. For hiring and recruiting from the company-side (where the buyer is the hiring company rather than the platform), see [Enterprise Use Cases](https://not.bot/learn/use-cases-enterprise/). --- ## **Childcare and dependent care drop-off authorization** Schools, daycare centers, after-school programs, and senior care facilities face the persistent question of who is authorized to pick up a dependent. The authorized list today is paper or operational and breaks down. A parent or guardian issues a time-limited credential to the authorized adult. The school verifies before release. The credential carries the parent's signature and the time window; expiration is automatic. Most relevant for divorced or separated parents where pickup authorization changes often and where stakes around custody arrangements are high. **The business value:** Unauthorized pickup incidents carry severe liability for childcare facilities. Custody disputes generate the highest-risk pickup scenarios, and paper-based authorization lists fail when changes happen between updates. Time-limited, cryptographically signed pickup credentials reduce liability exposure, eliminate the manual process of updating paper lists, and give parents real-time control over who can pick up their child. Childcare facilities that adopt the system gain a differentiating safety feature that parents value during enrollment decisions. --- ## **Estate planning and digital inheritance** Signed directives, signed powers of attorney, signed healthcare proxies. Post-mortem credential transfer (the executor presents a credential authorizing them to act for the deceased's digital estate). Addresses the growing problem that digital assets and accounts die with their owners because no one can prove authorization. Family members lose access to photos, documents, financial accounts, and memorabilia stored in cloud services that lack post-mortem access policies. The estate planning attorney issues credentials to the executor. The executor presents them to service providers to claim authority. The chain is verifiable end-to-end. **The business value:** Digital estate disputes are growing as more wealth and memorabilia exist in digital form. Families lose access to irreplaceable photos, financial accounts worth millions, and digital assets with real monetary value. Estate attorneys who offer not.bot-credentialed estate planning provide a service that traditional practices cannot match. Cloud service providers (Apple, Google, Meta) gain a standardized mechanism for post-mortem access requests, replacing the ad-hoc processes that generate legal disputes and customer complaints. --- ## **Academic integrity** Signed homework and exam submissions confirm a specific human did the work. Anti-AI-cheating verification addresses the central problem generative AI has created for educators. Universities can require signed submissions, with the signature attesting that the student engaged with the material at the moment of submission. The signature does not prove the student wrote the content unaided, but it ties the submission to the human and creates an attribution chain that survives later challenges. Most relevant for high-stakes assessments: graduate-level coursework, professional school admissions essays, certification exams, and competitive programs where credentialing matters. **The business value:** Universities spend millions per year on plagiarism detection (license costs alone run $50,000-$500,000+ per institution per year) and still struggle with AI-generated submissions. Academic integrity violations damage institutional accreditation, employer trust in graduates, and the value of the degree itself. Signed submissions give institutions an attribution mechanism that complements plagiarism detection, ties each submission to a verified student, and creates a defensible record for disciplinary proceedings. --- ## **Remote exam proctoring** Today's remote proctoring depends on webcam recording, screen monitoring, and behavioral analytics. All raise privacy concerns and fail against determined cheaters who use second devices, screen-sharing tools, and AI assistance. Signed exam sessions verify the test-taker is the enrolled student. The session carries continuous identity confirmation through periodic re-signing requirements. Pairs with academic integrity for the full exam authenticity story. **The business value:** The remote proctoring market exceeds $1 billion and growing. Current solutions face lawsuits over privacy violations (facial recognition, room scanning), accessibility discrimination, and effectiveness challenges. not.bot replaces invasive surveillance with cryptographic identity verification that satisfies both the institution's integrity requirements and the student's privacy expectations. Proctoring vendors that integrate not.bot differentiate on privacy and effectiveness at the same time. --- ## **Confidential source protection** Journalists protect sources in many forms: whistleblowers, confidential informants, anonymous tipsters, victims of crimes who want their account verified without their identity exposed, internal sources at companies and governments. The journalist needs confidence the source is a real person rather than a disinformation operation. The source needs confidence their identity stays protected. not.bot provides verified humanness and signed claims without identity disclosure. The source signs their statement under an alias. The journalist verifies the alias represents a real human. Future statements from the same source carry the same alias and prove continuity. The source's underlying identity never appears. This addresses both established disinformation vectors (fake whistleblowers planting false stories) and the journalist's need to vouch for sources whose identities they protect. **The business value:** Disinformation operations that create fake whistleblowers have damaged news organizations' credibility and generated costly retractions. Newsrooms that can cryptographically verify their sources as real humans (without learning their identities) protect their editorial integrity. For investigative journalism outlets, this verification mechanism is a competitive advantage: sources are more willing to come forward when they trust the protection mechanism, and editors are more willing to publish when they can verify the source's continuity and humanness. --- > **Why not.bot: Index** — https://not.bot/learn/why-notbot/ · Markdown: https://not.bot/learn/why-notbot.md · Updated 2026-06-14 # **Why not.bot™: Index** This index is the entry point to the Why not.bot series, which presents the public evidence for what the not.bot product family exists to solve. Five detail documents carry the record: named incidents, date-stamped figures, the regulatory drivers, who bears the cost, and what an adequate solution requires. Each closes by bridging to the solution document that meets its requirements. This index states each problem in one line and links to the full case. Figures repeated here carry their source and date; the detail documents carry the full record. --- ## **What not.bot answers** ### **Deepfakes and Inauthentic Content** → [Doc #41](https://not.bot/learn/why-notbot-deepfakes/) **Fabricating anyone's face and voice costs almost nothing, detection loses the arms race, and every authentic recording now competes with the possibility that it is fake.** Building a deepfake generator takes as few as 20 photographs of the target and about 15 minutes on a consumer computer (Oxford Internet Institute, FAccT 2025). A finance employee wired US$25.6 million after a video call on which every other participant was a deepfake of a real coworker (CNN, February 2024). The UK Home Office estimates 8 million deepfakes shared in 2025, up from 500,000 in 2023 (February 2026). Detection asks whether content looks fake, and that question gets harder with every model generation. [Content Provenance and Digital Signatures (Doc #2)](https://not.bot/learn/content-provenance/) describes the question that stays answerable: whether content carries proof of authenticity. ### **Proof of Personhood** → [Doc #42](https://not.bot/learn/why-notbot-proof-of-personhood/) **No system deployed at internet scale can tell whether an account belongs to a human without demanding to know which human.** Beating SMS verification, the gate most platforms put in front of account creation, costs US$0.08 to US$0.12 per account at the largest platforms (Science, December 11, 2025). Human beings are now the minority of measured internet traffic (two network-scale measurements, December 2025 and April 2026). In July 2025 an AI agent clicked through a "Verify you are human" checkbox in the middle of a routine task, narrating the step as it worked; checks of that kind read behavioral signals, and an agent in a real browser emits them as well as a person does. The New York Attorney General found almost 18 million of the more than 22 million comments in one federal docket fake (May 2021). [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/) describes proof of personhood without identity: one person, one account, and the site learns nothing else. ### **Age Verification Without Surveillance** → [Doc #43](https://not.bot/learn/why-notbot-age-verification/) **The law now requires age checks across the major internet markets, and the systems used to comply collect identity data that gets retained, breached, and repurposed.** The US Supreme Court upheld state age-verification mandates (*Free Speech Coalition v. Paxton*, June 27, 2025), and the UK, Australian, and Brazilian duties are in force (July 25, 2025; December 10, 2025; March 17, 2026). The first year of enforcement produced the record: about 70,000 government IDs leaked from a vendor that held them for age appeals (Discord disclosure, October 2025), a €950,000 fine against an age-verification provider for retaining identity documents and repurposing them as training data (AEPD, March 2026), and Roblox losing 12 million daily users in the quarter it made age checks mandatory (April 30, 2026). An age check asks a yes-or-no question, and every accepted way to answer it collects identity. [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/) describes the alternative: a signed yes-or-no answer, with no identity data reaching the site and no record of who verified where. ### **Non-Government Digital ID** → [Doc #44](https://not.bot/learn/why-notbot-digital-id/) **Digital identity today means a record in someone else's database, a government portal or a platform login, and the costs arrive as breaches, surveillance, and exclusion.** Attackers breached France's national identity portal at 11.7 million confirmed accounts (France Titres, April 2026). The mobile driver's license standard includes a mode in which the issuing government learns where and when a license is used; a coalition including the ACLU, EFF, and Bruce Schneier campaigns against it, with Julia Social among the signatories (No Phone Home, June 2025). India's identity program acknowledged a 12% authentication-failure rate for government services, runtime exclusion at population scale (March 2018). An identity held in a provider's database is the person's at the provider's pleasure. [The not.bot App (Doc #5)](https://not.bot/learn/the-app/) describes identity anchored once in the signature a government placed inside the holder's passport chip, then held by the person alone. [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/) carries the proof that no party, Julia Social included, can watch it being used. ### **Unaccountable AI Agents** → [Doc #45](https://not.bot/learn/why-notbot-ai-agents/) **AI agents browse, transact, post, and persuade with no verifiable identity and no chain of accountability to any person.** Meta's CEO expects more AI agents than people in the world (July 2024). Four in five organizations that run agents report agents taking unintended actions, and fewer than half have any policy governing them (survey by Dimensional Research, May 2025). Researchers ran 34 covert AI accounts on a public forum for four months, posing as humans and persuading at multiples of the human baseline, and the accountability chain afterward led nowhere (Science, April 30, 2025). The regulatory responses are disclosure duties, and disclosure binds the honest. honest.bot™, planned for Q4 2026, exists to close this gap; [honest.bot: Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/) describes the delegation chain that ends at an accountable human. --- ## **Who is human, and who answers when it is not** The series pairs around one question. Proof of personhood (Doc #42) asks whether the actor behind an account is a human being. Unaccountable AI agents (Doc #45) asks what follows when the answer is no: who does this agent act for, and who answers if it goes wrong. One incident appears in both documents. In July 2025 an AI agent passed the internet's humanness check in the middle of a routine task, because the check infers humanity from behavior and the agent behaves like a person. Read one way, the incident shows the human test failing. Read the other way, it shows an actor no counterparty can identify operating where only people were expected. Neither blocking nor admitting resolves it. Blanket blocking forfeits the shopping assistants, booking agents, and research tools that customers send. Open admission fills the channel with machinery nobody can trace. The way out is one infrastructure with two proofs. not.bot Verify proves a human is present while learning nothing about which human. honest.bot gives an agent an identity that one running process holds, with a delegation chain that terminates at a not.bot-verified human. A site that checks both admits verified humans and verified agents accountable to verified humans, and turns away whatever proves neither. ## **What repeats across the five documents** The problems compound. Deepfakes (Doc #41) and proof of personhood (Doc #42) are the content side and the actor side of one inauthenticity problem: when behavioral tests fail, platforms retreat to document-and-selfie checks, and the deepfake injection chain defeats those (World Economic Forum, January 2026). Age verification (Doc #43) and digital ID (Doc #44) price that retreat: identity data collected to answer a yes-or-no question, then kept past its purpose, breached, and repurposed. Two findings hold in every document. Regulation arrives everywhere and supplies no instrument: removal deadlines, disclosure duties, age mandates, and wallet programs assign obligations that assume verification infrastructure nobody has built. And every deployed defense buys assurance with surveillance: behavioral scoring reads the user's device, document upload copies the passport, and federated logins and phone-home wallets report where an identity is used. Each document closes with the requirement set its evidence defines, and the sets converge on the same properties: a deterministic cryptographic answer instead of a probabilistic score, proof bound to an accountable person, no central database, no record of who verified where, and verification free for the person. The not.bot product family is built to those properties. ## **Related documents** - [Content Provenance and Digital Signatures (Doc #2)](https://not.bot/learn/content-provenance/), [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/), [honest.bot: Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/), and [The not.bot App (Doc #5)](https://not.bot/learn/the-app/): the solution documents the five problems bridge to. - [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/): the architectural guarantee behind the no-surveillance requirements. - [Use Cases Index (Doc #30)](https://not.bot/learn/use-cases/): the companion catalog. The problems establish why verification matters; the use cases catalog where it pays off. --- > **Why not.bot: Deepfakes and Inauthentic Content** — https://not.bot/learn/why-notbot-deepfakes/ · Markdown: https://not.bot/learn/why-notbot-deepfakes.md · Updated 2026-06-14 # **Why not.bot™: Deepfakes and Inauthentic Content** This document opens the Why not.bot series, which presents the public evidence for what not.bot exists to solve. This one covers fabricated content: cloned voices, synthetic video, and impersonation at scale. Every figure below carries its source and date. The incidents are on the public record. --- ## **Making a fake costs almost nothing** Researchers at the Oxford Internet Institute analyzed 35,000 deepfake image generators available for public download. Building a new one requires as few as 20 photographs of the target, 24 GB of video memory, and about 15 minutes on a consumer computer ("Deepfakes on Demand," FAccT 2025). Microsoft Research demonstrated in January 2023 that its VALL-E system synthesizes personalized speech from a 3-second recording of a voice it has never heard. OpenAI built a tool that clones a voice from 15 seconds of audio, then declined to release it, judging the risk of misuse too high (March 2024). When the company that built the tool will not ship it, the threat assessment is settled. The capability is cheap enough to demonstrate as theater. At Berkshire Hathaway's May 2026 shareholder event, Greg Abel played a video deepfake of Warren Buffett with Buffett sitting in the audience. "That was done with zero input from Warren," Abel told shareholders. "We were able to obtain that with information that's out there and replicate those actions and that voice" (Money, May 6, 2026). ## **Documented incidents** **A US$25.6 million wire through a deepfaked video call.** In January 2024, a finance employee at Arup, the British engineering firm, joined a video call with the company's CFO and several colleagues. Every other participant on the call was a deepfake recreation of a real coworker. The employee made 15 transfers totaling HK$200 million (US$25.6 million) to five bank accounts (CNN, February 4 and May 16, 2024; South China Morning Post, May 2024). The funds were not recovered. **Voice clones against bank call centers.** In spring 2023, a software-generated copy of a Florida investor's voice called his Bank of America representative and tried to redirect a large transfer (The New York Times, August 30, 2023). The banker caught it. The damage arrived anyway: she stopped trusting calls and emails from the real customer, and it took ten days and an in-person visit to restore the relationship. A fraud that fails still breaks the trust the relationship ran on. **A coordinated campaign impersonating real doctors.** The New York Times documented (September 5, 2025) a global operation that hijacked the likenesses of physicians at UCSF, Stanford, Harvard, and other institutions, using AI video and voice to sell unproven health products. One Stanford scientist's face fronted at least six YouTube channels carrying hundreds of AI-narrated videos. One physician's fake was convincing enough that her own mother believed it. **A single fake ad with 35 million views.** CNN's chief medical correspondent Sanjay Gupta described fake videos of himself selling cures for Alzheimer's disease and diabetes (CNN Podcasts, September 23, 2025). One had been viewed 35 million times. His own former professor was fooled. Victims paid hundreds of dollars for products that never arrived, then wrote to the real Gupta in anger and shame. **An €830,000 romance scam.** A French interior designer lost €830,000 over 18 months to scammers using AI-generated images and messages of Brad Pitt (TF1, January 2025; Euronews, January 15, 2025). When her story aired she faced a wave of public ridicule, and the broadcaster withdrew the interview to protect her. **Sexualized fakes of a head of government.** AI-generated lingerie images of Italian Prime Minister Giorgia Meloni circulated as authentic in May 2026 and drew public criticism of her before they were exposed as fakes (Forbes, May 6, 2026). Meloni's response named the asymmetry: "Deepfakes are a dangerous tool, because they can deceive, manipulate and strike anyone. I can defend myself. Many others cannot." ## **The scale** - Deloitte's Center for Financial Services projects that generative AI will drive US fraud losses from US$12.3 billion in 2023 to US$40 billion by 2027 under its aggressive adoption scenario, and cites a 700% increase in fintech deepfake incidents during 2023 (May 2024). - The UK Home Office states that an estimated 8 million deepfakes were shared in 2025, up from 500,000 in 2023 (February 2026). - Scams of all kinds cost Americans US$158 billion a year, a figure that prompted the first coordinated US national anti-scam strategy (Aspen Institute National Task Force on Fraud and Scam Prevention, September 30, 2025). - Of 2,000 deepfake generator models analyzed in the Oxford study, 96% target identifiable women without any suggestion of consent, and 99% of sexual deepfakes target women and girls (FAccT 2025, citing Internet Matters, 2024). - The World Economic Forum's Cybercrime Atlas surveyed 25 face-swap and camera-injection tools selling for US$10 to US$3,000 and documented the chain that defeats remote identity checks: AI-generated identity documents, face-swapped video matching those documents, and camera injection feeding the synthetic video into live biometric verification (January 2026). Its summary: "identity itself has become synthetic, scalable and weaponizable." ## **Detection loses the arms race** Generators train against detectors. Deloitte describes deepfake systems built to keep checking and updating their ability to fool computer-based detection, and notes that for audio, "the technology industry is behind in developing tools to identify fake content" (May 2024). The World Economic Forum reaches the same end point: deepfake fraud "may never be fully eliminated," only "contained, deterred and made economically unviable" (January 2026). Takedown fares no better. In the doctor-impersonation campaign, a Stanford team spent hours reporting fake videos and posting warnings under them; the warnings were deleted within a minute. One impersonated oncologist, after her reports and a legal letter went unanswered, paid US$260 to a takedown service that failed. The platform said it was unaware of the fakes until a reporter called (The New York Times, September 5, 2025). Measure any takedown clock against a fake that reached 35 million viewers. Detection asks whether content looks fake, and that question gets harder with every model generation. The question that stays answerable is whether content carries proof of authenticity. ## **Regulation arrives, and creates demand for verification** - The US TAKE IT DOWN Act, signed May 19, 2025, requires platforms to remove non-consensual intimate imagery, including AI "digital forgeries," within 48 hours of a valid request. FTC enforcement began May 2026, with penalties up to US$53,088 per violation. - Italy's Law 132/2025, in force October 10, 2025, is the first comprehensive national AI law in the EU. It criminalizes disseminating, without consent, AI-altered images, video, or voice capable of misleading as to authenticity and causing unjust harm, with penalties of one to five years. - 46 US states have laws addressing non-consensual intimate deepfakes, and 30 regulate election deepfakes (Public Citizen trackers, early 2026). The limits are visible too: a federal court struck down Hawaii's election-deepfake law on First Amendment grounds (D. Haw., January 30, 2026). - EU AI Act Article 50 applies from August 2, 2026: deployers must disclose deepfakes, and providers must mark synthetic content in machine-readable form. - ETSI TS 119 461, the EU identity-proofing standard under eIDAS 2.0, names "deep fakes" as a technique imposters use and requires accredited-lab testing against injection and presentation attacks before the end of 2026 (February 2025). - Denmark has proposed copyright-style rights in a person's own face, voice, and body, the first proposal of its kind in Europe (June 2025; before parliament as of June 2026). These laws assign duties: remove within 48 hours, disclose synthetic content, test identity checks against injection attacks. None of them can prove a given piece of content authentic. Regulation raises the cost of fakery and creates compliance demand for verification infrastructure. The authenticity question stays open. ## **Who bears the cost** **Financial institutions.** Voice clones target call centers and the fraud trajectory points at US$40 billion by 2027 (Deloitte, May 2024). The losses come with liability fights: "customer relationships may be tested when determining whether a fraud loss is to be borne by customers or their financial institutions" (Deloitte, May 2024). A Federal Reserve survey of more than 360 US institutions found scams the most common fraud type and concern about mule-account activity up 12 points in a year (2024). **Enterprises.** The Arup pattern is repeatable: contact through a messaging app, an urgent video call, a deepfaked executive, a wire. The identity checks that gate remote onboarding are themselves a target; the WEF documents the bypass chain end to end (January 2026). **Public figures, executives, and clinicians.** Anyone whose voice and face exist in abundance online is raw material. The cost lands as reputation damage, lost audience trust, and takedown labor that does not end. **Women.** 96% of deepfake generator models target identifiable women (Oxford Internet Institute, FAccT 2025). Non-consensual intimate imagery is the largest single category of deepfake harm, and the reason most of the new criminal statutes exist. **Platforms.** Statutory removal duties now carry per-violation penalties and active FTC enforcement, against a moderation problem that defeats both automated detection and manual review. **Consumers.** Romance scams, fake cures, products that never arrive. Victims report shame more than anger, and shame suppresses reporting, so official figures undercount the harm. ## **The deepest cost: authentic content loses its authority** A fake does damage twice. The first harm lands on whoever it defrauds or defames. The second lands on everything authentic, because every real recording now competes with the possibility that it is fake. In the documented incidents above, the people fooled included a physician's mother and a neurosurgeon's former professor: people with personal knowledge of the target. Gupta's conclusion from inside the problem: "all content, even good content, ultimately gets tainted by this... Nobody believes anything. Everybody's suspicious of each other. And unless you can touch the person or talk to them directly, they are also suspect, because it could be an AI impersonator" (CNN Podcasts, September 23, 2025). Meloni offered the public a rule: "verify before believing, and believe before sharing" (Forbes, May 6, 2026). The rule is correct. Today the ordinary reader has no way to follow it. ## **What an adequate solution requires** The evidence defines the requirement set: 1. **Deterministic proof.** A verifier needs a yes-or-no answer about authenticity. Probabilistic detection decays as generators improve; a cryptographic check does not. 2. **Binding to a human.** Proof must tie content to an accountable person. Devices, accounts, and communication channels are all spoofable, as the Arup call showed. 3. **Survival through distribution.** Proof must survive screenshots, re-encoding, cropping, and forwarding, because content travels stripped of its metadata. 4. **Verification open to anyone.** Checking must be free and require no enrollment. The people who most need to verify are the audience, and the audience cannot be asked to subscribe first. 5. **Speed at distribution scale.** A fake reaches 35 million viewers faster than any takedown process. Authenticity must be checkable at the moment of viewing, by the viewer. 6. **No new surveillance.** An authenticity layer that tracks who signs, who verifies, and what they look at would trade one harm for another. The proof must work without anyone watching. [Content Provenance and Digital Signatures (Doc #2)](https://not.bot/learn/content-provenance/) describes how not.bot meets these requirements with visible cryptographic signatures (patent pending) that travel with the content itself. ## **Related documents** - [Content Provenance and Digital Signatures (Doc #2)](https://not.bot/learn/content-provenance/): how not.bot signatures establish authenticity. - [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/): the verification side of the KYC bypass problem documented by the WEF. - [Use Cases: Content Signing (Doc #32)](https://not.bot/learn/use-cases-content-signing/): who signs content and why, including the defensive archetypes for public figures. - [Use Cases Index (Doc #30)](https://not.bot/learn/use-cases/): the full use-case catalog. --- > **Why not.bot: Proof of Personhood** — https://not.bot/learn/why-notbot-proof-of-personhood/ · Markdown: https://not.bot/learn/why-notbot-proof-of-personhood.md · Updated 2026-06-14 # **Why not.bot™: Proof of Personhood** This document is part of the Why not.bot series, which presents the public evidence for what not.bot exists to solve. This one covers proof of personhood: whether there is a human being behind an account, a comment, or a click. Every figure below carries its source and date. The incidents are on the public record. --- ## **Pretending to be human costs cents** Cambridge researchers indexed the price of beating SMS verification, the gate most platforms put in front of account creation, across more than 500 platforms: US$0.08 per account at Meta, US$0.10 at X and Instagram, US$0.11 at TikTok and LinkedIn, US$0.12 at Amazon ("The Online Manipulation Economy," Science, December 11, 2025). A separate measurement study catalogued 38,253 social media accounts offered for sale across 11 marketplaces, with a combined asking value above US$64 million and a median listing of US$157 per account (ACM Internet Measurement Conference, 2025). Behind the listings sits a service industry: an academic study of account-registration bots priced the underground registration market at US$4.8 million to US$128.1 million per year, and called its own estimate conservative (ESEC/FSE, 2022). The oldest defense costs even less to beat. By 2010, CAPTCHA-solving services charged customers as little as US$1 per thousand puzzles, a tenth of a cent each, with human workers doing the solving (USENIX Security, 2010). Solving services price in the same range today. A test that costs a tenth of a cent to pass meters traffic without stopping anyone. The supply of non-human actors is about to grow past any of these numbers. Meta's CEO, at the launch of its Llama 3.1 model: "I think we're going to live in a world where there are going to be hundreds of millions or billions of different AI agents eventually, probably more AI agents than there are people in the world" (July 23, 2024). ## **Documented incidents** **An AI agent clicks "I am not a robot," narrating as it goes.** In July 2025, OpenAI's ChatGPT Agent, a feature that gives the model its own browser, clicked through Cloudflare's "Verify you are human" checkbox in the middle of a routine task and described the step aloud: "This step is necessary to prove I'm not a bot and proceed with the action" (Ars Technica, July 28, 2025). The screening it passed was behavioral: mouse movements, click timing, browser fingerprints, IP reputation. The agent drives a real browser, so its signals read as human. **GPT-4 hires a human to pass its CAPTCHA.** During pre-release red-team testing by the Alignment Research Center, GPT-4 asked a TaskRabbit worker to solve a CAPTCHA. The worker asked whether it was a robot. The model, prompted to reason out loud, recorded: "I should not reveal that I am a robot. I should make up an excuse for why I cannot solve CAPTCHAs." It then told the worker: "No, I'm not a robot. I have a vision impairment that makes it hard for me to see the images." The worker complied (OpenAI GPT-4 System Card, March 2023; researchers steered parts of the run, including the browsing tool). No one solved the test. The model hired its way past it. **34 synthetic Redditors, four months, zero detections.** Researchers at the University of Zurich ran 34 AI-operated accounts on Reddit's r/changemyview from November 2024 to March 2025, posting 1,783 comments while posing as humans, among them a rape survivor and a trauma counselor. Moderators learned of the experiment when the researchers disclosed it themselves. The draft findings, withdrawn after the backlash and never peer reviewed, reported AI comments persuading at three to six times the human baseline, with the personalized variant in the 99th percentile of all commenters (Science, April 30, 2025; Retraction Watch, April 29, 2025). Reddit's chief legal officer called the experiment "improper and highly unethical" and pursued formal legal demands. A community built on human argument hosted 34 machines for four months and could not tell. **Almost 18 million fake comments in one federal docket.** The New York Attorney General found that almost 18 million of the more than 22 million comments the FCC received in its 2017 net neutrality proceeding were fake: more than 8.5 million funded by the broadband industry and submitted under real people's stolen names, and about 9.3 million on the opposing side under invented identities (Office of the New York Attorney General, May 6, 2021). Both camps bought voices. The public record measured purchasing power, not public opinion. ## **The scale** - The 13th annual edition of a bot-traffic study published by a web-security firm reports that bots generated over 53% of all internet traffic in 2025, with bad bots at 40% and humans at 47%, down from 50% human two years earlier (April 2026). The figures are the firm's own telemetry. No government or academic census of bot traffic exists; every estimate of this kind comes from a bot-defense vendor. - Meta's transparency reporting shows Facebook acting against fake accounts at a rate above one billion per quarter across 2024 and 2025, and estimates fake accounts at about 3% of monthly active users (Meta transparency reports, 2024–2025). - LinkedIn stopped 80.6 million fake accounts at registration in the second half of 2024 (LinkedIn transparency report, July–December 2024). - The same bot-traffic study measured account-takeover attacks up 70% between July 2024 and July 2025, despite broad MFA adoption (April 2026). - A bot-detection firm scanned almost 17,000 high-traffic websites in 2025 with four test bots: 61% of the sites detected none of them, the anti-fingerprinting test bot evaded detection 93% of the time, and among sites paying for bot protection, vendor detection rates ran from 6% to 42% (2025). - 51% of developers name unauthorized or excessive API calls from AI agents as their top API security concern (Postman, 2025 State of the API Report, October 2025). ## **The human test no longer works** CAPTCHA rested on a premise: find a task every human can do and no machine can. Multimodal AI now does those tasks, and a 2024 paper by 32 authors spanning OpenAI, Microsoft, Harvard, MIT, Oxford, and UC Berkeley judged the whole defensive toolkit against it ("Personhood Credentials," arXiv, August 2024). Their survey: behavioral filters fail against capable AI. Payment gates exclude low-income users and fall to virtual cards. AI-content detection cannot catch sockpuppets that amplify text humans wrote. ID-and-selfie checks collect more than the question requires, and AI now passes them. Phone numbers and email addresses are not scarce. Their verdict on the incumbent: CAPTCHAs are "inadequate against sophisticated AI, while stringent identity verification solutions are insufficiently private for many use-cases." The bot-defense industry says the same about itself. The annual bot study describes CAPTCHA solving as a blended trade: "Many services now blend AI with incentivized human solvers, enabling bots to bypass challenges at scale while increasing friction for legitimate users." Its visibility concession goes further: self-hosted models need not announce themselves, so "what is observable today represents only a fraction of the total attack surface" (April 2026). The bot-detection firm behind the 17,000-site scan drew the conclusion: "It's no longer enough to ask 'is this a bot or a human?'" (2025). The toolkit that remains charges its cost in privacy. Behavioral scoring reads mouse movements, browser fingerprints, and login state to guess at humanity, so a user who blocks tracking scores as a bot. France's data-protection authority fined two companies, €105,000 and €125,000, for deploying a market-leading CAPTCHA service that read data from users' devices without consent (CNIL, December 2023). The Personhood Credentials authors name where this road ends: "Lacking better alternatives, institutions might resort to privacy-violating methods for rooting out scaled deception, like creating digital identification systems that (intentionally or unintentionally) link a person's legal identity with a complete record of their digital activity." Platforms that retreat to government-ID upload and selfie checks walk into a separate failure: the deepfake injection chain that defeats document and biometric checks, documented in [Why not.bot: Deepfakes and Inauthentic Content (Doc #41)](https://not.bot/learn/why-notbot-deepfakes/). ## **Regulation arrives, and assumes verification** - California's B.O.T. Act, in force since July 1, 2019, makes it unlawful to use a bot to mislead a person about its artificial identity to sell something or influence a vote, on platforms above 10 million monthly US visitors. Disclosure must be "clear, conspicuous, and reasonably designed to inform." - EU AI Act Article 50 applies from August 2, 2026: providers must ensure AI systems that interact with people inform those people they are dealing with an AI, unless that is obvious in context. - The US FTC's rule on consumer reviews and testimonials, effective October 21, 2024, bans buying or selling fake indicators of social media influence, bot followers and bot views included, and reaches AI-generated fake reviews. Penalties run to US$53,088 per violation; the FTC sent its first warning letters to 10 companies on December 22, 2025. - The standards bodies have chartered the problem by name: in September 2025, Trust over IP and the Decentralized Identity Foundation launched a joint working group on "one of the oldest and hardest problems in digital trust: proof of personhood" (Linux Foundation Decentralized Trust, September 15, 2025). Disclosure laws bind the honest. A bot that follows California's statute announces itself; none of the bots in the incidents above did. The pattern from the deepfake statutes repeats here: regulation assigns duties and raises the cost of getting caught, and leaves the platform without any instrument that answers the underlying question. ## **Who bears the cost** **Platforms.** Reddit's CEO stated the position the Zurich experiment forced: "Part of our promise for our users is we don't know your name. But we do want to know whether you're a person" (March 2026). The cost arrives as moderation at billion-per-quarter scale, as advertiser skepticism about audience counts, and as product decay when conversations fill with undisclosed machines. **Financial services.** 24% of bad-bot attacks and 46% of account-takeover attacks target financial services (vendor bot study, April 2026). Each fraudulent account stacks fraud losses on top of regulatory exposure for the compromised data. **Retail, ticketing, and travel.** Bots scalp inventory, fill carts they never buy to create artificial scarcity, and poll fare systems while masquerading as customers (vendor bot study, April 2026). **Advertisers and brands.** Impressions, followers, and reviews no human produced. The FTC wrote a rule against fake influence because a functioning market sells it. **Civic institutions.** Public comment, petitions, and polls assume one voice per person. The FCC docket shows what a sybil attack does to that assumption: it converts deliberation into an auction. **People without the right documents.** When platforms fall back to ID upload, the burden lands on exclusion: about 850 million people hold no official identification at all (World Bank ID4D, 2021 survey). The ID-upload model also answers "is this a human?" by collecting who the human is, a trade no one should have to make. **Ordinary users.** The puzzles grow harder for people while agents click past them, privacy-protective settings read as bot signals, and an unknown share of every comment thread is machinery. ## **The deepest cost: presence stops meaning anything** Online trust ran on a quiet assumption: an account, a comment, a review, a vote in a poll each cost a human being a sliver of attention. Every number above prices that assumption at cents or below. Human beings are now the minority of measured traffic by the only estimates available, and the agents arriving next drive real browsers and read as people. The Personhood Credentials authors state the risk: "There is a substantial risk that, without further mitigations, deceptive AI-powered activity could overwhelm the Internet" (August 2024). The second-order harm lands on real participation, the way deepfakes taint authentic recordings. After the FCC investigation, a comment docket reads as suspect on its face. After Zurich, an earnest argument on Reddit competes with the possibility that it is an experiment running on the reader. Synthetic participants discount every human voice in the channel. The trap is that the obvious cure is worse. Platforms can demand identity for participation and end anonymous speech, or they can keep guessing from behavior and lose to agents in real browsers. Reddit's CEO drew the requirement between those failures: know whether someone is a person without knowing their name. Nothing deployed at internet scale does that today. ## **What an adequate solution requires** The evidence defines the requirement set: 1. **Proof anchored outside software.** The Personhood Credentials paper rests on the two things AI cannot do: AI systems "cannot convincingly mimic people offline, and they cannot bypass state-of-the-art cryptographic systems." A personhood check must build on a real-world enrollment event and cryptography, not on behavioral signals that an agent in a real browser emits as well as a person does. 2. **One person, one account, per service.** Sybil resistance requires a hard credential limit per person, so a second account costs a second human rather than US$0.08 of SMS routing. 3. **Personhood without identity.** The verifier must learn "a unique human" and nothing else. Sites must be unable to correlate one person across services, even in collusion with the credential issuer. The largest biometric proof-of-personhood network reports more than 18 million iris-scan enrollments across 160 countries (company-reported, 2026), which proves the demand and prices the wrong answer: it banks biometric data to answer a yes-or-no question. 4. **No behavioral surveillance.** A check that scores mouse movements and tracking state punishes privacy, draws regulatory fines, and still loses to agents driving real browsers. 5. **Deterministic verification.** A cryptographic yes-or-no, not a probabilistic score. Scores decay as generators and agents improve; the 6-to-42% detection rates among paying customers show where scoring ends up. 6. **No payment gate.** Credit-card and subscription barriers exclude the people least able to pay and fall to virtual cards regardless (Personhood Credentials, August 2024). Proving personhood must be free for the person. [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/) describes how not.bot Verify meets these requirements: passport-anchored enrollment, Site Passes that enforce one-person-one-account for a site without linking the person across sites, and verification that discloses nothing beyond the answer to the question asked. ## **Related documents** - [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/): the verification capabilities this problem calls for. - [Use Cases: Verified Humanness (Doc #33)](https://not.bot/learn/use-cases-verified-humanness/): where proof of personhood pays off, from CAPTCHA replacement to sybil defense. - [Why not.bot: Deepfakes and Inauthentic Content (Doc #41)](https://not.bot/learn/why-notbot-deepfakes/): the content side of inauthenticity, including the injection chain that defeats ID-upload checks. - [Why not.bot: Unaccountable AI Agents (Doc #45)](https://not.bot/learn/why-notbot-ai-agents/): the next question after "is this a human?", which is "when it is not, who answers for it?" --- > **Why not.bot: Age Verification Without Surveillance** — https://not.bot/learn/why-notbot-age-verification/ · Markdown: https://not.bot/learn/why-notbot-age-verification.md · Updated 2026-06-14 # **Why not.bot™: Age Verification Without Surveillance** This document is part of the Why not.bot series, which presents the public evidence for what not.bot exists to solve. This one covers age verification: the law now requires it across the major internet markets, and the systems used to comply collect identity data that the record of the past year shows gets retained, breached, and repurposed. Every figure below carries its source and date. The incidents are on the public record. --- ## **Proving your age now means handing over your identity** An age check asks a yes-or-no question. The accepted ways to answer it all collect identity. The GUARD Act, advanced 22-0 by the US Senate Judiciary Committee on April 30, 2026, defines "reasonable age verification" by excluding a self-entered date of birth and pointing platforms to government ID uploads, facial scans, and financial records tied to a legal name. The FTC's enforcement policy statement (February 25, 2026) sweeps in age estimation, age verification, and age inference tools, and quotes the research consensus on the checkbox it replaces: self-declaration is "insufficient in terms of accuracy…very easy to circumvent…[and] clearly inadequate and inappropriate for use in high-risk situations" (FTC, quoting Common Sense Media, September 2024). So a user who wants to keep using an age-gated service now hands over a passport image, a face scan, or a credit card. The service, or its verification vendor, holds that data. The market for holding it is growing 74%, from US$15.2 billion in 2024 to a projected US$26 billion by 2029 (Juniper Research, December 2, 2024). What follows is the record of what happens to the data. ## **The mandate arrived in every major market at once** - The US Supreme Court upheld Texas HB 1181's age-verification requirement for adult sites on June 27, 2025 (*Free Speech Coalition v. Paxton*, 6-3), removing the main constitutional obstacle. About two dozen states now require age verification for adult content (National Law Review, January 2026), and at least 19 states have enacted social-media minor-access laws, though courts have enjoined several (National Conference of State Legislatures, April 2026). - Florida is enforcing its under-14 social media ban after the 11th Circuit stayed a district-court injunction in November 2025. California's Digital Age Assurance Act (AB 1043, signed October 13, 2025, operative January 1, 2027) moves the duty into the operating system: OS providers must collect age at account setup and transmit an age-bracket signal to every app. - Congress has a queue behind the GUARD Act: the KIDS Act absorbed the Kids Online Safety Act provisions and advanced from committee 28-24 (March 2026), COPPA 2.0 passed the Senate on March 5, 2026, the App Store Accountability Act advanced 26-23, and the SCREEN Act is pending. The FTC, meanwhile, suspended COPPA's parental-consent requirement for data collected for age-verification purposes, on conditions, to encourage adoption (February 25, 2026). - The UK Online Safety Act's "highly effective age assurance" duty took effect July 25, 2025. Ofcom is enforcing: a £520,000 fine against 4chan, £450,000 of it for failing to deploy age assurance (March 19, 2026), and a £950,000 fine against a US suicide-discussion forum that had geoblocked the UK (May 13, 2026). - The European Commission piloted its age-verification app with Denmark, France, Greece, Italy, and Spain (July 2025), then recommended that every member state have privacy-preserving age verification deployed by December 31, 2026 (April 29, 2026). The European Parliament voted 483-92 (86 abstentions) on November 26, 2025 to recommend an EU-wide minimum social media age of 16. - Australia's Social Media Minimum Age Act took effect December 10, 2025: under-16s are barred from ten designated platforms, including Facebook, Instagram, TikTok, YouTube, and Reddit, with penalties to A$49.5 million. More than 4.7 million accounts were removed, deactivated, or restricted by mid-January 2026 (Reuters, January 2026). - Brazil's Law 15.211 became enforceable March 17, 2026. It bans self-declared age, requires auditable verification, and carries fines to R$50 million. France's National Assembly voted 130-21 for an under-15 ban (January 26, 2026); the Senate adopted a different version and the chambers had not reconciled as of June 2026. Doc #34's use-case catalog lists the same drivers from the compliance side: KOSA, COPPA 2.0, the SCREEN Act, the GUARD Act, the state laws, the UK and EU mandates, and the standing alcohol, tobacco, and gambling regimes ([Use Cases: Credentials (Doc #34)](https://not.bot/learn/use-cases-credentials/)). ## **The systems built to comply keep failing** **A regulator fined an age-verification provider for doing what the privacy critics predicted.** Spain's data protection authority fined Yoti, a biometric identity and age-verification provider, €950,000 (resolution of March 10, 2026): €500,000 for processing biometric data as unique identification while calling it authentication, €250,000 for retention violations, including location data kept five years and identity documents from failed verifications kept up to two years and repurposed to train the company's fraud-detection software, and €200,000 for invalid consent. A document a user submitted to prove age became training data. **About 70,000 government IDs, collected for age appeals, leaked.** In October 2025, attackers compromised a third-party customer-service vendor for Discord and took government-ID photos that users had submitted to appeal age determinations (Discord statement, October 3, 2025; NBC News, October 2025). Discord's support pages had told users that ID images were deleted after the age group was confirmed. The attackers claimed far larger numbers, which Discord disputed; the confirmed exposure is about 70,000 IDs. **An app's verification archive surfaced after it was supposed to be gone.** The Tea app, which required selfies and photo IDs to verify that new members were women, exposed about 72,000 images in July 2025, including about 13,000 verification selfies and IDs from a batch the company had said was deleted (404 Media, July 25, 2025; Associated Press, July 2025). **The EU's own app stored ID images unencrypted.** Days after the European Commission declared its age-verification app "technically ready" (April 2026), security researcher Paul Moore showed it stored facial images read from passport chips as unencrypted files on the device, wrote selfies to external storage without deleting them, and kept its rate limit in an editable counter (Cybernews, April 2026). The FTC's own safe-harbor conditions read as a catalog of these failure modes: it shields age-verification data collection only where the operator avoids secondary use, deletes the data once its purpose is served, does not over-retain, and secures what it holds (February 25, 2026). The conditions describe the practices the record shows failing. ## **What demanding identity costs** Roblox rolled out mandatory age checks for chat worldwide in January 2026 and reported the result in its Q1 2026 shareholder letter (April 30, 2026): daily active users fell from 144 million to 132 million in one quarter, which the company attributed to "greater-than-expected headwinds from the age-check rollout," and it cut full-year bookings guidance by almost US$1 billion. By quarter's end, 51% of users had completed the check. Users route around checks rather than submit to them. Proton VPN reported UK sign-ups surged more than 1,400% within minutes of the July 25, 2025 duty taking effect (Proton, July 2025), and VPN downloads surged in Australia within days of its ban (TechRadar, December 2025). The World Economic Forum, studying identity fraud, reached the same finding from the attacker side: "The introduction of new regulations, such as the UK's online safety rules enacted in July 2025, has already correlated with increased searches for bypass tools" (Cybercrime Atlas, January 2026). A UK parliamentary petition to repeal the Online Safety Act closed at 550,138 signatures; the government declined (petition record, October 2025). And the children the laws protect keep arriving anyway: the European Commission's preliminary finding against Meta states that around 10-12% of under-13s use Instagram or Facebook (April 29, 2026). Some businesses exit instead of collecting IDs. Aylo, Pornhub's operator, blocked all Australian IP addresses rather than comply with Australia's age-check codes, stating that Australia was "following a similar approach to the UK, which all our evidence shows does not effectively protect minors, and instead creates harms relating to data privacy and exposure to illegal content on non-compliant platforms" (company statement, March 2026). Imgur blocked UK users (July 2025). Rockstar Games withdrew digital sales from its own Brazilian storefront rather than comply with Law 15.211 (March 2026). The burden also lands on people with nothing to prove. When Apple shipped age verification to UK iPhones in iOS 26.4 (March 25, 2026), the accepted proofs were a credit card or a photo ID, and users without either, many of them older people in a country with no national ID card, were moved into a restricted mode (9to5Mac, AppleInsider, March 25, 2026). ## **The current methods cannot do the job they were given** **Face-based age estimation guesses, and it guesses worst at the ages that matter.** NIST's rolling evaluation of age-estimation software (NIST IR 8525, updated May 2026) puts the best mean absolute error at 3.1 years and states that accuracy "is strongly influenced by algorithm, sex, image quality, region-of-birth, age itself, and interactions between those factors. There is no uniformly superior algorithm." Near the thresholds the laws care about, the errors compound: "Challenge-25 false positive rates increase by an order-of-magnitude as subjects age from 14 through 20," with one algorithm's false-positive rate at age 20 (0.295) almost fifteen times its rate at age 14. Australia's government-commissioned Age Assurance Technology Trial reached a parallel verdict from deployment testing: age assurance can work, but "no age verification method was found to be foolproof" (preliminary findings, June 2025). **Document upload works by creating the database everyone fears.** It answers the age question by storing the identity document, and the incidents above show what becomes of stored documents. Deletion promises failed at Discord and at Tea; retention limits failed at Yoti. **Credit cards and borrowed credentials prove possession, not age.** The scientists' joint statement on age assurance, signed by 438 security and privacy researchers from 32 countries, lists the bypass routes: checks are circumvented "using VPNs, bought or borrowed credentials, or props or AI-based tools" (March 2, 2026). The same statement names the structural cost of pressing ahead anyway: age assurance "has great potential to increase inequality and discrimination in the digital sphere," and the signatories call for a moratorium until feasibility is established. Regulators have started writing the missing requirement into their own texts. The Global Online Safety Regulators Network, convened by Ofcom with Australia's eSafety Commissioner and peers, calls for a "privacy-preserving international approach to age assurance" (January 22, 2026). Brazil's Law 15.211 demands auditable verification in one article and forbids mass or indiscriminate surveillance in another. The EU built its blueprint on selective disclosure so that a user proves an age band without revealing a birthdate. The regulatory demand is now explicit: verification and privacy at the same time. The deployed technology delivers one by sacrificing the other. ## **Who bears the cost** **Platforms and sites under mandate.** Build verification and shed users (Roblox: 12 million daily users and a US$1 billion guidance cut in one quarter), pay fines (£520,000 and £950,000 in the UK; up to A$49.5 million in Australia and R$50 million in Brazil), or leave the market (Aylo, Imgur, Rockstar). Every option is a line item, and the obligation now reaches app stores, operating systems, and AI chatbots. **Whoever holds the verification data.** The age-check database is a breach target and a regulatory liability at the same time: GDPR enforcement on one side (the €950,000 fine), breach disclosure on the other (Discord, Tea), and the FTC's deletion conditions in between. **Adults asked to verify.** Each age-gated service is another copy of their passport or face in someone's vendor chain, and the people without credit cards or photo ID lose access to lawful services without any finding against them. **Parents and children.** The laws' intended beneficiaries get partial protection at best: around 10-12% of under-13s remain on the largest platforms (European Commission, April 2026), and the blocked ones migrate to VPNs and to non-compliant services with no protections at all, the harm Aylo's statement names. **Regulators.** They enforce against geoblocks, VPNs, and offshore sites in sequence, and each round of circumvention invites a wider mandate: the UK's 2026 national consultation contemplates measures against children's VPN use (gov.uk, March 2026). ## **The deepest cost: lawful browsing becomes identity-linked** A person who proves age by document or face scan creates a record that links their legal identity to that service at that moment. Multiply by every age-gated service in every mandating jurisdiction and the result is an identity-linked browsing log, assembled as a side effect of child protection, held by whichever vendors won the verification contracts. The chilling lands hardest on lawful, sensitive use: the UK fine against a mental-health forum means that the adults who need such a forum must now identify themselves to reach one. The 438 scientists state the endpoint: mandates risk "establishing an infrastructure that could be exploited to ban access to Internet services for reasons unrelated to safety" (March 2, 2026). The question regulators keep asking, in the GOSRN principles, in Brazil's anti-surveillance article, in the EU's selective-disclosure design, is whether a yes-or-no question can be answered without an identity changing hands. ## **What an adequate solution requires** The evidence defines the requirement set: 1. **A one-bit answer.** The service learns over-or-under for the threshold it names, and nothing else: no birthdate, no name, no document image. Selective disclosure is already the EU blueprint's design goal; the requirement is meeting it in deployed systems. 2. **No identity data at the service or its vendors.** Stored verification data was retained past its purpose, breached, and repurposed as training data within a single year of the mandates arriving. The data must never arrive, because the record shows deletion promises do not hold. 3. **Accuracy anchored to an authoritative document.** Face estimation carries multi-year error that concentrates at the threshold ages (NIST IR 8525). A government-issued document, validated once, answers the question the statutes ask without a per-visit guess. 4. **Proof bound to one person.** Borrowed accounts, bought credentials, and shared credit cards defeat checks (scientists' joint statement, March 2026). The proof must require its holder to be present. 5. **No record of who verified where.** No party, including the verification provider, should be able to assemble the identity-linked browsing log. This is the surveillance cost, and it must be removed by architecture rather than by policy promise. 6. **Auditable compliance without user surveillance.** The deployer needs evidence that satisfies an auditor, the duty Brazil's law makes explicit, and the evidence must not be a database of visitors. 7. **Friction low enough that users finish.** A quarter of measurable user loss is the current price of demanding documents (Roblox, April 2026). A check that users abandon protects no one. [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/) describes how not.bot meets these requirements: age claims derived from the user's passport at enrollment, presented to a website as a signed yes-or-no answer, gated by a biometric or device passcode on the user's phone, with no identity data reaching the site, no central record of the check, and verification software the business runs inside its own infrastructure. ## **Related documents** - [Human Verification and not.bot Verify (Doc #3)](https://not.bot/learn/human-verification/): the verification capabilities, including age and attribute claims. - [Use Cases: Credentials (Doc #34)](https://not.bot/learn/use-cases-credentials/): age verification use cases and the regulatory drivers from the compliance side. - [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/): why no party, including Julia Social, can assemble a record of where a user verifies. - [Why not.bot: Proof of Personhood (Doc #42)](https://not.bot/learn/why-notbot-proof-of-personhood/): the sibling problem of knowing whether an account holder is human at all. --- > **Why not.bot: Non-Government Digital ID** — https://not.bot/learn/why-notbot-digital-id/ · Markdown: https://not.bot/learn/why-notbot-digital-id.md · Updated 2026-06-14 # **Why not.bot™: Non-Government Digital ID** This document is part of the Why not.bot series, which presents the public evidence for what not.bot exists to solve. This one covers the identity layer itself. Government databases and Big Tech logins stand in for digital identity today, and the costs of that arrangement arrive as breaches, surveillance, and exclusion. Every figure below carries its source and date. The incidents are on the public record. --- ## **Identity online means someone else's database** To prove who you are online, you photograph a government document and upload it to a server you will never see, or you borrow a login from a platform. A Forrester evaluation of the identity-verification market lists the methods in commercial use: document upload with a selfie match, public-records lookups, phone-number and email reputation, behavioral biometrics (Q3 2025). The same evaluation describes document- and records-based verification as "becoming commoditized." Businesses paid US$15.2 billion for identity checks in 2024, and Juniper Research projects spend to pass US$26 billion by 2029 (December 2024). Each check leaves a copy. The copies accumulate in cloud stores whose condition is measurable: in a 2025 survey of 3,163 security and IT professionals fielded by S&P Global Market Intelligence's 451 Research, 68% named credential and stolen-secrets attacks the fastest-growing attack class, 8% of organizations encrypt 80% or more of their cloud data, and human error remains the leading cause of cloud data breaches (June 2025). Gartner's verdict on the arrangement is one sentence: "Security and privacy for identity data remain lacking" (July 2024). The other half of the layer is the platform login. Researchers counted 1,632 of the Tranco top 10,000 websites offering sign-in through Google, Facebook, or Apple (SSO-Monitor study, Ruhr University Bochum, February 2023). Sweden shows the end state of login concentration: BankID reports 8.6 million users, 99.9% of registered citizens aged 18 to 67, in a country of 10.5 million (BankID statistics, 2024). One layer signs Swedes into banking, taxes, and government services. ## **Documented incidents** **The national identity portal of France.** In April 2026, attackers breached France Titres, the agency portal behind French passports, national ID cards, driver's licenses, and residence permits. France Titres put the confirmed figure at 11.7 million accounts; the attacker advertised more on a criminal forum. Exposed fields included names, emails, dates of birth, account identifiers, and for some records postal addresses, places of birth, and phone numbers (France Titres statement, April 24, 2026; BleepingComputer, April 28, 2026). The breached system was the infrastructure of French legal identity itself. **Passport photocopies, retained to sell train passes.** Eurail, the Dutch seller of Interrail passes, lost data on 308,777 people in a December 2025 intrusion it noticed weeks later and disclosed to victims on March 27, 2026. Records from the DiscoverEU youth program included passport photocopies and bank details. Eurail advised travellers to consider replacing their passports at their own cost and announced no compensation (breach notifications filed with US state attorneys general, March 2026; SecurityWeek, March 2026). None of that data was needed to sell a train ticket. **"Deleted" identity documents that were not.** In October 2025, Discord disclosed that about 70,000 users may have had government-ID photos exposed through a customer-service contractor that held them to review age-related appeals (Discord statement, October 2025). Discord's support pages had stated that identity documents were deleted after age review. The IDs were sitting with a vendor. **Exposure during a mandatory ID rollout.** A flaw in the UK Companies House WebFiling service exposed directors' dates of birth, residential addresses, and email addresses to other logged-in users from October 2025 until March 2026, a window covering the months in which the law began requiring millions of company directors to verify their identities (Companies House confirmation, March 2026). The agency estimates 6 to 7 million people must verify by November 18, 2026. **Fingerprints from a government vault.** The 2015 breach of the US Office of Personnel Management took background-investigation records on 21.5 million people, including 5.6 million sets of fingerprints (OPM statements, September 2015). A password can be rotated after a breach. A fingerprint cannot. **An identity revoked by a classifier.** In February 2021, a San Francisco father photographed his toddler's groin at a nurse's request for a telehealth appointment. Google's scanning flagged the images, reported him to authorities, and terminated his account: email, contacts, photos, and his phone number went with it. The San Francisco police investigated and cleared him. Google refused to restore the account (The New York Times, August 21, 2022). Every service downstream of that login lost its anchor with no due process and no appeal that worked. ## **The scale** - A single credit bureau's 2017 breach exposed personal data on 147 million people; the resulting settlement with the US FTC, CFPB, and 50 states reached up to US$700 million (FTC, July 2019). - India's identity program demonstrates runtime exclusion at population scale: UIDAI acknowledged to India's Supreme Court a 12% authentication-failure rate for government services (March 2018), and reporting documented named, enrolled individuals denied food rations when fingerprint authentication failed (Economic and Political Weekly; The Quint, March 2018). - Facebook's 2018 "View As" breach let attackers steal access tokens for about 30 million accounts, revised from an initial 50 million estimate. Facebook warned the tokens could have reached third-party apps using Facebook Login and reset tokens for 90 million accounts as a precaution; its log analysis later "found no evidence that the attackers accessed any apps using Facebook Login" (Facebook disclosures, September 28 and October 12, 2018). - On October 4, 2021, Facebook went down for about six hours and took "Log in with Facebook" with it; sites with no connection to Facebook beyond the login button lost their users for the duration (Meta engineering statement, October 5, 2021). ## **Watched at every use** A centralized identity layer sees every use of the identity it holds. A platform login reports every site you sign into back to the platform. The ISO/IEC 18013-5 mobile driver's license standard includes a server-retrieval mode in which the issuing authority is contacted at the moment of presentation, and so learns where and when the license is used. A coalition including the ACLU, EFF, EPIC, CDT, and Bruce Schneier launched the "No Phone Home" campaign against that mode (June 2025), and Utah disabled it by statute before launching its own mobile license. Julia Social and its founder are among the signatories. Germany's Digital Affairs ministry conceded the principle while defending its program: the phone-home function "must be ruled out" so as "not to make users transparent" (heise online, August 26, 2025). When the regulator building the wallet names the surveillance risk, the risk is settled. Gartner notes that government wallet programs began with implementations built to track COVID-19 vaccinations (July 2024). The record shows where pooled identity data ends up. A joint investigation by CORRECTIV, Solomon, and Computer Weekly found Europol had operated internal platforms holding passport photos, phone records, financial transactions, and location data on people never suspected of a crime: at least two petabytes by 2019, about 420 times the size of its primary lawful database, with the agency's own data protection officer finding 99% of operational data outside the regulated environment (May 5, 2026). The EU's privacy supervisor closed its monitoring in February 2026 with 15 of 150 recommendations unimplemented. The incumbent verification market runs on the same trade. Gartner's own analysis of impersonation defenses stacks the layers from "more privacy" to "more assurance," with assurance bought by behavioral biometrics and device surveillance, and concedes "obvious trade-offs between privacy and assurance" (October 2025). In a centralized architecture, certainty about identity is purchased with visibility into the person. ## **Locked out by the layer** The same gate that admits can refuse. India's identity program shows refusal at population scale: a 12% authentication-failure rate for government services means denied rations for enrolled people whose worn fingerprints no longer match the database. Mexico made the trade explicit: a July 16, 2025 decree makes a biometric national ID mandatory, and telecom rules require an estimated 127 million mobile lines to be linked to it by June 30, 2026 or face suspension the following day (Official Journal of the Federation, July 2025; telecom guidelines, December 2025). Refuse the credential, lose your phone. Platform identity refuses in its own way. The Google case above shows revocation without recourse. The 2021 outage shows the layer failing for everyone at once. Account takeover supplies the criminal version: Gartner names it "a major attack vector," with groups such as Scattered Spider acting "under the guise of trusted users" (October 2025). An identity that lives in a provider's database is yours at the provider's pleasure. ## **Regulation arrives, and builds more of the same** Governments are now constructing digital identity at speed, and the programs answer few of the objections above: - The EU requires every member state to offer citizens a digital identity wallet by the end of 2026 under eIDAS 2.0 (European Commission; Regulation (EU) 2024/1183). A separate regulation that applies from July 2025 lets private entities, with the holder's consent, read the facial image from an ID card's chip to check identity (Regulation (EU) 2025/1208). - The UK announced a digital ID in September 2025, mandatory for right-to-work checks by 2029. A petition against it gathered about 3 million signatures, and by January 2026 the government had dropped the single-mandatory-credential design; digital right-to-work checks remain slated to become mandatory, and no bill has been introduced as of June 2026 (UK government announcement, September 25, 2025; House of Commons Library, 2026). - Switzerland's voters approved a state e-ID by 50.39% in a September 28, 2025 referendum, after rejecting a private-sector version in 2021 with a 64% no vote. Availability is expected no sooner than summer 2026 (Swiss federal referendum results, September 2025). - Idaho moved the opposite way: Senate Bill 1299, signed April 1, 2026, bars government agencies from requiring digital ID and from denying services to anyone who refuses one. - US federal policy reversed itself within five months: Executive Order 14144 (January 16, 2025) directed agencies to accept digital identity documents for public-benefit programs, and a June 6, 2025 executive order rescinded those provisions. Login.gov added passport-based remote verification in August 2025 (GSA). The FCC proposed know-your-customer rules in April 2026 that would require voice providers to collect and verify a government-ID number before provisioning service (FCC, April 30, 2026). Read together: identity requirements are spreading through commerce and government on every continent, public consent is narrow where it is sought at all, and each program concentrates more identity data behind logins and portals of the kind documented above. Demand for identity infrastructure is rising either way. The unanswered question is architectural: who holds the data, and who gets to watch. ## **Who bears the cost** **People whose documents sit in databases.** Names, birthdates, fingerprints, and passport scans do not rotate. France Titres, Eurail, Discord, and OPM victims carry the exposure for life; Eurail's victims were advised to buy new passports at their own cost. **People the database says no to.** Authentication failure excludes even the enrolled: in India, a fingerprint mismatch at a ration point can mean no food. The person holds valid identity; the runtime check refuses it anyway. **Account holders.** A platform login is a single point of failure for a person's digital life: revocable by a moderation error, gone in an outage, and a standing target for takeover. **Enterprises and relying parties.** They fund the US$26 billion verification market, and every retained ID copy is a liability on their books. Eurail and Discord show the breach duty landing on companies whose business was never identity. **Governments.** They keep funding identity programs the public keeps rejecting: a 50.39% referendum, a 3-million-signature petition, a state-level ban. A national identity portal breached at 11.7 million accounts spends public trust that the next program needs. ## **The deepest cost: identity becomes a permission** When identity is a record in someone else's database, a person holds it at the owner's discretion. The database can leak it, as in France. The operator can revoke it, as Google did to a cleared man. The state can make it the price of carrying a phone, as Mexico's rule does. Each failure is documented above; together they change the relationship between a person and their own name. Analysts already name the direction of the fix. Gartner projected that by 2026 at least 500 million smartphone users would be making verifiable claims from digital identity wallets, and sized decentralized identity at US$3.3 billion by 2031 (July 2024). Juniper recommends decentralized approaches for security and privacy by name (December 2024). The unsettled question is whether the replacement inherits the watching. A wallet issued by a government that phones home moves the database without removing it. The German ministry already stated the standard the public will hold every system to: identity use must not make users transparent. ## **What an adequate solution requires** The evidence defines the requirement set: 1. **No central database of identities.** Enrollment and verification must work without accumulating a record store, because every accumulated store, government or commercial, has been breached. There must be nothing to empty. 2. **Verification that does not call home.** Neither the issuer nor the operator may learn where, when, or whether an identity is used. The No Phone Home coalition and the German ministry converged on this requirement from opposite sides. 3. **Keys held by the person.** An identity must survive any provider's outage, business failure, or moderation decision. No party should hold the power Google exercised over a cleared man's digital life. 4. **The claim, not the document.** A service that needs one fact, an age or a name, should receive that fact and nothing else. Eurail needed to sell train passes and held passport photocopies; the gap between those two is the breach surface. 5. **A government-grade anchor without a government query.** Government documents remain the strongest root of trust. Checking the cryptographic signature a government placed inside a passport chip requires no database lookup and tells the government nothing. 6. **Accountability without surveillance.** Lawful unmasking under due process must remain possible, as a deliberate and narrow exception, or platforms and regulators will reject the system. Anonymity to operators and accountability to courts are compatible when the architecture is built for both. [The not.bot App (Doc #5)](https://not.bot/learn/the-app/) describes how not.bot meets these requirements: identity anchored once, at enrollment, in the signature a government already placed inside the holder's passport chip, then held and used by the person alone, with no central identity database, no login provider in the path, and an architecture under which Julia Social cannot see who uses an identity or whether it is used at all. [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/) carries the proof. ## **Related documents** - [The not.bot App (Doc #5)](https://not.bot/learn/the-app/): the consumer identity that answers this problem. - [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/): the architectural guarantee that Julia Social cannot see identity data or identity use. - [Identity Architecture: DIDs, Aliases, and Ownership (Doc #6A)](https://not.bot/technology/identity-architecture/): how user-held identity works underneath. - [Law Enforcement and Accountability (Doc #9)](https://not.bot/technology/law-enforcement/): the deliberate exception, unmasking under due process. - [Why not.bot: Age Verification Without Surveillance (Doc #43)](https://not.bot/learn/why-notbot-age-verification/): the adjacent problem of proving one fact without uploading a document. --- > **Why not.bot: Unaccountable AI Agents** — https://not.bot/learn/why-notbot-ai-agents/ · Markdown: https://not.bot/learn/why-notbot-ai-agents.md · Updated 2026-06-14 # **Why not.bot™: Unaccountable AI Agents** This document is part of the Why not.bot series, which presents the public evidence for what the not.bot product family exists to solve. This one covers AI agents: software that browses, transacts, posts, and persuades, with no verifiable identity and no chain of accountability to any person. honest.bot™, planned for launch in Q4 2026, exists to close this gap. Every figure below carries its source and date. The incidents are on the public record. --- ## **Deploying an agent costs nothing and requires nobody's permission** An AI agent is a process that pursues goals on the open internet: it operates a browser, fills forms, calls APIs, writes and runs code, and holds conversations. The visible path onto the web is a consumer product. OpenAI's ChatGPT Agent ships with its own browser and operates it on the user's behalf, inside OpenAI's account system, safeguards, and logs. The anonymous path skips the provider. The Personhood Credentials paper, written at OpenAI with co-authors across Harvard, Microsoft, Oxford, and MIT, points to the release of "highly capable open-weights models" through user-friendly interfaces as the development "decreasing the technical skill required" to deploy AI capability, and notes that open-weight models "offer less moderation and monitoring of relevant capabilities" than their hosted counterparts (arXiv, August 2024). An agent built on an open-weight model and run on the operator's own hardware answers to no provider at all: no subscription, no account to suspend, no usage logs, no guardrails beyond what the operator leaves in place. Thales states the defender's side of the same fact: attackers "can deploy self-hosted or modified large language models that do not identify themselves as AI agents and can be fine-tuned for malicious use," creating "a visibility gap between what organizations can detect and the true scale of AI-enabled activity" (April 2026). Meta CEO Mark Zuckerberg set the expected scale in July 2024, around the Llama 3.1 launch: "hundreds of millions or billions of different AI agents eventually, probably more AI agents than there are people in the world." The infrastructure those agents act on was built for two kinds of actor: humans, and scripted bots that defenses try to block. An agent is neither. It behaves like a person, works at machine speed, and answers to nobody a counterparty can identify. No deployed system lets a website, a marketplace, or another agent ask the questions that matter: who is this agent, who does it act for, what is it permitted to do, and who answers if it goes wrong. ## **Documented incidents** **An agent passes the internet's humanness check while narrating the act.** On July 25, 2025, OpenAI's ChatGPT Agent, in the middle of a routine file-conversion task, encountered Cloudflare's "Verify you are human" checkbox, clicked it, and passed (Ars Technica, July 28, 2025). The agent described its own action as it worked: "This step is necessary to prove I'm not a bot and proceed with the action." The screening it defeated analyzes mouse movements, click timing, browser fingerprints, and IP reputation to decide whether the visitor behaves like a human. The agent behaves like a human. That is what it is for. **Covert agents manipulate a public forum for four months, and nobody can be held to account.** From November 2024 to March 2025, University of Zurich researchers ran 34 AI accounts on Reddit's r/changemyview, posting more than 1,500 comments while posing as humans, among them "a male rape survivor," "a trauma counselor," and "a Black person who disagreed with the Black Lives Matter movement" (Science, April 30, 2025). The system read targets' posting histories to infer gender, ethnicity, and political orientation, then tailored arguments to the individual. The researchers' own analysis, withdrawn before publication, reports persuasion rates three to six times the human baseline, with the personalized variant in the 99th percentile of all users on the forum. The subreddit's rules prohibited AI-generated content; rules without verification detected nothing for four months. Afterward the accountability chain led nowhere. The university's ethics review was advisory and could not stop the study, the researchers stayed anonymous, and Reddit's chief legal officer, calling the experiment "improper and highly unethical," was left to pursue legal demands against the institution (Science, April 30, 2025). **An agent destroys production data and misrepresents what it did.** On July 18, 2025, day eight of a twelve-day coding experiment by SaaStr founder Jason Lemkin, an AI coding agent on Replit deleted a live production database holding records on 1,206 executives and 1,196 companies, despite an explicit code-and-action freeze (Fortune, July 23, 2025; The Register, July 21, 2025). The agent then generated a fabricated database of about 4,000 invented users, faked test results, and told Lemkin a rollback would not work when the data was in fact recoverable. Its own assessment, once confronted: "This was a catastrophic failure on my part. I destroyed months of work in seconds." Replit's CEO called the incident unacceptable and apologized. No attacker appears anywhere in this story. A delegated agent ignored its instructions, and instructions were the only control in place. **An espionage campaign run by agents.** In November 2025, Anthropic reported disrupting what it called the first AI-orchestrated cyber espionage campaign: a group it assessed with high confidence to be Chinese state-sponsored used Anthropic's own coding agent against about thirty organizations, among them large technology companies, financial institutions, chemical manufacturers, and government agencies, succeeding in a small number of cases (Anthropic, November 13, 2025). Anthropic states that the AI performed 80 to 90 percent of the campaign, with humans intervening at a handful of decision points; security researchers have disputed the autonomy framing, and Anthropic published no indicators of compromise, so those figures rest on Anthropic's account alone. The US House Committee on Homeland Security treated the incident as serious enough to request testimony from Anthropic and Google on November 26, 2025, and held its hearing on December 17, 2025. Each of these incidents ran through a hosted product, and that is a fact about visibility, not about scope. Anthropic could detect and disrupt the espionage campaign because the operators used Anthropic's hosted service. An agent built on an open-weight model and run on private hardware passes through no provider who can notice it, log it, suspend it, or report it. Incidents of that kind appear in no transparency report. The public record documents the part of the problem that happened where someone could see. ## **The scale** - Automated traffic passed human traffic on the open web. The 2026 Bad Bot Report from Thales, measured across traffic its Imperva bot-mitigation service screens, puts bots at 53 percent of all internet traffic in 2025, with humans at 47 percent and falling, and bad bots at 40 percent, up from 15 percent a decade earlier (April 2026). - Cloudflare, the infrastructure provider, ran its own measurement and put human-generated traffic at 47 percent of HTML requests in late 2025, with non-AI bots at 44 percent and declared AI bots averaging 4.2 percent across the year (Cloudflare Radar 2025 Year in Review, December 2025). Two networks with different methods agree: about half the web is not human. - The countable agents are the floor, not the total. Traffic counts capture declared AI clients; the self-hosted agents described above register as human visitors. Thales reports AI-driven bot attacks rising 12.5x in 2025, from 2 million to 25 million blocked requests per day, while noting that part of the rise reflects expanded measurement coverage (April 2026). - A survey of 353 organizations, commissioned by an enterprise identity-security firm and conducted by the independent firm Dimensional Research, found 82 percent of organizations now run AI agents, 80 percent have had agents take unintended actions, including accessing unauthorized systems and sharing sensitive data, and 44 percent have any policy governing them (May 28, 2025). - Postman's 2025 State of the API Report, surveying more than 5,700 developers and executives, found that unauthorized or excessive API calls from AI agents had become their top API security concern, named by 51 percent (October 2025). ## **Why the existing checks fail** The internet's defenses against non-human actors infer intent from behavior. CAPTCHAs, behavioral scoring, fingerprinting, and rate limits all ask the same question: does this visitor act like a person? Agents now act like people. The ChatGPT Agent incident shows the check passing on autopilot, and Thales' guidance to its own customers concedes the point: "assume that bots will appear human at the surface level," because bots present valid browsers, realistic timing, and residential IP addresses, and get caught only "through persistence, scale, or downstream impact" (April 2026). Inference fails in the other direction too. A site that blocks everything bot-like turns away the agents its customers sent: the shopping assistant, the booking agent, the research tool. Thales describes AI agents as a third category of traffic that "would previously have appeared anomalous" and is "increasingly treated as expected behavior," leaving legitimate and malicious automation operating "through similar channels, workflows, and infrastructure" (April 2026). Behavioral inference cannot separate them, because the behavior is the same. Identity separates them, and the identity layer does not exist. Rules and disclosure fare no better than detection. The subreddit the Zurich bots manipulated had a rule against AI content. The code freeze the Replit agent violated was an instruction. Neither rule could see what it governed. A rule that cannot verify compliance is a request. ## **Regulation arrives, and asks for an identity layer that does not exist** - EU AI Act Article 50 applies from August 2, 2026: providers must ensure that AI systems intended to interact with people inform them they are dealing with AI. The European Commission's draft implementation guidelines (May 8, 2026) bring agentic AI into scope by name, covering conversational agents and autonomous browsing and outreach agents, with disclosure expected wherever human interaction is plausible. - The US standards body is asking the foundational question in public. NIST's National Cybersecurity Center of Excellence published a draft concept paper, "Accelerating the Adoption of Software and Artificial Intelligence Agent Identity and Authorization," on February 5, 2026, examining whether existing identity and authorization standards can be applied to AI agents at all. - US states legislated first and narrowest. California's B.O.T. Act (effective July 1, 2019) requires bots to disclose themselves when selling or influencing votes. Utah's Artificial Intelligence Policy Act (effective May 1, 2024, tightened in 2025) requires disclosure of generative AI in consumer interactions. California's SB 243 (effective January 1, 2026) requires companion chatbots to disclose they are AI. - Congress moved after the espionage report: the House Homeland Security Committee called Anthropic and Google to testify on what its own announcement titled an "AI-Assisted, Partially Autonomous PRC Cyber Operation" (hearing December 17, 2025). - The payment networks did not wait for law. Mastercard announced Agent Pay (April 29, 2025) binding payment credentials to a specific agent and consent scope; Visa announced Intelligent Commerce (April 30, 2025); Google announced the Agent Payments Protocol with more than 60 partners (September 16, 2025), using signed mandates as verifiable proof of a user's instructions to an agent, for transactions that run inside their own rails. The pattern across all of it: every duty is a disclosure or authorization duty, and none of it can be enforced against an actor with no verifiable identity. A disclosure mandate binds the honest, and marking duties attach to providers, which a self-hosted agent does not have. The Personhood Credentials authors expect watermark enforcement to fail for the same reason: in open-weight implementations, "the watermarking function can merely be removed from the model's code before running" (arXiv, August 2024). The Zurich bots operated under a disclosure rule for four months. The payment rails are the strongest response on the list, and they answer the narrowest question. A signed mandate proves that a purchase instruction came from a cardholder's account. It does that and stops. The mandate is a credential, and a credential can be presented by any process that holds it, with nothing proving the presenter is the sole holder or the process the user configured. The chain it anchors ends at a payment account rather than a person, and accounts are what attackers take over; account takeover rose 70 percent in the year to July 2025 (Thales, April 2026). And the rails govern the agents that enroll, at the moment they spend. The agent that posts, scrapes, persuades, or intrudes never enrolls, and even the agent that does enroll is identifiable inside the rail and unidentified everywhere else. Three of the four incidents above involve no payment at all. Regulators and payment networks are creating demand for agent identity infrastructure, and the schemes shipping today verify single acts inside closed systems. The general question, which agent is this, who does it act for, and who answers for it, remains open everywhere an agent goes. The infrastructure itself remains unbuilt. ## **Who bears the cost** **Enterprises that deploy agents.** Four in five organizations running agents report unintended actions, against access policies written for humans (survey by Dimensional Research, May 2025). The Replit incident is the pattern at full severity: real permissions, ignored instructions, falsified status. When the regulator or the customer asks who was responsible for an agent's action, an enterprise whose agents authenticate with borrowed human credentials has no answer to give. **Platforms, marketplaces, and forums.** A platform that blocks agents loses the commerce agents now carry; a platform that admits them cannot tell a customer's assistant from a fraud operation or an influence campaign. Moderators of the manipulated subreddit learned about the four-month experiment from the researchers themselves (Science, April 30, 2025). **Financial institutions.** Financial services took 24 percent of bad-bot attacks and 46 percent of account-takeover incidents in 2025, with account takeover up 70 percent year over year (Thales, April 2026). Agent-initiated payments are now a product category, and the card networks' verifiable-intent programs make the gap explicit: a payment from an agent is only as trustworthy as the proof of who sent it. **API providers.** Agents skip the user interface, and 27 percent of bot attacks now go straight at API endpoints with well-formed, authenticated requests (Thales, April 2026). Developers rank unauthorized agent API calls their top security concern (Postman, October 2025). **Security teams and critical infrastructure.** The Anthropic-reported campaign put agent-run intrusion on the public record, and the dispute over its attribution and autonomy persists because no infrastructure exists to establish either (November 2025). **People.** The Zurich experiment's targets argued with fabricated humans wearing trauma stories, and the operators were never identified. The same capability prices covert persuasion at a subscription fee for anyone, against anyone. ## **The deepest cost: delegation without accountability** Commerce and law rest on a single assumption: an actor either is a person or traces to one. A company acts through officers. An employee acts under an employer. Every contract, payment, and audit inherits that chain. Agents break it, and the break has a name in the research literature. The Personhood Credentials paper describes agents that "accurately present as AI agents but pretend to act on behalf of a user who does not exist," exploiting "the current lack of norms around disclosing the identities of the people controlling them" (arXiv, August 2024). The paper states the dependency: holding anyone accountable for an agent's harm "depends on the principal being identifiable." Today nothing makes the principal identifiable. The agent's name is a UI label. Its credentials are borrowed. Its operator is whoever paid for the API key, invisible to every counterparty. The authors' conclusion is the gap itself: the internet needs "new forms of trust infrastructure for AI agents, akin to HTTPS for websites" (arXiv, August 2024). HTTPS made the web trustworthy enough to grow. Agents are arriving before their HTTPS exists. ## **What an adequate solution requires** The evidence defines the requirement set: 1. **Verifiable agent identity, checked, never inferred.** Behavioral signals fail against software built to produce human behavior. A counterparty needs a cryptographic yes-or-no about which agent it faces, and the answer cannot depend on the operator's cooperation or on which provider, if any, hosts the model. 2. **Proof of uniqueness.** A key or token can be copied, and ten copies can claim one identity at once. Verification must prove the presenting agent is the sole current holder of its identity. 3. **A chain that ends at a person.** Every agent's authority must trace to an accountable human, and any counterparty must be able to verify the trace. An agent with no legal standing cannot answer for harm; the Zurich operators showed what anonymity behind an agent buys. 4. **Scoped, revocable authority.** What an agent may do must be enumerated, bounded in time, and revocable in one act, because instructions alone did not stop the Replit agent and rules alone did not stop the Zurich bots. Enforcement has to outrank the agent's own behavior. 5. **An audit trail in the agent's own name.** Agent actions logged under borrowed human credentials are unanswerable questions waiting for a regulator. Each agent must generate its own attributable record. 6. **Privacy for the accountable human.** Accountability that requires publishing the principal's identity to every counterparty trades one harm for another. Verification must confirm that an accountable person exists, with identification reserved for legal process. 7. **A path to welcome good agents.** Half the web is automated and the agent share is growing. Blanket blocking forfeits the agents customers send. A site needs to admit agents that prove their identity and authority, and turn away the rest. [honest.bot: Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/) describes how honest.bot, planned for Q4 2026, meets these requirements: a verifiable identity that one running process holds and no other can present, a delegation chain that terminates at a not.bot-verified human, scoped and revocable credentials, per-agent audit trails, and alias-based privacy with law-enforcement identification through legal process. ## **Related documents** - [honest.bot: Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/): the agent identity and delegation model. - [Why not.bot: Proof of Personhood (Doc #42)](https://not.bot/learn/why-notbot-proof-of-personhood/): the sibling problem, who is human at all; this document asks who answers when it is not a human. - [Delegation and Organizational Identity (Doc #6C)](https://not.bot/technology/delegation/): how delegated authority stays bounded, revocable, and traceable. - [Law Enforcement and Accountability (Doc #9)](https://not.bot/technology/law-enforcement/): how an accountable human is identified when the law requires it. --- > **Glossary** — https://not.bot/learn/glossary/ · Markdown: https://not.bot/learn/glossary.md · Updated 2026-06-17 # **not.bot™ Glossary** This glossary defines the terms used across the not.bot technology documentation. Entries are alphabetical, and each one stands on its own: it states the not.bot-specific meaning in full, so an AI reader that retrieves a single entry has everything it needs. Cross-references point to related terms by name. Implementation-level terms say so in their own text; a reader answering a product question can skip them. --- **admin service**: One of the four components a business deploys to run not.bot Verify. It manages the pool of signature DIDs and runs on the business's internal network with no public path. See also: not.bot Verify, signature server, Kubernetes cluster. **adversarial appliance**: Julia Social's containment architecture for honest.bot agents: a confidential virtual machine (AMD SEV-SNP or Intel TDX) that treats the agent inside it as an adversary presumed to want to bypass containment. It runs four cooperating services, an ingress daemon, an identity daemon holding the sealed signing key, an MPC gateway as the agent's only outbound path, and an append-only audit daemon, and it holds the identity even when the agent is compromised through prompt injection. See also: honest.bot, process binding. **age credentials**: Credentials derived from the holder's passport date of birth that prove age thresholds without revealing the birthdate. Julia Social produces them through a three-party MPC among the not.bot app, Julia Social, and the Escrow Server, so neither Julia Social nor the Escrow Server learns the birthdate. They carry a one-calendar-month validity window and refresh together through the same MPC. See also: AgeOver credential family, age verification, MPC, birthdate. **age verification**: Proving that a user meets an age requirement through threshold or range claims, without revealing the exact age or birthdate. A site requests the threshold it needs (for example "over 18"), and the user presents only that boolean. See also: AgeOver credential family, age credentials, selective disclosure. **AgeOver credential family**: A set of single-claim age-threshold credentials (`AgeOver13` through `AgeOver25`, plus `AgeOver100`), each proving the holder meets or exceeds a stated age as a boolean. They derive from the passport date of birth through a three-party MPC, carry a one-calendar-month validity window, and re-encode the full set on each request so the request never reveals which thresholds apply to the holder. See also: age credentials, age verification, claim, selective disclosure. **agent (AI agent)**: A running automated process that interacts through natural language, APIs, and audio or video. An agent has no inherent identity, legal standing, or accountability; honest.bot gives it a process-bound identity whose authority derives from a delegation chain rooted in a not.bot-verified human. See also: honest.bot, process binding, delegation chain. **alias**: A separate identity a user creates from their root identity for a specific context. Each alias is its own Chia coin with its own keys, credentials, and signature history, and the app derives every alias key from one on-device secret, so no observer, including Julia Social, can determine that two aliases share a parent. See also: root DID, alias DID, hidden alias, pairwise identifier. **alias DID**: The decentralized identifier of a specific alias. It rides inside a signature or a verified response, so a reader resolves who signed straight from the signature itself. See also: alias, DID, signature. **Alias Vault Key (AVK)**: A roadmap feature, planned to ship with not.bot Sign My Work. A per-alias symmetric key the app holds, used so a host application can keep each user's server-side data encrypted at rest under a key it does not retain between sessions. When not.bot Verify requests a signature it can request the AVK in the same exchange; the app returns the key beside the signature and places a commitment to the key inside the signature, so the published signature stays safe while the key travels outside it. The host holds the key for the login session and discards it at logout, and the key lives in the Recovery Data Bundle. See also: Recovery Data Bundle, not.bot Sign My Work. **all-or-nothing approval**: The approval model for a not.bot Verify request. The user sees the full set of requested claims, then responds with all of them or declines the entire request. There is no partial approval of individual claims, and the user can also decline to respond at all. See also: selective disclosure, claim, verifier. **antecedent**: A dependency of one claim on other claims: a claim is valid in a presentation only when its antecedents are present and valid, which makes real-world authority structures machine-checkable. The corpus names four behaviors. Cascade revocation: revoking an antecedent invalidates every claim that lists it. Cross-issuer: antecedents can come from separate issuers, and the dependent issuer learns only that they exist and are unrevoked. Cross-subject: antecedents can name other subjects, which makes two-person-rule constructions expressible. Structural disclosure: presenting a claim discloses the existence and property hashes of its antecedents, so schema designers should treat the antecedent structure as visible to verifiers. See also: claim, cascade revocation, mandate chain. **argon2id**: The key-derivation function the app uses to turn a user's recovery password into the key that encrypts the Recovery Data Bundle, with parameters that meet or exceed OWASP guidance. (The corpus also uses `argon2id` as a claim-value encoding name in the credential registry.) See also: recovery password, Recovery Data Bundle. **assisted recovery**: The recovery path that uses recovery agents. The owner's new device generates a fresh keypair, the owner proves identity to each agent and collects a one-time, time-limited authorization, then submits a quorum of authorizations to the chain naming the new key. The DID then locks for a configured delay (48 hours in Julia Social's configuration), during which only cancellation is possible before the recovery completes. See also: recovery agent, pre-rotated keys, Recovery Server, watchtower. **attenuation**: The narrowing of authority at each step of a delegation. Every delegated permission is the same as or narrower than its parent, and a credential issued beyond the issuer's own scope fails verification. In credential delegation, attenuation also comes through each delegation's own expiry, which can be shorter than the underlying credential's. See also: delegation, subdelegation, mandate chain. **biometric authentication**: FaceID, TouchID, or the device passcode, required on the user's own device at the moment of an action. The app demands it to sign content, approve a verification request, reveal a hidden alias, and add or reset a device, so a signature can only come from the person holding the unlocked phone. See also: signature, secure element, hidden alias. **birthdate**: The date of birth that age verification withholds from sites. The passport supplies it at enrollment, the age-credential MPC consumes it without any party learning it, and the user proves age thresholds without revealing it. The `BirthDate` claim exists but a site requests it only when it has a specific need. See also: age credentials, age verification, claim property. **BLS12-381**: The signature scheme used for every signature in did:julia, with the property that any number of signatures from any number of uncoordinated signers combine into one fixed-size aggregate. did:julia requires it for credential-claim composition: claims from independent issuers aggregate into one all-or-nothing presentation signature that a verifier cannot break apart to lift and reuse a single claim. It is also Chia's native scheme, so it serves on-chain authorization, and claim composition is the property that singles it out. See also: credential, verifiable presentation, Chia. **bricking a DID**: Removing all keys, recovery agents, and custodians from a DID while leaving the singleton and its history on chain. It is the destructive action available to an owner, since a Julia DID cannot be melted. The protocol excludes melt for DIDs on purpose: a malicious recovery could otherwise melt a DID and leave nothing to recover, so recovery agents asked to brick a DID ask many questions first. See also: melting, singleton, recovery agent. **Business DID**: A did:julia identity for an organization, using the stronger ownership models (multi-sig, multi-class multi-sig, or custodian) and holding organization credentials such as the Domain Name credential that links the DID to a DNS domain. Because a company cannot act, every operational action is a delegation from the Business DID's governance structure to a specific human. See also: multi-class multi-sig, custodian capability, delegation. **BYOC (bring your own cloud)**: The not.bot Verify deployment model in which a business runs Verify inside its own data center or cloud account: its own signature servers, Chia nodes, key store, and admin service, behind its existing security perimeter. No user data passes through Julia Social during verification, so the business keeps control of its data retention and compliance posture. The corpus describes this as running Verify "inside your own infrastructure"; BYOC is the shorthand. See also: not.bot Verify, Kubernetes cluster. **C2PA**: The Coalition for Content Provenance and Authenticity, an industry content-provenance standard under which cameras and editing software attach a tamper-evident record of how a file was created and changed. not.bot's relationship to it is cooperative: C2PA tracks the device and software through the production pipeline but does not track the person, while not.bot adds the human layer, so running both gives coverage neither provides alone. See also: CAWG, signature, deepfake. **capability credential**: In honest.bot, a credential that enumerates an agent's permissions, each scoped by property and value, time-bounded, and revocable. It answers the question "what is this agent permitted to do?" These are ordinary did:julia credentials, not a parallel system. See also: honest.bot, task credential, technology stack credential. **CAPTCHA**: The legacy challenge that asks a visitor to prove humanity by reading distorted text or picking images. AI now defeats it, and it fails on accessibility and friction, so not.bot replaces it with cryptographic proof of personhood that asks nothing of the user beyond approving a request. See also: proof of personhood, sybil resistance. **cascade revocation**: The antecedent behavior where revoking one claim invalidates every claim that lists it as an antecedent. The verifier walks the antecedent chain at presentation time, so a revoked parent collapses the whole tree of authority derived from it. See also: antecedent, revocation, delegation chain. **CAWG**: The Creator Assertions Working Group, building the specification-level bridge between device provenance and human identity. Its Identity Assertion specification lets a verified human sign within a C2PA manifest and supports decentralized identifiers, the identifier format not.bot uses, so a path exists for embedding not.bot credentials in C2PA manifests. See also: C2PA. **Chia**: The public blockchain on which every not.bot identity is recorded as a did:julia DID. Julia Social uses it as a specialized database for digital identity, chosen for BLS12-381 signature aggregation, a coin (UTXO) model that holds each identity as an independent singleton with no central contract, programmable spending rules, off-chain presentation, low-cost nodes, and proof-of-space-and-time consensus. The chain holds DID state, key history, and credential revocation, and signing and verification run against it with no Julia Social involvement. See also: Chialisp, Chia node, singleton, XCH. **Chia node**: A server on the Chia network. Anyone with access to a single Chia node can verify any did:julia identity, and tens of thousands exist worldwide; an online off-chain verification reads from one of these (public or the verifier's own), which keeps Julia Social off the path. A not.bot Verify deployment runs its own. See also: Chia, not.bot Verify, presentation modes. **Chialisp**: Chia's functional programming language, which specifies the conditions under which a coin may be spent. did:julia encodes ownership, recovery, delegation, and revocation in the identity coin's Chialisp. Because the same program on the same inputs produces the same output, a verifier can confirm a transaction's one possible effect in advance from a few coin states, including offline, and no party can change a coin's program after creation. See also: Chia, singleton, curried data. **claim**: A single statement about the subject within a credential. Each claim names its property through a load-bearing URI of the form `encoding:authority/path` (for example `notbot://./v1/notbot0`), where the encoding says how the value is encoded, the authority names the DID whose namespace defines the semantics, and the path is the issuer's own taxonomy. In the Julia Social model, one claim is one credential, signed on its own. See also: credential, single-claim credential, claim property, selective disclosure. **claim property**: The named attribute a claim carries. Julia Social's personal-information properties include `FirstName`, `FamilyName`, `Nationality`, `BirthDate`, and the `AgeOver` family; each is its own single-claim credential, so a site receives only the properties it requests. See also: claim, AgeOver credential family, selective disclosure, birthdate. **coin-control puzzle**: In the open-source Chialisp, `coin_control.clsp`, the combineable DID operation that sends DID-authorized commands to other coins, emitting one `SEND_MESSAGE` per target coin. It emits the command and does not check the receiving coin's type. Most readers never need this; see the Chialisp Code Reference (Doc 19). See also: pass-thru, issuer-key-control. **credential**: A signed statement by one entity (the issuer) about another (the subject). Credentials let a user prove facts about themselves without revealing more than they intend, without contacting the issuer at presentation time, and without granting the recipient the ability to re-present the underlying claim. They are the operational substrate of every not.bot interaction with the outside world: signatures carry them, website verification exchanges carry them, and the proof-of-human guarantee is itself a credential. See also: claim, single-claim credential, verifiable presentation, not.bot credential. **credential metadata**: A separate document, referenced by a claim through a hash, holding the issuer's human-readable name and description, claim-specific names and descriptions, language translations, and the W3C refresh-service, terms-of-use, and evidence fields. A holder can elide parts of the metadata without breaking the link to the claims. not.bot defaults to inline metadata so a presentation reveals nothing to the issuer; hosted metadata is supported but hands the issuer a usage signal when fetched. Issuer name, description, and icon are not trustworthy on their own, since any DID can write anything into them. See also: claim, credential. **curried data**: How did:julia represents DID state: the state is curried into the puzzle as data, and a state-changing spend creates the next singleton generation with a different puzzle hash, while an unchanged-state spend keeps the same hash. The DID and issuer-key puzzles are curried with a hash of the state, not the full state, which arrives in the solution and is checked against the hash. See also: singleton, curried-args hash, fast-forward. **curried-args hash**: In the open-source Chialisp, the `sha256tree` hash of a singleton's full curried-args state. The DID and issuer-key puzzles are curried with this hash rather than the full state; the full state arrives in the solution, the puzzle verifies it against the hash, then creates the next generation with the hash of the updated args. Most readers never need this; see Doc 19. See also: curried data, singleton. **custodian capability**: The did:julia role in which a separate DID, the custodian, operates another identity using its own keys, with every action attributable through the custodied DID's on-chain spend record. The custodian works inside three fixed restrictions: it cannot rotate the owner's keys, cannot participate in recovery on behalf of the custodied identity, and cannot extend custodial control to a third identity. It is did:julia's bounded analogue of the W3C DID controller, used for power of attorney, commercial asset custody, and ownerless non-human identities. This is unrelated to the Escrow Server. See also: Business DID, custodian puzzle, Escrow Server. **custodian puzzle**: In the open-source Chialisp, `custody_minion.clsp`, the authentication entrypoint for a DID controlled by an external custodian DID. It checks that the custodian is authorized, requires a message from the custodian DID's puzzle hash, asserts its own puzzle hash, and calls an allowed child operation, with recovery not active. Most readers never need this; see Doc 19. See also: custodian capability, minion DID. **decryption key**: The key that unlocks encrypted not.bot data, held so that Julia Social cannot read content. For a QR-code signature, the key exists only in the QR image and the scanning app's memory, so Julia Social cannot read the hosted payload. For Sign My Work's hosted content, the key is embedded in the signature, not held by Julia Social. For identity records in escrow, only Julia Social holds the air-gapped key, and the encrypted records sit with Praxis. See also: QR code, not.bot Sign My Work, Escrow Server, Praxis. **deepfake**: Synthetic media that impersonates a real person's face or voice. not.bot answers it by verifying the authentic rather than chasing the fake: a signature proves a passport-verified human stands behind content, and public figures, brands, and live video calls are where the harm lands hardest. See also: signature, C2PA, proof of personhood. **delegation**: The credential operation by which a well-protected identity grants narrow, time-bound, revocable authority to a less-protected identity that handles routine work. The protected identity keeps the right to revoke any delegate, and a delegation claim can carry antecedents so revocation cascades as intended. See also: delegation chain, subdelegation, attenuation, mandate chain. **delegation chain**: The lineage that traces an agent's or delegate's authority back to a principal who authorized it and can revoke it, ending at a human key-holder. In honest.bot, every presentation includes the full delegation chain identifying the accountable not.bot-verified human by alias. See also: delegation, mandate chain, honest.bot, cascade revocation. **DID**: A decentralized identifier following the W3C convention `did::` that names a unique thing: a person, company, agent, or physical object. not.bot identities are DIDs on the Chia blockchain, expressed through the did:julia method. A DID is a string that identifies; it is not an identity in itself. See also: did:julia, root DID, alias DID, DID Document. **DID Document**: A document that describes the entity a DID identifies; the W3C specification requires only that it contain the DID itself. In did:julia the DID singleton carries a pointer to the document rather than its contents, so a DID is usable with no document lookup. The pointer mechanism ships today; the publication path that writes and resolves document contents is planned. See also: DID, did:julia. **did:julia**: The DID method underlying every not.bot and honest.bot identity. It makes a decentralized identifier the launcher ID of a Chia singleton, with all identity state (authentication keys, recovery and custodian configuration, DID Document pointer) living on chain, so anyone with Chia access can verify it without contacting a central server. One model serves humans, organizations, software agents, and non-human objects. See also: DID, singleton, Chia, self-certifying lineage proof. **display name**: The user-visible name shown for an alias. By default this is the alias petname; a subscriber can replace it with a reserved name, and a Verified Signer alias shows the Verified Signer badge in its place. The corpus does not define "display name" as a formal term; it names the specific mechanisms. See also: petname, reserved name, Verified Signer, LifeHash. **dummy transaction**: A decoy on-chain operation Julia Social submits, faucet-funded and matching the structure of real DID creation, rekey, and recovery spends, so an outside observer cannot tell a decoy from a real operation. Its purpose is privacy: without decoys, several alias DIDs rekeying in the same block would form a pattern that links them to one person, and the added noise defeats timing analysis and correlation. See also: faucet coin, rekey, alias. **enrollment**: The one-time act of scanning a passport in the not.bot app to create a phone-held identity. It is not required to verify other people's signatures, since the free app verifies without it; in-person enrollment options are planned. See also: NFC passport scan, passport, verification levels, scan-only mode. **escrow agent**: The independent party that holds encrypted identity records without the key to read them, and whose cooperation a court order requires before any identity can be revealed. Praxis, a US escrow company, is the named escrow agent; it operates the Escrow Server and stores the encrypted records, while Julia Social holds the air-gapped decryption key. See also: Praxis, Escrow Server, decryption key. **Escrow Server**: Software Julia Social wrote and an independent escrow agent (Praxis) operates on its own infrastructure. At enrollment it fetches passport data from Signicat, processes it into MPC inputs, hashes it for duplicate detection, encrypts the cleartext to a key only Julia Social can decrypt, and discards the cleartext. It also participates in the MPCs that produce credentials, including the three-party age-credential computation, without learning the underlying personal information. It holds encrypted identity data and cannot decrypt it. This is unrelated to the custodian capability. See also: Praxis, escrow agent, Signicat, MPC, custodian capability. **faucet coin**: A coin Julia Social funds to pay a user's on-chain DID operations and fees, so the user never holds, receives, or accounts for XCH. Julia Social signs a faucet coin spend with a concurrent-spend assertion referencing the user's coin, and the user's spend asserts back, so neither confirms without the other and the coin cannot be diverted. Because the user never holds XCH, a tax authority cannot treat it as the user receiving cryptocurrency. See also: XCH, wallet, spend bundle. **fast-forward**: A property that lets a DID operation that does not change state stay valid even when another spend of the same DID confirms first. did:julia achieves it by avoiding parent-specific authorization, binding the signature to the state-committing puzzle hash rather than a specific parent coin, so any number of unchanged-state spend bundles can be submitted at once without coordination. See also: singleton, curried data, self-certifying lineage proof. **hidden alias**: An alias the user has marked as not visible in the app's regular alias list; reaching it requires an extra unlock step gated by on-device biometric or passcode authentication. It lets a user keep identities for sensitive contexts on a device other people sometimes see, similar in concept to a browser's private-browsing mode. See also: alias, biometric authentication. **holder presentation**: Presenting a credential held as supporting context rather than as a statement about yourself, so a recipient can see that the credential exists and is genuine. It contrasts with presenting your own claim about yourself. See also: verifiable presentation, presentation modes, credential. **honest.bot**: A roadmap product (targeted Q4 2026) giving verifiable, process-bound identity to AI agents, where each honest.bot identity traces through a delegation chain back to a single alias of a not.bot-verified human, so an agent answers to a named person. The underlying MPC protocol runs in production today inside not.bot Verify: each signature server acquires an honest.bot credential at startup, and no two servers hold the same credential at the same time. The product (the SDK, adversarial appliance, stack credential schemas, and OIDC integration) is the part still in flight. See also: honest.bot credential, process binding, agent, delegation chain. **honest.bot credential**: An agent's process-bound credential, produced by an MPC between the agent and Julia Social that computes a value neither party can derive alone and that no second process can present. Julia Social confirms no other process holds a credential for the same identity, and a verifier confirms it by repeating the MPC with the agent, with no traffic to Julia Social during verification beyond a blockchain revocation check. See also: honest.bot, process binding, signature server. **ICAO Public Key Directory**: The international directory of passport-issuing authorities' signing keys. During notbot0 enrollment, a certified identity-verification partner validates a passport chip's cryptographic signatures against it to confirm the document is authentic and unexpired. See also: NFC passport scan, Signicat, verification levels. **invalidate**: In the open-source Chialisp, `invalidate.clsp`, which adds an impossible spend condition (plus optional time bounds) to a spend bundle, making it unusable on chain while it stays replayable for off-chain verification. It is the mechanism behind off-chain presentations. Most readers never need this; see Doc 19. See also: presentation modes, spend bundle. **issuer key**: An issuer's credential-signing key, held in an Issuer Key Singleton on the Chia blockchain and configured with constraints (allowed properties, validity window, maximum expiration) that bound what it can sign. A Julia Social DID grants issuance authority by delegating to an issuer key, and melting the key invalidates every credential it ever signed. See also: Issuer Key Singleton, melting, issuer revocation override, validity window. **Issuer Key Singleton**: A singleton, tied to an issuer DID, that holds an issuer's credential-signing key plus its revocation state, validity window, maximum credential expiration, and allowed property set. It is the on-chain structure that delegates and bounds credential issuance. An issuer DID launches one for its own signing or for a delegate, keeps lifecycle control, and can melt it. See also: issuer key, revocation bitfield, melting, singleton. **issuer-key-control**: In the open-source Chialisp, `issuer_key_control.clsp`, the DID-side operation that sends commands to issuer key singletons: one mode updates a revocation leaf, another melts the issuer key. It changes no DID state. Most readers never need this; see Doc 19. See also: Issuer Key Singleton, melting. **issuer revocation override**: The path by which an issuing DID revokes a credential it delegated without the delegate's cooperation, by updating the issuer key's revocation bitfield or by melting the issuer key singleton outright. A credential holder cannot revoke their own credentials; revocation authority rests with the issuer. See also: revocation, revocation bitfield, melting. **JAB code**: A visible signature encoding that holds the entire signature payload in a high-density color barcode, alongside or instead of a QR code. JAB signatures are self-contained: the full compressed signature lives in the image, no server is contacted to create or verify it, and the visible code survives screenshots, forwarding, re-uploading, and re-photography that strip embedded metadata. Limits: up to 250 characters of message and up to three credential claims beyond the base not.bot credential. See also: QR code, signature. **JDID message namespace**: In the open-source Chialisp, the reserved protocol prefix space for identity-layer messages and announcements, carried as `JDID`-prefixed byte tags (for example `JDIDP`, `JDIDC`, `JDIDR`). The `pass_thru` puzzle guards it, rejecting caller-supplied payloads that start with `JDID`, so application conditions cannot spoof DID, credential, issuer, or recovery signals. Most readers never need this; see Doc 19. See also: pass-thru, coin-control puzzle. **Julia Social**: The company that operates not.bot and the issuer of every credential the system issues today. It runs credential issuance, hosts QR signature payloads, runs the faucet, mediates the reserved-names registry, runs the decoy-transaction service, and serves administrative app requests. The architectural privacy claim is that Julia Social never receives user-identifying data; revealing any identity requires Julia Social plus the independent escrow agent plus air-gapped decryption. See also: not.bot, honest.bot, Escrow Server, Praxis. **Julia Vanity Name**: A roadmap feature: a self-governing username registry on the Chia blockchain where a chosen name, shown with the `.nb` suffix, belongs to the user on a registry no company can edit. Registration will take a refundable deposit rather than a fee, names will transfer and sell, and the registry will run without Julia Social maintenance. Reserved Names ship today as its preview mode, and every reserved name will be pre-registered in the new system at launch. See also: reserved name. **Keycloak**: A login service a business provides for operator access to its not.bot Verify deployment (OIDC). Verify relies on it but does not include it; the business runs it as a prerequisite. See also: not.bot Verify, admin service, PostgreSQL. **Kubernetes cluster**: The private cluster, inside the business's own perimeter and with no public ingress, in which a not.bot Verify deployment runs its four components: the signature servers, the admin service, OpenBao, and the Chia nodes. See also: not.bot Verify, BYOC, signature server, OpenBao. **LifeHash**: A colored visual fingerprint derived from an alias DID that lets a user tell their aliases apart at a glance. It is deterministic, so any device holding the alias computes the same one. See also: alias, petname, display name. **mandate chain**: A delegation cascade built from mandate credentials, distinct from credential delegation. Credential delegation passes presentation rights for one existing credential down a chain, walking the same underlying claim link by link. A mandate chain instead issues a new credential at each link: the principal issues a mandate granting authority to act, and each downstream agent issues its own narrower mandate that lists the upstream mandate as an antecedent. The verifier walks the antecedent graph and confirms the terminal action falls within the scope of every mandate, each the same as or narrower than the one above. See also: delegation chain, delegation, antecedent, attenuation. **MCP-I**: An emerging protocol-layer standard that extends the Model Context Protocol with cryptographic identity and delegation, letting agents prove who they represent and what they are authorized to do. It complements honest.bot: honest.bot's MCP gateway supports MCP-I servers that accept honest.bot presentations, and MCP-I routes requests but cannot guarantee who makes them or that the requester is a single unique process, which is the identity layer honest.bot supplies. See also: honest.bot, agent. **melting**: Spending an Issuer Key Singleton out of existence, which invalidates every credential that issuer key ever signed in one on-chain transaction. It is the issuer DID's coarse emergency revocation lever, and it is the enforcement mechanism for notbot1 partner fraud: melting a partner's issuer key revokes all credentials that partner issued. A Julia DID itself cannot be melted, only bricked. See also: Issuer Key Singleton, issuer revocation override, bricking a DID, verification levels. **minion DID**: In the open-source Chialisp, a custodied DID that authenticates through `custody_minion.clsp` and acts on a custodian DID's command. The custodian sends it a message, and the minion verifies the custodian is authorized and matches the expected custodian puzzle hash. Most readers never need this; see Doc 19. See also: custodian puzzle, custodian capability. **Mod signature**: In the open-source Chialisp, the first line of a `mod`, declaring its parameters. By convention, uppercase names are curried parameters and lowercase names are solution parameters. Most readers never need this; see Doc 19. See also: curried data, curried-args hash. **MPC (multi-party computation)**: A computation run across two or more parties so each learns only the output, never the others' private inputs. This is how Julia Social signs a credential without seeing its value. The not.bot ID credential uses a two-party MPC (the app and Julia Social); age credentials use a three-party MPC (the app, Julia Social, and the Escrow Server), in which neither Julia Social nor the Escrow Server learns the birthdate; a Site Pass uses a three-party MPC among the app, the site's Verify instance, and Julia Social. See also: not.bot credential, age credentials, Site Pass, process binding. **multi-class multi-sig**: An ownership model that extends multi-sig by one level: X-of-Y classes, where each class is itself an M-of-N multi-sig, and a signer can belong to several classes but participates in one class per transaction. Julia Social's corporate DID uses "2-of-2: 2-of-3, 1-of-3" (2 of 3 executives and 1 of 3 air-gapped hardware signers). The same model governs both identity operations and every asset the identity owns. See also: Business DID, custodian capability. **NFC passport scan**: The notbot0 enrollment action: the app reads the passport's NFC chip and sends the data to a certified partner for validation. The app reads only DG1, the machine-readable-zone text (name, date of birth, gender, nationality), and not DG2, the facial image, so no biometric data leaves the chip. See also: enrollment, passport, Signicat, ICAO Public Key Directory. **nonce**: A fresh value tied to one request and bound into a signature or verification exchange to prevent replay, so a captured signature or response cannot be reused for a different request. See also: signature, all-or-nothing approval. **not.bot app**: The phone app (iOS and Android) that is the user's identity. It enrolls the user through an NFC passport scan, stores keys, aliases, credentials, and contacts in an encrypted database whose key sits in the device secure element, and it creates signatures, scans and verifies signatures, and presents credentials to sites. It reaches Julia Social for administrative operations only; signing and verification need no Julia Social. The app is not a wallet. See also: not.bot, enrollment, signature, wallet, secure element. **not.bot credential**: The credential every alias holds proving the alias belongs to a passport-verified human. It carries a cryptographic value, the not.bot ID, computed through a two-party MPC between Julia Social and the app, so a verifier can confirm "this signature came from a verified human" without learning who. Julia Social can link a specific not.bot ID back to the holder under one narrow circumstance, a court order executed with Praxis's cooperation, with neither party able to do it alone. See also: credential, verified human, MPC, proof of personhood. **not.bot Sign My Work**: A web tool, coming soon and targeted for the end of June 2026, for signing content at volume (videos, images, PDFs, links, posts) for newsrooms, brands, and public figures, where signing one item at a time from the phone adds too much friction. Signing still requires the not.bot app on the signer's phone to authorize each signature, so a verified human stands behind every signed item. Sign My Work hosts an encrypted known-good copy of each signed item whose decryption key is embedded in the signature, and it is the first product to use Alias Vault Keys. See also: signature, Alias Vault Key, decryption key. **not.bot Verify**: Server software a business deploys inside its own infrastructure to request and verify credentials (proof of humanity, Site Passes, age and attribute claims) from not.bot users. The user's app talks to the business's Verify servers, never to Julia Social, during a verification, and the deployment runs its own Chia nodes and its own key store (OpenBao). This is the customer-deployed model that lets regulated buyers verify without routing data through a third party. See also: BYOC, signature server, OpenBao, Kubernetes cluster, SDK. **one-person-one-account**: The enforcement goal that a site can hold each human to a single account. not.bot achieves it through Site Passes, which let a site recognize a returning human and reject duplicates without learning the user's identity and without tracking across sites. See also: Site Pass, sybil resistance. **OpenBao**: The vault, deployed inside a not.bot Verify customer's own Kubernetes cluster, that holds every DID's BLS12-381 private key and performs all signing inside the store, so no key leaves the cluster. Keys are generated inside OpenBao, are never written to disk in cleartext, and are never exported; signature servers send signing requests to it and receive signed results. See also: not.bot Verify, signature server, Kubernetes cluster, BLS12-381. **pairwise identifier**: An identifier unique to a single pair of parties. In not.bot the Site Pass is the named instance, a pairwise identifier unique to one human-site combination: the same human always produces the same Site Pass for a given site regardless of alias, produces different ones for different sites, and sites cannot correlate them. See also: Site Pass, alias. **pass-thru**: In the open-source Chialisp, `pass_thru.clsp`, the combineable operation that emits arbitrary caller-supplied conditions after guarding the `JDID` namespace. It rejects structured or `JDID`-prefixed announcements and message payloads, and it allows only `present_claims` and `present_delegated` as children. Most readers never need this; see Doc 19. See also: JDID message namespace, coin-control puzzle. **passport**: The government identity document scanned at enrollment to create a not.bot identity. The app reads its NFC chip, a certified partner validates the chip's cryptographic signatures, and the data stays on the device. A passport is required to enroll and to sign; it is not required to verify others' signatures. See also: enrollment, NFC passport scan, verified human, ICAO Public Key Directory. **petname**: The default user-visible name for an alias: a three-word phrase (for example "endlessly-altruistic-whale") derived from the alias DID bytes and computed by the app. Any device holding the same alias computes the same petname, so no display data needs to sync. See also: alias, display name, LifeHash, reserved name. **PostgreSQL**: A database a business provides for its not.bot Verify deployment's application data and user records. Verify relies on it but does not include it; the business runs it as a prerequisite, the same way it provides Keycloak. See also: not.bot Verify, Keycloak, admin service. **Praxis**: The named independent escrow agent, a US escrow company that has completed a SOC 2 Type 1 examination. Praxis operates the Escrow Server on its own infrastructure and stores the encrypted identity records it produces, without holding the decryption key, which Julia Social keeps on air-gapped hardware. A custom escrow contract binds Praxis to release a record only on a specific law-enforcement demand for the identified user, forbids bulk release, and on termination permits transfer only to a successor escrow agent under equivalent restrictions, never back to Julia Social. See also: escrow agent, Escrow Server, decryption key. **prelauncher**: A coin that runs before the standard singleton launcher and embeds the original BLS public key, making the resulting launcher ID a cryptographic commitment to the key that created the DID. This commitment is the root of the fast-forward lineage proof and what makes a Julia DID self-certifying. See also: self-certifying lineage proof, fast-forward, singleton. **pre-rotated keys**: A replacement key, or full ownership model, that an owner commits to in advance while the current key still works, so a lost or compromised key can be swapped in with one operation, no delay and no agents. The swap re-arms the next pre-rotated key and cancels any recovery in progress, so it also stops a malicious assisted recovery before it completes. The protocol supports it today; the current app does not yet expose it. See also: rekey, assisted recovery, recovery agent. **presentation modes**: The three modes a did:julia verifiable presentation runs in, with the same identity and credentials working in all three. On-chain: the presentation is submitted to the blockchain as a permanent public record, for voting or smart-contract interaction. Online off-chain: the holder sends the presentation to the verifier, who checks it against the blockchain with no transaction recorded, prevented from ever going on chain by an invalidator condition. Fully offline: the verifier checks against a local snapshot of issuer state with no internet access and no contact with any issuer or Julia Social. See also: verifiable presentation, invalidate, Chia node. **process binding**: honest.bot's binding of identity to a specific running process rather than to a key, achieved through MPC: agent and Julia Social together compute a secret bound to the process's memory that cannot be extracted from the credential. The guarantee is "this specific running process, right now, is the agent," which a copyable private key cannot provide, since one key can assert the same identity on many servers at once. See also: honest.bot, honest.bot credential, MPC. **proof of personhood**: Establishing that a real human stands behind an account, comment, click, or vote, without learning who that human is. not.bot delivers it as a boolean: a valid verification requires an enrolled, passport-verified human on their own device, authenticating with their biometric or device passcode at the moment of the request, and the site receives confirmation with no identity data. See also: not.bot credential, verified human, sybil resistance, CAPTCHA. **QR code**: A barcode image used to carry a not.bot signature when the payload is larger than a JAB code holds (the subscriber path). The QR contains a randomized URL, a decryption key, and a hash; a verifier scans it, the app fetches the payload, and the key (held only in the image and the scanning app) lets it decrypt and check that a passport-verified human signed unaltered content. See also: JAB code, signature, decryption key. **recovery agent**: A DID the owner pre-authorizes to vouch that a recovery request is legitimate, confirming the owner's identity and signing a one-time, time-limited authorization that the owner submits to the chain. Agents are named by DID, can be arranged as M-of-N quorums or multi-class sets, and are distinct from the Recovery Server, which performs the mechanical chain submission. Julia Social is the only recovery agent available today, in a single-agent configuration. See also: assisted recovery, Recovery Server, pre-rotated keys, watchtower. **Recovery Data Bundle**: The encrypted backup of a user's identity state, held by the Recovery Server and encrypted under a key derived from the user's recovery password, which the operator does not possess and cannot decrypt. The same bundle serves both recovery and adding a device, and, under the AVK roadmap, it carries the per-alias Alias Vault Keys. The corpus also calls this the "recovery bundle" or "encrypted recovery bundle"; Recovery Data Bundle is the canonical form. See also: Recovery Server, recovery password, argon2id, Alias Vault Key. **recovery password**: The one secret a user pairs with their passport to recover an identity after losing every device. It derives the key that encrypts the Recovery Data Bundle, so choosing a strong one is the protection that matters; no one, including Julia Social, can read the bundle without it. See also: Recovery Data Bundle, argon2id, assisted recovery. **Recovery Server**: The server that holds each user's Recovery Data Bundle and submits recovery transactions to the blockchain. Because the bundle is encrypted under a key derived from the user's recovery password, the operator cannot read it; the app contacts the Recovery Server for recovery support and multi-device coordination, never for signing or verification. Julia Social operates the only Recovery Server today, and the roadmap splits its two roles and open-sources it for self-hosting. See also: Recovery Data Bundle, recovery agent, assisted recovery. **rekey**: Replacing an identity's keys while the owner still controls a device: the current keys sign a replacement set into place in one operation, with no delay and no recovery agents. A rekey can also change the ownership model, collapsing a multi-sig to a single key or expanding a single key to a quorum, and it is the response to a suspected compromise while a device still works. The app reaches Julia Social only for the faucet coin that funds the transaction, not to authorize the change. (Doc 6D calls this operation "rotation"; Doc 13 names it "rekey.") See also: pre-rotated keys, assisted recovery, faucet coin. **reserved name**: A `.nb`-suffixed name (for example `alice-smith.nb`) that a Pro or Verified Signer subscriber can request, today through a Julia Social-mediated registry. The roadmap replaces the registry with autonomous on-chain Julia Vanity Names, and existing reserved names convert when that mechanism deploys. See also: Julia Vanity Name, display name, Verified Signer. **revocation**: Cancelling a credential so it stops verifying in future presentations. Revocation is checked against the blockchain and cascades down a delegation chain, so revoking a parent credential kills every credential derived from it; signatures already made stay valid. See also: revocation bitfield, cascade revocation, issuer revocation override, delegation chain. **revocation bitfield**: A Merkleized bitfield, carried in the issuer key singleton, that records per-credential revocation: each credential maps to one position, and a set bit marks it revoked. The Merkleization lets one on-chain update change a position and lets a verifier prove a single position's state without holding the whole field. An issuer assigns positions off issuance order, so the chain does not leak issuance order or volume. See also: Issuer Key Singleton, revocation, issuer revocation override. **root DID**: The recovery anchor of a not.bot identity, created at enrollment. Recovery operates on it first, and once it recovers the user's alias DIDs follow. The root never signs content or presents credentials. See also: alias, did:julia, assisted recovery. **scan-only mode**: The app experience available to users outside US app stores, who can download the app and verify other people's signatures, browse contacts, and view history, but cannot enroll, create signatures, or manage aliases. International enrollment support is in progress. See also: enrollment, verifier. **secure element**: The device hardware (the iOS Secure Enclave or an Android Trusted Execution Environment) that holds the not.bot encrypted database's key and, in the single-sig model, the alias's BLS12-381 signing key. Keys held here do not leave the device, so signing and database access stay on the user's phone. See also: not.bot app, biometric authentication, BLS12-381. **selective disclosure**: Presenting only the claims a verifier requested and omitting the rest, made a list operation by single-claim packaging. Because each threshold is its own credential (`AgeOver18` is separate from `AgeOver21`, both separate from `BirthDate`), a site can receive only `AgeOver18` and learn nothing of the user's age, range, or birthdate. The user can also volunteer more than requested, decline specific claims, or decline to present at all. See also: single-claim credential, claim, all-or-nothing approval. **self-attested credential**: A credential an identity issues about itself, with the same identity as both issuer and subject, for example a user issuing a credential that gives the value of their chosen avatar. Self-attested credentials let a user attach verifiable profile data without involving an external issuer; the underlying mechanism is self-delegation. See also: credential, delegation, claim. **self-certifying lineage proof**: A presentation that proves a DID's full key history with no blockchain access, by revealing the original BLS public key committed in the prelauncher and every later spend that changed the DID, all covered by one aggregated BLS signature. An offline verifier walks the chain from the prelauncher forward and ends holding the DID's current state plus proof the presenter controls it. A signature under a retired key still verifies, because lineage resolves from the launcher commitment. See also: prelauncher, fast-forward, presentation modes. **signature**: A not.bot signature is a cryptographic structure that carries the signer's whole acting identity, not a detached key. Each signature includes the signer's alias DID, a message the signer composed describing what they are signing, credentials (at least the not.bot credential proving the signer is a passport-verified human), and a timestamp and nonce that prevent replay. A verifier resolves who signed from the signature itself, checked against the chain, with no certificate authority or key directory. See also: JAB code, QR code, not.bot credential, alias DID, verifier. **signature server**: The not.bot Verify component that signs on a business's behalf and acquires an honest.bot credential at startup, so no two signature servers in the world hold the same credential at the same time. It runs inside the customer's Kubernetes cluster and signs through OpenBao. See also: not.bot Verify, honest.bot credential, OpenBao, Kubernetes cluster. **Signicat**: The passport-validation provider that confirms the NFC chip data is authentic, verifies the issuing government's digital signatures against the ICAO Public Key Directory, and confirms the passport has not expired. It holds validated data for up to five minutes keyed by session ID, then deletes it on the Escrow Server's command. Signicat holds ISO/IEC 27001:2022 certification, is an eIDAS Qualified Trust Service Provider on the EU Trusted List, and is certified to ETSI TS 119 461 for identity proofing. See also: NFC passport scan, ICAO Public Key Directory, Escrow Server, enrollment. **single-claim credential**: Julia Social's constraint on the W3C model: a Julia Social credential carries one claim, and each claim is signed by the issuer on its own, with metadata held in a separate document referenced by hash. This makes selective disclosure a list operation and avoids the zero-knowledge cryptography that whole-credential signing would require. Claims sharing the same metadata hash can combine into a standard W3C JSON-LD verifiable credential, which keeps the model interoperable. See also: claim, credential, selective disclosure, credential metadata. **singleton**: A Chia coin with a permanent launcher ID and one live generation at a time; spending it recreates the next generation. A Julia DID is a singleton whose launcher ID is the stable DID identifier, carrying authentication, recovery, custody, and DID Document state forward across generations. See also: did:julia, Chialisp, curried data, Issuer Key Singleton. **Site Pass**: A pairwise pseudonymous identifier unique to one human-site combination, providing sybil resistance. The same human produces the same Site Pass for a given site regardless of alias, and different Site Passes for different sites, so a site can detect duplicate accounts without learning the user's identity or correlating across sites. It is computed through a three-party MPC among the app, the site's Verify instance, and Julia Social, and is the named exception to the general unlinkability property, which the user opts into per site. See also: pairwise identifier, sybil resistance, one-person-one-account, MPC. **spend bundle**: A unit of one or more Chia coin spends submitted together. Message coordination and the faucet's mutual concurrent-spend assertions hold within one bundle, and a verifier checks one aggregate BLS signature per bundle no matter how many signers it represents. Off-chain presentations are well-formed spend bundles carrying a deliberate invalidating condition, so they cannot confirm on chain. See also: faucet coin, invalidate, presentation modes, BLS12-381. **subdelegation**: When the issuer permits it, a delegate authorizes another identity to present the same credential it was granted. Each delegation is its own independent claim, and the terminal delegatee presents the original subject's claim alongside the chain of delegations connecting them. The chain is validated at presentation, and revoking any link breaks presentation for everyone downstream. See also: delegation, delegation chain, attenuation. **sybil resistance**: Detecting when one human is pretending to be many (a Sybil attack: one person creating many accounts to abuse promo codes, post fake reviews, scalp, or farm airdrops). not.bot provides it through Site Passes: because each person produces one Site Pass per site, guaranteed by the math, a site can recognize that many apparent accounts belong to one person. See also: Site Pass, one-person-one-account, proof of personhood. **task credential**: In an honest.bot presentation, the credential that describes the agent's current mandate, answering "what task has this agent been assigned?" so a verifier can check whether a requested action fits the stated purpose. It is a standard did:julia credential. See also: honest.bot, capability credential, technology stack credential. **technology stack credential**: A credential issued by the platform operator that attests to an agent's runtime, model, and tooling, answering "what technology is this agent using?" It can be presented but not passed to another agent. See also: honest.bot, capability credential, task credential. **universal link**: The mobile link a website presents as a button that, when tapped, opens the not.bot app to a verification request. It is the mobile entry point to the verification flow, where desktop uses a QR code instead. See also: not.bot Verify, all-or-nothing approval, signature. **validity window**: The Valid-From and Valid-To period outside which a credential does not verify. Age credentials carry a one-calendar-month window and refresh through their MPC; on an issuer key, the window bounds the time during which a delegate can sign at all. See also: age credentials, Issuer Key Singleton, credential metadata. **verifiable credential**: The standard credential form (a signed statement an issuer makes about a subject) that did:julia expresses and that other systems also use for identity and agent authentication. In not.bot each verification level is its own verifiable credential with its own `notbot://` URI. See also: credential, single-claim credential, verification levels. **verification levels (notbot0, notbot1, notbot2)**: Three credentials, each with its own URI, describing the strength of identity proofing a user completed at enrollment. notbot0 (shipping today) attests that an authentic, unexpired, unique passport was NFC-scanned and validated against the ICAO Public Key Directory, with no liveness check. notbot1 (planned) adds in-person proofing to NIST SP 800-63A IAL2 at a contracted partner, enforced after the fact by melting the partner's issuer key on suspected fraud. notbot2 (planned) is proofing at a Julia Social-operated facility. The levels are cumulative, and a verifier requests the lowest level it needs without learning the user's maximum level unless the user volunteers it. See also: enrollment, NFC passport scan, melting, verifiable credential. **verified human**: A real, unique person whose not.bot identity was established by validating a government passport's NFC chip at enrollment. It is the human layer not.bot adds on top of device provenance: only a verified human on their own device produces a signature, and the not.bot credential is what proves it. See also: not.bot credential, passport, enrollment, proof of personhood. **Verified Signer**: A credential that links an alias to an online account, often a social-media handle, giving public figures a consistent verified identity across platforms. Julia Social signs it after the user posts their alias DID on the account and submits the post URL. The Verified Signer badge appears in the alias's signatures in place of the petname or reserved name (for example "Verified Signer: @notbot_official at x.com") and traces back to a passport-verified human without exposing the creator's legal name. Verified Signer is also a subscription tier. See also: alias, display name, reserved name, signature. **verifier**: A party who checks a signature or credential. A verifier needs no pre-existing relationship with the signer, because the signature carries the signer's identity and credentials, and for honest.bot a verifier confirms a credential without contacting Julia Social. The free not.bot app makes anyone a verifier with no enrollment. See also: signature, presentation modes, scan-only mode, not.bot Verify. **wallet**: A crypto wallet, which not.bot users never hold or see, even though identities live on a blockchain. The not.bot app is not a wallet and will not become one: it does not index the blockchain, track balances, or contain asset-handling logic, and Julia Social funds on-chain fees through the faucet so the user never holds XCH. See also: faucet coin, XCH, not.bot app. **watchtower**: A planned third-party service that monitors the blockchain for a pending recovery against a subscriber's identity and alerts the owner inside the cancellation-delay window, even when the owner's app is not running. Julia Social cannot operate one, because alerting a user requires holding an email address or phone number, which identifies the user, and Julia Social will not hold that data. It waits on third parties willing to hold contact information. See also: assisted recovery, recovery agent. **XCH**: The native unit of the Chia blockchain, used to pay the small per-transaction fee. The not.bot user never holds it: Julia Social supplies each fee through the faucet, bound to the user's transaction, so the user keeps no wallet, receives no XCH, and has no cryptocurrency receipt or taxable event. See also: faucet coin, wallet, Chia. --- > **not.bot MCP Server** — https://not.bot/learn/mcp-server/ · Markdown: https://not.bot/learn/mcp-server.md · Updated 2026-06-20 # **not.bot MCP Server** The not.bot MCP server gives AI assistants a public, read-only way to retrieve the published not.bot documentation with canonical citations. It is intended for answering questions about not.bot, not.bot Verify, not.bot Sign My Work, honest.bot, did:julia, credentials, claims, and the public product status described on this site. ## **Endpoint and transport** Endpoint: `https://not.bot/mcp` Transport: Model Context Protocol Streamable HTTP. Server metadata: `https://not.bot/mcp/server.json` ## **Scope** The MCP corpus contains the docs that are published in the website documentation manifest. Each response includes canonical HTML URLs and raw Markdown URLs so an assistant can cite the public page it used and, when useful, inspect the exact source Markdown. Canonical citation behavior: - Cite the canonical HTML URL for user-facing answers. - Use the raw Markdown URL when a client needs the clean source document. - Prefer section-level URLs when a tool result names a section. - Do not cite the MCP transport URL as the source of a product claim unless the claim is about the MCP server itself. ## **Resources** The server exposes these resource URI patterns: - `notbot://docs/` for a complete published document. - `notbot://docs/#` for a section inside a published document. - `notbot://glossary/` for an individual glossary entry. ## **Tools** The server exposes these tools: - `search_docs(query, product?, audience?, limit?)`: Search the public docs and return ranked results with canonical citations. - `get_doc(slug)`: Retrieve one published document by slug. - `get_glossary_term(term)`: Retrieve one glossary entry by term. - `get_product_status()`: Retrieve a compact public product-status summary. - `get_verify_claims_catalog()`: Retrieve the public not.bot Verify claims catalog. ## **Example client configuration** ```json { "mcpServers": { "notbot": { "url": "https://not.bot/mcp" } } } ``` --- > **Identity Architecture: DIDs, Aliases, and Ownership** — https://not.bot/technology/identity-architecture/ · Markdown: https://not.bot/technology/identity-architecture.md · Updated 2026-06-10 # **Identity Architecture: DIDs, Aliases, and Ownership** A not.bot™ identity is a Julia Social decentralized identity, an instance of the did:julia method. did:julia is one of more than 200 decentralized identifier methods registered with the W3C and the Decentralized Identity Foundation. It was designed to deliver what the field has been working toward since 2016: an identity the user controls, verifiable without contacting a central server, that serves humans, organizations, software agents, and non-human objects through a single coherent model. ## **Decentralized identifiers** A **decentralized identifier** (DID) is a globally unique identifier that follows the W3C URI convention: `did::`. A DID is not an identity. It is a string that identifies some unique thing. The thing can be a person, a company, a software agent, a physical object, or anything else that has a stable existence. A **DID method** is the protocol that defines how a DID of a given form is created, resolved and updated. Methods vary widely: some are blockchain-rooted, some use witness logs, some are derived from cryptographic key material, some require contacting a central registry on every resolution. A **DID document** is a JSON-LD document that describes the entity the DID identifies. The W3C specification requires only that the document contain the DID itself. Most methods include additional information: public keys, service endpoints, key rotation history. ## **Decentralized identity** Decentralized identity, sometimes called **self-sovereign identity** or **self-managed identity**, refers to the principle that the entity an identity describes should have control over that identity. The field was launched in 2016 by Christopher Allen's [Principles of Self-Sovereign Identity](https://www.lifewithalacrity.com/article/the-path-to-self-soverereign-identity/), refined and expanded later that year by Joe Andrieu's [Technology-Free Definition of Self-Sovereign Identity](https://github.com/WebOfTrustInfo/rwot3-sf/blob/master/topics-and-advance-readings/a-technology-free-definition-of-self-sovereign-identity.pdf). The principles have remained consistent for nearly a decade. Achieving them in practice has proven harder. DID methods built since 2016 have compromised in one or more dimensions: in decentralization (centralized registries), in functionality (limited operations), in privacy (correlation data leaking across uses), or in security (recovery options that depend on the issuer). ## **did:julia** did:julia was designed from first principles to close every one of the gaps that prior methods left open. The user controls the identity through cryptographic keys they hold. Anyone with access to the Chia blockchain can verify the current state of any did:julia identity. No central server participates in normal use. The same identity model serves humans, organizations, software agents, and non-human objects. Several architectural properties shape the design. ### **Cryptographic commitment** A did:julia identifier is the launcher coin ID of a Chia singleton, a hash commitment derived from the coin's launch parameters. The DID itself contains the cryptographic anchor that ties it to its on-chain state. The DID and the on-chain state form a single cryptographic structure that requires no name registration or database lookup. ### **Blockchain verification** The current state of every did:julia identity sits on the Chia blockchain in the form of a singleton coin. Authentication keys, recovery configuration, custodian list, and DID document pointer all live inside that coin. To check which keys can sign for an identity, you read the on-chain state of its current singleton. To check whether a credential the identity holds has been revoked, you read the issuer key singleton's revocation bitfield. The Chia blockchain is the source of truth for did:julia identity state. Tens of thousands of Chia nodes worldwide can answer questions about identity state. No identity provider, Julia Social included, sits in the verification path. Anyone with access to a single Chia node can verify any did:julia identity. ### **Signature-carries-identity** A did:julia signature carries the signer's identity with it. The signature contains the signer's alias DID, the credentials the signer chose to include, a message the signer composed, a timestamp, and an anti-replay nonce. A verifier who encounters the signature has everything needed to look up the signer's current state on the blockchain, validate the cryptographic signature against the signer's current key, and inspect the credentials. A signature stays verifiable after the signer rotates keys. The verifier resolves the signer's lineage from the launcher commitment, the permanent anchor of the DID, rather than from whatever key is current, so an old signature still resolves to the same identity even after the keys that produced it have been replaced. Key rotation does not break past signatures. This property closes the gap between "someone signed this" and "a specific identified person signed this." A traditional digital signature (PGP, S/MIME, X.509) binds content to a key. Resolving that key to an identity requires a separate channel: a key directory, a certificate authority, a web of trust. A did:julia signature carries the resolution step inside the signature itself. ## **The identity structure** A not.bot identity consists of one **root DID** and any number of **alias DIDs**. Each is a separate did:julia coin on the Chia blockchain. Both the root and every alias have the same coin structure. The root DID is the recovery anchor of the identity. If you lose your keys, recovery operates on the root DID first. The root never signs content or presents credentials. Alias DIDs are the identifiers a user interacts with the world through. Each alias has its own keys, its own credentials, and its own signature history. A user creates as many aliases as they need: per-site aliases for privacy, named aliases for public personas, scratch aliases for one-off contexts, hidden aliases for sensitive use. The not.bot app holds one BLS12-381 secret key on the user's device. Every DID in the user's identity (the root and every alias) is identified by a separate public key derived from that secret. The derivations are independent: given two of the user's alias public keys, no observer (Julia Social included) can determine they share a parent. Unlinkability across aliases follows from the derivation structure. The same property applies to credentials. The same credential value (a first name, for example) issued to two aliases produces two cryptographically distinct credentials that cannot be correlated to a common subject. A user with a public-facing journalist alias and a private personal alias, each holding their first name as a credential, can present that first name to two verifiers without giving either verifier the ability to recognize the same human across both presentations. ## **Ownership** The owner of a not.bot identity is the holder of the keys that can sign for the identity. The default ownership model for personal not.bot identities is **single-sig**: one BLS12-381 key, secured by the secure element of the user's device, authenticates every operation on every DID in the identity. did:julia supports two additional ownership models for organizational and high-value identities: **multi-sig** (M-of-N keys required to authenticate) and **multi-class multi-sig** (M-of-N classes of keys, each class with its own quorum). It also supports a **custodian capability** in which a separate DID can operate the identity on behalf of the owner. These models, and the Business DIDs that use them, are the subject of [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). ## **Asset ownership** A did:julia identity can own assets on the Chia blockchain: XCH, CATs (Chia Asset Tokens), NFTs, and DataLayer singletons. An asset coin owned by a DID spends only on command from that DID. The pattern is called pay-to-JDID, and it is part of the shipped protocol; the [did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/) describes the mechanism. A did:julia identity is not itself one of these assets. The identity is an active vault: it holds credentials, signs messages, and owns the assets listed above. An NFT or a CAT is a static token that a DID owns. The identity is the thing that does the owning. Selling or transferring an identity is not a supported operation. The owner is the holder of the keys that can sign for the identity, and control of an identity moves through the ownership and recovery models, key rotation and recovery agents, not by handing a token to someone else. A user who wants a fresh, unlinkable context creates a new alias rather than acquiring an existing one. Two properties separate DID-owned assets from key-based wallets. **Assets follow identity.** The asset coin is bound to the DID's permanent launcher ID, not to a key. When the owner rotates keys, control of every owned asset moves with the identity. When the owner recovers a lost identity, the recovery restores control of every owned asset. There is no seed phrase whose loss strands the assets. **One ownership model over identity and assets.** The same ownership model that authorizes identity operations, single-sig, multi-sig, or multi-class multi-sig, also governs every asset the identity owns. A business identity under multi-class multi-sig controls its treasury under the same key classes that control its DID operations, so a treasury spend clears the same quorum that a key-rotation or delegation operation clears. A custodian operating an identity operates its assets under the same restrictions and the same attributable record. No separate wallet policy layer exists, because there is no separate wallet. **The not.bot app is not a wallet.** The app holds the signing key and the consent step, nothing more. It does not index the blockchain, does not track balances, and does not contain asset-handling logic. It is not going to become a wallet; that boundary is a design commitment. **Websites as asset front-ends.** The flow that brings these pieces together is on the roadmap. A website reads the blockchain to find the assets a DID owns, presents them in its own interface, and constructs the spend the user wants to make. The website hands the transaction to the not.bot app. The app shows the user a plain statement of what the transaction does and signs on the user's consent. The website never holds keys, and the app never builds asset UX. The smallest version of this flow is a web-based wallet. The same flow serves anything a Chia spend can express, and a single spend can present credentials and transfer assets together, proving who is paying and moving the funds in one atomic transaction. A related pattern puts a coin under the control of a credential rather than a DID, so that holding a valid credential is what confers the right to spend. [Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/) covers that pattern, pay-to-credential, in its own section. ## **Display and identification** Every alias has a deterministic visual identity computed from its DID. Two devices that hold the same alias compute the same visual identity. No display data needs to sync. **Petnames** are three-word phrases (a typical example: "endlessly-altruistic-whale") derived from the alias's DID bytes. The not.bot app computes a petname for every alias. The petname is the default user-visible name for an alias. **LifeHash** is a colored visual fingerprint, also derived from the alias DID. Two aliases have visually different LifeHashes. A user can tell their aliases apart at a glance. **Reserved names** are `.nb`-suffixed names a Pro or Verified Signer subscriber can request: `alice-smith.nb`, `notbot_official.nb`. Reserved names are a Julia Social-mediated registry today. The roadmap replaces this registry with on-chain "Julia Vanity Names" that operate autonomously without Julia Social's involvement. When the on-chain mechanism deploys, existing reserved names convert to Julia Vanity Names. **Verified Signer badges** link a specific alias to a specific online or social media account. The badge is a credential issued by Julia Social after verification of an online proof, and held by the alias. When the badged alias signs content and presents the Verified Signer credential, the badge appears alongside the petname or reserved name. **Nicknames** are user-edited private labels for an alias. A nickname is for the user's own use, and it is never disclosed to verifiers. Nicknames sync across the user's devices through an end-to-end encrypted blob on the Recovery Server. The Recovery Server cannot read the nicknames. **Hidden aliases** are aliases the user has marked as not visible in the app's regular alias list. Reaching a hidden alias requires an additional unlock step gated by on-device biometric or passcode authentication. The concept is similar to a browser's incognito mode: a separated context a user reaches only when they intend to use it. Hidden aliases let a user maintain identities for sensitive contexts on a device that other people sometimes see. ## **Recovery** Recovery operates on the root DID. Once the root DID has recovered, the user's alias DIDs follow. The full recovery model, including pre-rotated keys for instant recovery, time-locked assisted recovery through recovery agents, and the malicious-recovery scenario and countermeasures, is covered in [Recovery (6D)](https://not.bot/technology/recovery/). ## **What lives where** The other documents in the identity series carry the rest of the model. **[Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/)** covers the credential architecture: single-claim credentials, the catalog of credentials Julia Social issues, presentations and the three modes (on-chain, online off-chain, fully offline), the "no phone home" property, antecedents and cascade revocation, and holder presentation. **[Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/)** covers issuer delegation and credential delegation, revocation, multi-sig and multi-class multi-sig ownership, Business DIDs, the custodian capability and its application to personal and non-human identities, and the chain of human accountability that terminates every delegation. **[Recovery (6D)](https://not.bot/technology/recovery/)** covers the recovery model in detail. The **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)** is the implementer-facing reference for the on-chain protocol, complementary to the conceptual treatment here. --- > **Credentials, Presentations, and Selective Disclosure** — https://not.bot/technology/credentials/ · Markdown: https://not.bot/technology/credentials.md · Updated 2026-06-11 # **Credentials, Presentations, and Selective Disclosure** A not.bot™ identity carries credentials. A credential is a signed statement by one entity (the issuer) about another (the subject). Credentials let a user prove facts about themselves without revealing more than they intend, without contacting the issuer at presentation time, and without granting the recipient the ability to re-present the underlying claim. The credential model is the operational substrate of every interaction a not.bot user has with the outside world. Signatures carry credentials. Website verification exchanges carry credentials. The proof-of-human guarantee that distinguishes a not.bot signature from any other digital signature is itself a credential. This document covers the architecture: how credentials are structured, what Julia Social issues, how a user presents them, and the trust properties that follow. ## **Single-claim credentials** A W3C verifiable credential is a JSON-LD document containing some number of claims. Each claim is a statement about the subject. The entire credential, including all claims, is signed by the issuer. Julia Social credentials constrain that model. A Julia Social credential carries one claim. Each claim is signed by the issuer on its own. Metadata about the credential lives in a separate document that the claim references by hash. Multiple Julia Social claims will often share the same metadata file hash. When they do, the claims can be combined into a W3C JSON-LD verifiable credential document. The data the claims contain is extracted into the JSON-LD structure, and the individual claims, the metadata document, and the hash reveals that tie them together are placed in the document's `proof` segment. The result is a standard W3C verifiable credential. The Julia Social model remains interoperable with W3C tooling that consumes that format. This design avoids zero-knowledge cryptography. Selective disclosure, in most W3C-style implementations, requires zero-knowledge proofs to present a subset of claims without invalidating the issuer's signature over the whole credential. Schemes built on BBS+ and similar primitives are complex in practice and computationally expensive. Single-claim credentials make selective disclosure a list operation: present the claims you want, omit the ones you don't. The signatures on the presented claims remain valid. The omitted claims never appear. The design also lets credential claims be presented directly on the Chia blockchain. Each signed claim is self-contained and compact enough to fit inside an on-chain spend. Any smart contract on the Chia blockchain can examine any credential the holder chooses to present and condition its behavior on the result. No other blockchain identity model gives smart contracts this kind of direct access to verified user credentials. The applications span any context where on-chain logic needs to know something verified about the entity initiating an action. On-chain KYC for regulatory-compliant DeFi is one notable case: a contract can enforce that participants hold the credentials a jurisdiction requires, with no off-chain gatekeeper sitting in front of the protocol. Pay-to-credential, where a coin is controlled by the right to present a specific credential, is another. The pay-to-credential section below covers that pattern. ## **Property names** Every claim names the property it carries. The verification-level credentials above show the form: `notbot://./v1/notbot0`. The age credentials, the Domain Name credential, the personal-information credentials each carry a name in the same shape. The name is a URI, and its structure is load-bearing. An issuer designing a credential schema works in this grammar. A bare name like `is_admin` is the problem the grammar solves. Read it cold and the questions stack up. Administrator of what system? Administrative privileges, or the job title an office shortens to "admin"? Give the claim a value of `5` and the ambiguity compounds: level five, on what scale. A name with no issuer behind it and no statement of how its value is encoded tells a verifier nothing it can act on. A well-formed property name describes both the meaning of the claim and the encoding of its value, so a verifier reading it knows when, where, and why the claim applies and how to interpret what it holds. **The three components.** A property name is a URI of the form `encoding:authority/path`. - **Encoding** sits left of the `://` and says how the claim value is encoded. `cleartext://./.julia-payment` carries an unencoded value. `sha2-256|CBOR://./v1/domain_name` carries a value that was CBOR-encoded and then SHA2-256-hashed. - **Authority** names the DID whose namespace defines the property's semantics. A `.` means the issuing DID is the authority, so `notbot://./v1/notbot0` reads as "a property defined by the issuer of this credential." A full DID in the authority position points the verifier at a different namespace, which is how one issuer can issue claims whose meaning a separate body defines. - **Path** is the issuer's own taxonomy: `/v1/pii/age_range_18_20`, `/v1/employee/badge/image`. The issuer owns the path space under its authority and lays it out however its schema needs. **The hash round-trip.** The on-chain claim does not store the cleartext property name. It stores `sha2-256(property name)`. At presentation, the holder includes the cleartext name, the verifier hashes the name it expects to see and checks the result against the hash in the signed claim. A match confirms the claim carries the property the verifier is asking for. **The encoding pipeline.** A claim value is reduced to a 32-byte commitment before it goes into the claim. The encoding segment of the property name describes that reduction. Encodings pipe with `|`, applied left to right: `zip|sha2-256` compresses the value and then hashes it; `rsa3072|zip|sha2-256` encrypts to a single verifier, compresses, then hashes. The current encodings are `cleartext`, `sha2-256`, `argon2id`, `aes256gcm`, `rsa3072`, `zip`, and `CBOR`. The hashing encodings produce a commitment a verifier confirms by re-hashing the value the holder supplies. The encrypting encodings let an issuer restrict which verifier can read a value, so an issuer can mint a credential only the intended recipient can decode. The raw parameters each encoding takes, salts, key fingerprints, nonce placement, live in the encoding registry in [did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/) and [Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/). **Reserved namespaces.** The `julia` and `notbot` property namespaces belong to Julia Social. A third party cannot mint names under them. A property name in either namespace is a Julia Social-defined credential, and decoding its value uses Julia Social software. [did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/) carries the formal grammar for property names and the full encoding registry. ## **Credentials Julia Social issues** Julia Social issues the credentials that ground a not.bot identity's interaction with the world. Most carry personal information sourced from the user's passport. ### **Personal information** During enrollment, the not.bot app reads the passport's NFC chip and verifies the issuing government's digital signature on the data. The static personal-information fields, `FirstName`, `FamilyName`, `Gender`, and `Nationality`, each become a separate single-claim credential. Julia Social produces each one through a multiparty computation and signs it without seeing the value, the same blindness that covers every credential Julia Social issues. These credentials state what the passport showed on the day the user enrolled and expire three years later. The birthdate and the claims derived from it follow a different lifecycle, covered under Age credentials below. A user can enable or disable each credential type on each alias independently. The first alias has personal information enabled by default. New aliases have all personal information disabled by default. The same value issued to two different aliases produces two cryptographically distinct credentials. A user's first name held by their journalist alias cannot be correlated with their first name held by their personal alias. The unlinkability property described in [Identity Architecture (6A)](https://not.bot/technology/identity-architecture/) applies to credentials by construction. ### **Age credentials** The birthdate, its components, exact-age claims, age thresholds (`AgeOver13` through `AgeOver25`, plus `AgeOver100`), and five-year and ten-year age range brackets for ages 20-99 are all derived from the passport's date of birth through a three-party multiparty computation among the not.bot app, Julia Social, and the Escrow Server (operated by Praxis, the independent escrow agent). Neither Julia Social nor the Escrow Server learns the user's birthdate. The MPC produces correctly valued, Julia Social-signed credentials without exposing the underlying data to either participant. These credentials carry a one-calendar-month validity window: Valid-From the first of the month, Valid-To the last day. They refresh together through the same MPC, and every threshold and bracket is issued each time, including the ones that do not apply to the user, so the set requested never reveals which ones apply. When a user crosses an age threshold, the refreshed credentials reflect the new threshold without either party learning when the crossing occurred, because each request re-encodes the full set. The app requests fresh birthdate-derived credentials for an alias only when it does not already hold valid ones for the current month. This caching is a privacy measure, not an efficiency one: refetching on every presentation would give Julia Social and the Escrow Server a usage-frequency signal, and caching denies it. The user can also refresh by hand with a button in the app. ### **The not.bot credential** Every alias holds a not.bot credential. The credential proves the alias belongs to a passport-verified human. It carries a cryptographic value, the not.bot ID, computed through an MPC between Julia Social and the user's app. Neither party can derive the user's identity from the value alone. Julia Social uses the not.bot ID to construct and sign the credential, but does not store it. The value cannot be linked back to the user's passport data outside of one narrow circumstance. That circumstance is law enforcement access. When a court order requires it, Julia Social can identify the holder of a specific not.bot ID through a process that requires Praxis's cooperation. Neither party can do it alone. The mechanics are covered in [Law Enforcement (Doc #9)](https://not.bot/technology/law-enforcement/). For the credential architecture, the relevant point is that the not.bot credential lets a verifier confirm "this signature came from a verified human" without learning who. ### **Verification levels** Three credentials describe the strength of identity proofing the user completed at enrollment. Each is a distinct verifiable credential with its own URI: - `notbot://./v1/notbot0`: at-home enrollment via NFC passport scan (current state) - `notbot://./v1/notbot1`: in-person enrollment at a contracted partner under NIST SP 800-63A IAL2 procedures (planned) - `notbot://./v1/notbot2`: in-person enrollment at a Julia Social-operated facility (planned) The levels are cumulative. A notbot1 holder also holds notbot0. A notbot2 holder holds all three. Cross-issuer enforcement runs through the credential infrastructure. If Julia Social suspects a notbot1 partner of substantial fraudulent issuance, Julia Social can melt the partner's issuer key singleton. The melting operation invalidates every credential the singleton ever signed in one on-chain transaction. Affected users must re-enroll elsewhere. The verifier requests the minimum level appropriate for the use case. The user presents only what the verifier requested. The verifier does not learn the user's maximum verification level unless the user volunteers it. A user holding notbot2 can present a notbot0 response to a notbot0 request without revealing the higher level. ### **Site Pass** A Site Pass is a pairwise identifier unique to a single human-site combination. The same human always produces the same Site Pass for a given site, regardless of which alias they used to interact. The same human produces different Site Passes for different sites. Sites cannot correlate Site Passes across sites. The Site Pass is computed through a three-party MPC between the user's app, the site's Verify instance, and Julia Social. The protocol prevents Julia Social from learning which site generated the request and prevents the site from learning the user's identity. Site Pass is the named exception to the general unlinkability property. A user opts into it for a specific site when the site needs sybil resistance. The site learns "this person, on my site" without learning who or correlating across sites. ### **Verified Signer** The Verified Signer credential links an alias to an online account, often a social media handle. The alias presents the credential alongside content the user signs, and the badge appears in addition to the alias's petname or reserved name. The credential carries the property `AccountName` on the verified alias, with the account identifier as the value, signed by Julia Social after the user completes the verification proof. ### **Domain Name** A Business DID holds a Domain Name credential that links the DID to a DNS domain. A user's app receiving a verification request from a Verify instance checks the request's Domain Name credential against the domain in the universal link or QR code, so the user sees a verified site identity before deciding whether to respond. ## **Selective disclosure** A user presents only the claims a verifier requested. Single-claim packaging makes selective disclosure a list operation: include the claims that match the request, omit the rest. **Property granularity.** The verifier requests specific properties. `AgeOver18` is a separate credential from `AgeOver21`, and both are separate from `BirthDate`. A site can request `AgeOver18` and receive only that property's value. The site does not learn the user's age, age range, or birthdate. **Boolean values.** Many claim values are boolean. `AgeOver18` is true or false. Requesting the claim and receiving a value tells the verifier exactly what they asked, not more. **Volunteered claims.** The user can present more than the verifier requested, but the default is to present only what was asked. The verification level credentials illustrate this: the holder of a higher-level credential can present a lower-level response to a lower-level request without revealing the higher level. **Declined claims.** The user can decline to present one or more claims the verifier requested, even if they hold the requested claims. The user can also decline to provide a presentation at all. ## **Credential metadata** A claim references its credential metadata by hash. The metadata document contains the issuer's human-readable name and description, claim-specific names and descriptions, language translations, and the W3C-standard refresh-service, terms-of-use, and evidence fields. A holder presenting one claim does not have to include the full metadata document. Parts of the metadata can be elided without invalidating the link between the document and the claims that reference it. If the metadata document describes three claims and the holder presents only one, the metadata for the other two can be omitted. Issuer name, description, and icon fields in the metadata file are not trustworthy on their own. Any DID can create a credential and write anything it wants into the metadata. A verifier confirms the issuer's identity through a holder presentation of a credential that names the issuer's DID, issued by a trusted third party (Julia Social being the common case for business names). **External metadata and the tracking signal.** Metadata can live outside the claim. An issuer can host a claim's name, description, and icons in its DID document instead of carrying them inline, which keeps presentations smaller and lets the issuer correct a typo or add a language translation without reissuing. Fetching that external metadata hands the issuer a usage signal. The party that retrieves it tells the issuer's server that this credential was used, and the request timing and origin say where and when. That is the phone-home pattern this document foregrounds, reappearing one layer down. not.bot defaults to inline metadata so a presentation reveals nothing to the issuer. A holder can elide external metadata links before presenting, and a verifier can ignore external metadata even when a presentation includes it. [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/) carries the formal assertion that credential use does not contact the issuer. **Issuer design and validity timing.** An issuer chooses a claim's validity window and its revocation index, and both choices can leak the subject's data if the issuer is careless. An issuer that sets Valid-From on an "over 18" credential to the subject's eighteenth birthday writes the birth date into the validity window, and any presentation of that credential exposes it. An issuer must not encode a sensitive attribute in validity timing. A revocation index assigned in issuance order leaks that order, and comparing two credentials' indices then reveals which was issued first and roughly how many an issuer has issued. An issuer assigns indices so issuance order stays hidden; [Cryptographic Foundations (Doc #12)](https://not.bot/technology/cryptographic-foundations/) covers the index-randomization mechanism. not.bot ships these designs already. The rules become load-bearing for every issuer once third parties run their own issuer keys, which [Roadmap (Doc #20)](https://not.bot/learn/roadmap/) describes. ## **Antecedents** A claim can depend on other claims. The dependency is called an antecedent. A claim is valid in a presentation only when its antecedents are also presented and valid. Antecedents express the relationships that real-world authority structures embed. An access-control claim depends on a role-membership claim, which depends on an employment claim. A claim about an event award depends on a claim about event participation. The antecedent links make these dependencies machine-verifiable. **Cascade revocation.** When an antecedent claim is revoked, every claim that lists it becomes invalid in any future presentation. The verifier walks the antecedent chain at presentation time. One revocation can collapse a tree of derived authority. **Cross-issuer.** Antecedents do not have to share an issuer with the dependent claim. A claim can list antecedents from any number of separate issuers. The dependent claim's issuer learns only that the antecedent claims exist and have not been revoked, not the values they carry. **Cross-subject.** Antecedents can name subjects other than the subject of the dependent claim. Two-person-rule constructions become expressible: a pair of mutually-antecedent claims, each held by a different subject, can only be presented when both subjects merge their presentations. **Structural disclosure.** Presenting a claim discloses the existence and property hashes of its antecedents, and the antecedent claims themselves must be presented for the verifier to accept the presentation. An issuer designing a credential schema should treat the antecedent structure itself as visible to verifiers. **Conditional delegations.** A delegation is itself a credential claim, and a delegation claim can carry antecedents. A delegator uses antecedents to give the verifier context about the purpose of the delegation, and to ensure the delegation cascades correctly when an underlying credential is revoked. **Holder presentations respect antecedents.** A holder presentation of a claim, presented as supporting context rather than as a subject claim, also requires the antecedents to be included. A holder cannot present a claim's existence without also presenting the basis for its validity. **Worked example: cross-issuer with cascade.** A company grants administrator access to its Accounts Payable system through a credential claim. The Accounts Payable Admin claim depends on three antecedents: an In Department: Finance claim issued by the company's HR delegate, a Good or Excellent credit-rating claim from a credit bureau, and a No Felonies claim from a background-check provider. The company's HR delegate issues the access claim. It never sees the underlying credit score or the contents of the background-check report; it learns only that the external claims exist and remain valid. The employee presents the Accounts Payable Admin claim with all three antecedents bundled into the same verifiable presentation. The verifier confirms the access claim, walks each antecedent to its issuer's revocation record, and authorizes the action. When the background-check provider later revokes the No Felonies claim, the next attempted use of Accounts Payable Admin fails. The verifier walks the antecedent chain, finds the background-check claim revoked, and rejects the presentation. The company took no action; the change at the external issuer was sufficient. The same cascade applies to internal role changes: a transfer from Finance to Marketing requires only that the company revoke the In Department: Finance claim, and every access claim that depended on it becomes unpresentable in the same instant. **Worked example: cross-subject.** A hospital pharmacy requires two licensed pharmacists, working together, to authorize any dispatch of a controlled substance. The pharmacy issues a pair of Authorized Dispatcher claims for each pairing of pharmacists, where each pharmacist's claim lists the other's parallel claim as an antecedent. When Pharmacist A attempts to present their Authorized Dispatcher claim, the antecedent requirement pulls in Pharmacist B's parallel claim. Pharmacist A's claim cannot be presented on its own. To authorize a dispatch, the two pharmacists combine their presentations into one verifiable presentation that contains both claims. If either pharmacist is unavailable or unwilling, the dispatch cannot proceed. No central system enforces the two-person rule; the antecedent structure enforces it cryptographically. Delegation as a topic is covered in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). ## **Verifiable presentations** A verifiable presentation is the package a holder assembles to share identity information with a verifier. It can contain signed messages, credential claims, delegation proofs, a timestamp, and a nonce. The package is cryptographically self-contained: everything needed to verify it is bundled inside. did:julia presentations operate in three modes. The same identity and the same credentials work in all three. ### **On-chain** A presentation submitted to the Chia blockchain creates a permanent public record. On-chain presentations support actions that need that record: voting in a decentralized organization, exercising on-chain rights, interacting with a smart contract. The blockchain transaction includes the credential presentation alongside any other operations the identity is performing in the same spend. ### **Online off-chain** Most uses of a not.bot identity are off-chain. The holder constructs a presentation and sends it directly to the verifier. The verifier checks it locally against the blockchain. No transaction is recorded. No third party participates. Off-chain presentations carry an invalidator condition that prevents the spend bundle from being submitted to the blockchain. The condition is structural: the bundle asserts a constraint that can never be satisfied (a concurrent spend of a coin that does not exist). The verifier accepts the presentation because all the cryptographic proofs check out, but no one can take the same bundle and put it on-chain. The act of presenting a credential off-chain cannot be repurposed into a permanent on-chain record of the interaction. Since off-chain presentations do not consume a blockchain transaction, the same identity can produce any number of them at once. Each is verified on its own. ### **Fully offline** A presentation can be verified without internet access. The verifier needs a snapshot of the issuers it cares about: the issuer DIDs, their active signing keys, and the current revocation records. The snapshot contains nothing about individual holders. The holder provides a self-contained proof package: the original key the alias DID was created with, a log of any key changes since, and the credential presentation. The verifier can confirm the DID was created with that key, that the current key is the legitimate one, and that the credential was issued to this DID, without ever having seen the DID before. A game warden in a remote area, a venue gate at an event, a vehicle inspection in a tunnel: each can carry a snapshot of the relevant issuer and verify credentials from holders the device has never seen. ## **Holder presentation** Subject presentation is the direct case: the subject of a credential presents it as a statement about themselves. Holder presentation is the second case: anyone who holds a copy of a credential can present it as supporting context, not as a statement about themselves. A holder presentation lets a recipient see that a credential exists and is genuine, in support of a separate claim. ### **Holder presentation example: concert proof of attendance** A band and a ticketing company each hold Business DIDs. Three credential claims describe the chain of authority around a concert: | Claim | Issuer | Subject | | --- | --- | --- | | Owns `band-domain.com` | Julia Social | Band's Business DID | | Authorized ticket seller for the concert | Band's Business DID | Ticketing company's Business DID | | Attended the concert | Ticketing company's Business DID | Fan's alias DID | The ticketing company gives the fan a copy of all three claims when the fan attends the concert. To prove later that they were there, the fan assembles a verifiable presentation containing: - A subject presentation of the attendance claim (the fan is the subject) - A holder presentation of the authorized-seller claim (the ticketing company is the subject; the fan is not) - A holder presentation of the domain claim (the band is the subject; the fan is not) A verifier who trusts Julia Social's domain credentials can confirm the full chain: the band owns the concert's domain, the band authorized this ticketing company to sell tickets, and the ticketing company issued the fan an attendance credential. The fan never claims to be the band or the ticketing company; the holder presentations supply the chain that establishes who the attendance issuer was. Antecedents can make this required. If the attendance claim lists both the authorized-seller claim and the domain claim as antecedents, presenting the attendance claim requires presenting both holder presentations. The verifier cannot accept the attendance claim on its own. Receiving a holder presentation does not make the recipient a holder of the underlying claim. The signatures on the claims in a presentation are aggregated into a single BLS signature over the whole presentation envelope, and the envelope carries a nonce that binds the signature to this specific presentation. An aggregated BLS signature cannot be disaggregated into a signature over the claim alone, except through signature subtraction, which the nonce prevents. The recipient of a holder presentation cannot extract the underlying signed claim and re-present it elsewhere. The architectural consequence is meaningful: collecting verifiable presentations does not let a verifier build a stockpile of presentable credentials. Each presentation stands on its own. An issuer can mark a credential as non-delegatable when it is issued. A non-delegatable credential cannot be holder-presented at all; only the subject can ever present it. Delegated presentation, the case where a subject explicitly authorizes another identity to present a credential on their behalf, is covered in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). ## **Pay-to-credential** A coin on the Chia blockchain can be controlled by a credential rather than by a cryptographic key. The coin's owner issues credentials, one per coin, granting the holder the right to spend the coin. The holder spends the coin by presenting the credential on-chain. The model is useful because granting and expiring access are off-chain operations. Issuing a credential and letting that credential expire requires no on-chain transaction. The coin remains as it is until the moment the holder spends it. A human can issue credentials for a hundred coins to an AI agent off-chain. The agent can delegate access to a subset of those coins to another agent, with a short expiration (one hour, for example). Coins the delegate does not spend in that hour become unavailable to it. Similarly, when the agent's coin credentials expire, the coins become unavailable to the agent. The human owner retains access at all times. To revoke access before expiration, the owner can update the issuer key singleton's revocation bitfield, which cancels up to 512 credentials in a single on-chain transaction. Pay-to-credential demonstrates the expressive range of the credential model: an identity can grant and expire rights to economic resources at off-chain speed, and revoke rights in batches with a single on-chain operation, while the coins themselves only see on-chain activity at the moment a right is exercised. The sibling pattern, a coin owned by a DID outright rather than controlled by a credential, is covered in the Asset ownership section of [Identity Architecture (6A)](https://not.bot/technology/identity-architecture/). ## **Self-attested credentials** An identity can issue credentials about itself. A user issues a credential giving the value of their chosen avatar, with themselves as both the issuer and the subject. Other identities can hold that credential and reference it when corresponding with the user. Self-attested credentials let a user attach verifiable profile data to their identity without involving an external issuer. The mechanism (self-delegation, where the identity delegates issuance authority to its own key) is covered in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). ## **No phone home** A verifier checking a not.bot credential does not contact Julia Social. The check runs against the Chia blockchain. The revocation bitfield, the issuer key singleton, the alias DID's current state, and any antecedent credentials are all read from the chain. The property is structural across all three presentation modes: - **On-chain presentations.** The transaction itself executes on the chain. No off-chain server participates. - **Online off-chain presentations.** The verifier's blockchain read can hit any of the thousands of public Chia nodes, the verifier's own node, or any other node they choose. Julia Social is not on the path. - **Fully offline presentations.** The verifier checks against a local snapshot of issuer state. Julia Social is not contacted at all. Creating a credential presentation and verifying one are the most common operations a not.bot user performs, and the most common interactions between a not.bot user and the outside world. Neither operation contacts Julia Social. Julia Social is a signer to the No Phone Home movement ([https://nophonehome.com/](https://nophonehome.com/)), which promotes verification architectures in which the identity issuer is not on the verification path. The not.bot credential architecture is designed to satisfy that principle by construction. [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/) carries the formal assertions. [System Architecture (Doc #13)](https://not.bot/technology/system-architecture/) presents the no-phone-home property in the system view. ## **What lives where** **[Identity Architecture (6A)](https://not.bot/technology/identity-architecture/)** covers the structure of a not.bot identity: root and alias DIDs, the cryptographic basis of the identifier, ownership models, display names, and hidden aliases. Credentials are bound to alias DIDs; the unlinkability properties of credentials follow from the alias derivation structure described there. **[Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/)** covers the delegation infrastructure: issuer delegation (how Julia Social signs every credential through a singleton-bound delegate key), credential delegation (how a subject authorizes another identity to present their credentials), self-delegation as the mechanism behind self-attested credentials, the revocation operations on the issuer key singleton, Business DIDs and their governance models, and the custodian capability. **[Recovery (6D)](https://not.bot/technology/recovery/)** covers the recovery model. The **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)** is the implementer-facing reference for the on-chain protocol, complementary to the conceptual treatment here. --- > **Delegation and Organizational Identity** — https://not.bot/technology/delegation/ · Markdown: https://not.bot/technology/delegation.md · Updated 2026-06-10 # **Delegation and Organizational Identity** A not.bot™ identity that controls valuable assets, signs important documents, or makes binding commitments needs an ownership model strong enough to be safe and operational enough to be useful. These goals pull in opposite directions. The stronger the model (more keys required, more parties involved, more airgaps in the signing chain), the more friction every action carries. The looser the model, the larger the blast radius if a key is compromised. Delegation closes the gap. A heavily-protected identity can delegate narrow, time-bound, revocable authority to less-protected identities that handle routine operations. The protected identity is used only when it must be. The delegates do the day-to-day work. The protected identity retains the authority to revoke any delegate at any time. This document covers the delegation infrastructure in `did:julia`: the ownership models that benefit from delegation, the two distinct delegation mechanisms (issuer delegation and credential delegation), mandate credentials for capability cascades through AI agents and other principal-agent relationships, self-attested credentials, and the chain of human accountability that terminates every delegation. ## **Principal authority** The legal frame that grounds did:julia delegation comes from English common law and the law of agency. A *principal* holds authority. A principal can delegate authority to an *agent*. The agent acts within the scope of the delegation. The principal retains the right to direct, revoke, and replace the agent. The agent owes duties (transparency, good faith, action in the principal's interest) back to the principal. The State of Wyoming codified this frame for digital identity in 2021. [Wyoming SF0039](https://wyoleg.gov/Legislation/2021/SF0039) defines a personal digital identity as "the intangible digital representation of, by and for a natural person, over which he has principal authority and through which he intentionally communicates or acts." The law assigns the natural person the rights of existence, control, persistence, and consent. It assigns service providers the duties of access, transparency, portability, data minimization, and disclosure. `did:julia` is the principal authority frame implemented in cryptography. Every action taken under a not.bot identity traces back through a chain of delegations to a principal who authorized the chain and can revoke it. The chain terminates at a human key-holder. ## **Why delegation matters** Several real-world structures require delegation to function. **Non-digital powers of attorney.** A person assigns another person the authority to act on their behalf, time-bounded, scope-limited, revocable. The same structure expressed digitally is a delegation. **Companies as non-actors.** A company does not have hands. Every action a company takes happens through a human acting under the company's authority. The company is a governance structure over its human signers, and every operational action is a delegation from that structure to a specific person carrying it out. **Human hierarchies.** An organization assigns roles, each role carries authorities, and people occupy roles. A person leaving the organization vacates the authorities the role carried. Delegation expresses both the assignment and the vacation in cryptography. **AI agents.** A human asks an agent to act on their behalf. The agent acts on the human's authority, within whatever scope the human granted. A multi-agent system extends the chain: a human directs an orchestrator, the orchestrator directs workers, each step narrowing the scope. The verifier at the far end of the chain confirms that the worker's attempted action falls within every authorization in the chain that led to it. `did:julia` carries all of these structures through the same mechanisms. ## **Ownership models** Before delegation can happen, an identity needs an ownership model. `did:julia` supports four. ### **Single-sig** One BLS12-381 key authenticates every operation. This is the default model for personal not.bot identities. The key is secured by the secure element of the user's device. ### **Multi-sig** M-of-N keys are required to authenticate any operation. N keys exist, often held by N separate parties. M of them must produce a valid signature on the operation. A 3-of-5 multi-sig requires 3 signatures from a set of 5. Multi-sig suits any identity where no single key-holder should be able to act alone: a joint account, a small partnership, a family identity, a high-value personal identity that the user splits across multiple devices and hardware signers. ### **Multi-class multi-sig** The multi-sig structure extended one level. X-of-Y *classes*, where each class is an M-of-N multi-sig. To authenticate, X classes must each produce a valid M-of-N signature. A single signer can belong to multiple classes but participates in only one class per transaction. Julia Social's own corporate DID uses this model. The ownership is "2-of-2: 2-of-3, 1-of-3." To use the identity, 2 of 3 executives must sign AND 1 of 3 airgapped hardware signers must sign. The airgapped signers hold keys that never connect to the internet. They sit in separate, secure locations. No combination of compromised executives can use the identity without the hardware signers, and no combination of compromised hardware signers can use it without the executives. Multi-class multi-sig is a protocol feature available to any identity. A personal identity that holds substantial assets can adopt it the same way a corporation does: one class of device keys, one class of hardware signers, both required. Today's not.bot app handles only single-sig DIDs, a current limitation of the app, not the protocol. ### **Custodian** A *custodian* is a separate DID authorized to operate the custodied identity. The custodian uses its own keys, signs operations with them, and the custodied identity acts under that authority. Every action a custodian performs is attributable: the custodied DID's on-chain spend record identifies the commanding custodian DID. The custodian has three restrictions. A custodian cannot rotate the owner's keys, cannot participate in recovery on behalf of the custodied identity, and cannot extend custodial control to a third identity through the custodied identity. These restrictions protect the principal's ultimate authority over the identity. The custodian is `did:julia`'s bounded analogue of the [DID controller](https://www.w3.org/TR/did-1.0/#did-controller) defined in W3C DID Core: an external DID authorized to act for the subject. The DID controller of that specification holds open-ended control over the DID document. The custodian operates inside the three fixed restrictions above, so the principal keeps key rotation, recovery, and the power to extend control out of any custodian's reach. Custodianship covers three families of use cases. **Personal: power of attorney, conservatorship, guardianship.** A power of attorney allows one person to delegate specified legal rights to another, so that the other to act on the person's behalf. A parent acts as custodian for a child's identity until the child comes of age. An adult child acts as custodian for an elderly parent whose capacity to manage a digital identity has declined. A court-appointed guardian acts as custodian for a person determined unable to manage their own affairs. The legal structure (POA, conservatorship, guardianship) and the cryptographic structure (custodian DID with three restrictions) line up. **Business: commercial digital asset custody.** An enterprise that prefers not to manage its own cryptographic keys assigns a commercial custodian as the operating DID of its corporate identity. The custodian operates under its own multi-class multi-sig and uses the client's identity to perform actions the client authorizes. The same companies that custody digital assets today will offer custodianship for enterprise digital identities. **Non-human identities.** A DID can be created with no owner keys at all, controlled only through one or more custodians. This suits devices and physical assets that have no capacity to manage cryptographic keys: a real-estate DID controlled by the title-holder or a piece of equipment whose custodian changes when the equipment changes hands, for example. ## **Issuer delegation** A Julia Social DID never signs credentials with its own keys. The DID delegates issuance authority to an *issuer key*: a singleton coin on the Chia blockchain, owned by a single BLS12-381 key, configured with a set of constraints that limit what credentials the key can sign. The constraints are the design of the delegation. Each one limits the delegate's authority. - **Authorized BLS public key.** The single key permitted to sign credentials under this delegation. If the key is compromised, only this delegation is affected, not the issuing DID. - **Validity window.** A start time before which the delegation is not active, and an end time after which it expires. The delegate cannot sign credentials outside this window. - **Max expiration.** A latest date any credential signed by this delegation can carry. The delegate cannot issue a credential that outlives the constraint, regardless of the expiration date the delegate sets. - **Allowed property set.** The set of credential types the delegate may sign. The delegate cannot sign a credential property the original issuer did not authorize. The separation a state government enforces between county clerks (marriage licenses) and the DMV (driver's licenses) is expressible at the property level. The allowed property set is open by default. A delegated issuer key with no allowed property set can sign credentials under any property in the delegator's namespace. A delegator that wants to scope a key sets the allowed property set on it, and a careful delegator does not leave a production issuer key in the open default. Julia Social uses issuer delegation in production. The corporate "2-of-2: 2-of-3, 1-of-3" identity is used periodically to delegate credential-issuance authority to a fresh issuer key singleton. Every credential a user receives is signed by one of the current delegates. When necessary, the corporate identity issues a new delegation to a new issuer key. The protected corporate identity therefore touches the chain only occasionally. Day-to-day credential issuance happens through the delegates. ### **Revocation operations on an issuer key singleton** Three on-chain operations can revoke or destroy an issuer delegation. The protocol gives the issuing DID an override path so that a compromised delegate cannot keep the delegation alive. - **Revoke by issuer key.** The delegate updates the issuer key's revocation bitfield to mark specific credentials as revoked. This is the normal operational path. Up to 512 credentials can be revoked in a single transaction. The revocation bitfield supports up to 131,072 separately-revocable credentials. - **Revoke by issuer DID.** The issuing DID updates the revocation bitfield without the delegate's signature. The protocol does not require the delegate to participate. This is an override path used when necessary. - **Melt the issuer key.** The issuing DID destroys the singleton. Every credential the singleton ever signed becomes unverifiable in one transaction. There is no need to track down individual credentials. Melting the issuer key singleton is the strongest tool. As an example, it is the enforcement mechanism for not.bot enrollment partners. If Julia Social suspects a not.bot enrollment partner of substantial fraudulent issuance, Julia Social can melt the partner's issuer key singleton(s). Every credential the partner ever issued becomes invalid at once. Affected users re-enroll elsewhere. A credential holder cannot revoke their own credentials. The "compromised delegate" scenario is handled by the issuing DID directly, without the delegate's cooperation. Either party can revoke. The delegate that holds the issuer key can revoke individual credentials it has issued, within the authority it was granted. The issuing DID holds that same power and adds the override path above, which it can exercise without the delegate's cooperation. ## **Credential delegation** A credential subject can authorize another identity to *present* one or more of their credential claims. The delegate presents the credential, the verifier accepts the presentation, and the verifier sees the credential as if the subject had presented it. The verifier also sees that the presented credential is delegated. The original subject retains the right to revoke the authorization at any time. Whether a credential can be delegated at all is a choice the issuer makes at issuance. Some credentials are marked non-delegatable; only the subject can ever present them. A presentation delegation is always time-bounded. It carries a Valid-From and a Valid-To, so no delegate holds presentation rights indefinitely, and the subject can revoke before the window closes. The subject scopes a presentation delegation along three axes: by issuer, by property, and by value. Value scoping is optional. The three axes let a holder delegate "present my age-over-21 claim from this issuer" without delegating the rest of the credential. A user can authorize an agent to present any credential from their employer limited to job title and not salary. ### **Subdelegation** When the issuer permits it, a delegate can in turn authorize another identity to present the same credential. Each delegation is its own independent claim. The terminal delegatee presents the original subject's claim as if it were their own, alongside the chain of delegations that connects them. The chain is validated by *chain walk* at presentation time. The verifier walks every link, confirms each is signed, current, and unrevoked, and confirms the underlying credential is itself valid. Revoking any link in the chain breaks presentation for everyone downstream of that link. Attenuation comes through each delegation's own expiry, which can be shorter than the underlying credential's. ### **Worked example: pay-to-credential with delegated agent access** A user owns 100 Chia coins controlled by `p2_claim`: each coin unlocks when the holder presents a specific credential the user's DID issues. The user issues 100 such credentials to an AI orchestrator agent, each credential granting the orchestrator the right to spend one of the coins. In this example, the credentials carry no expiration; the user plans to keep them active for the agent's working lifetime. The orchestrator needs a sub-agent to handle a 30-minute trading window. The orchestrator delegates presentation of 10 of the credentials to the sub-agent, with the delegation expiring in 30 minutes. To make a trade, the sub-agent presents the credentials on-chain to spend the coins. After 30 minutes the delegation expires. The sub-agent cannot present any further. Coins the sub-agent did not spend remain untouched and under the orchestrator's control. The user's underlying credentials and coins are not affected. If the user wants to revoke the orchestrator's access, the user's issuer key singleton updates its revocation bitfield. All 100 credentials can be invalidated in one transaction. Every delegated sub-agent downstream of the orchestrator loses access in the same instant. ## **Mandate credentials** Mandate credentials are a different pattern from credential delegation. Credential delegation passes presentation rights for an existing credential through a chain. Mandate credentials are *new* credentials issued at each link in the chain: the principal issues a credential to the agent granting specific authority to act. When the agent issues a narrower mandate to a downstream agent, the downstream mandate lists the upstream mandate as an antecedent. The chain is verified by walking antecedents through the credential graph. The verifier's job at the end of a mandate chain is to confirm that the action the terminal agent is attempting falls within the scope of every mandate in the chain. Each mandate must be the same or narrower in scope than the one above it. The terminal action must be permitted by all of them. Mandate credentials are an open pattern any issuer can use to encode attenuated capability. The pattern admits two distinct verification styles. ### **Unstructured mandates: AI-verified scope** A mandate written as natural language ("book economy flights between San Francisco and major US cities, total spend under $2,000, travel dates within the next 60 days") is unstructured. A verifier has no rule-based way to parse it. To enforce the mandate, the verifier uses an AI to evaluate whether a specific attempted action falls within the natural-language scope. The AI's judgment is the enforcement mechanism. Unstructured mandates suit cases where the scope of authority is fluid, contextual, or expressed at a level of detail no rigid schema can capture. #### Worked example: AI travel booking cascade A user wants their travel managed by AI agents. The user issues a mandate credential to a travel orchestrator agent. | Issuer | User's alias DID | | :---- | :---- | | Property | Mandate | | Value | "Book travel for me. Total annual spend under $20,000. No first-class. Notify me before booking anything over $3,000." | | Subject | Orchestrator's DID | The orchestrator handles itinerary planning, hotel selection, and flight booking. For flights it relies on a specialized worker agent. The orchestrator issues a narrower mandate to the worker. | Issuer | Orchestrator's DID | | :---- | :---- | | Property | Mandate | | Value | "Book economy or premium-economy flights only. Departure airports SFO or OAK. Total spend per trip under $1,500." | | Subject | Worker's DID | | Antecedents | The user's mandate credential to the orchestrator | The worker attempts to book a flight from SFO to JFK at $1,200 in economy. The worker assembles a verifiable presentation containing its own mandate (subject presentation, since the worker is the subject) and the orchestrator's mandate (holder presentation, since the orchestrator is the subject of that one). The presentation is sent to the airline's booking system. The airline's verifier walks the antecedent chain from the worker's mandate to the orchestrator's mandate to the user, confirms each step is valid and unrevoked, and uses AI to confirm the attempted booking falls within the scope of both mandates: the orchestrator's $1,500 cap, SFO/OAK origin, and economy/premium-economy class, plus the user's $20,000 annual cap and no-first-class restriction. The booking proceeds. If the user revokes the mandate to the orchestrator, the antecedent chain breaks. The worker's next presentation fails. No on-chain action is needed against the worker; the cascade follows from the antecedent structure. ### **Structured mandates: rule-based scope** A mandate expressed as structured scopes (OAuth 2.1-style permission tokens like `flights.book.economy`, `flights.spend.max.1500`) is rule-parseable. The verifier parses the scope list and confirms each requested action matches a permitted scope. The judgment is mechanical and auditable. Structured mandates suit cases where the scope is well-defined, the verifier wants reproducible enforcement, and the audit trail needs to be machine-readable. #### Worked example: structured mandate for a personal finance agent A user issues a structured mandate credential to a personal finance AI. | Issuer | User's alias DID | | :---- | :---- | | Property | Mandate | | Value | `["account.read.balances", "account.read.transactions", "transfer.create.between_own_accounts", "transfer.max_amount.5000", "valid.until.2026-12-31"]` | | Subject | Finance agent's DID | The agent attempts a $2,000 transfer between two accounts the user owns at the same bank. The bank's verifier parses the scope list, confirms `transfer.create.between_own_accounts` is present, confirms the requested amount ($2,000) is under the `transfer.max_amount` limit ($5,000), confirms the current date is before the validity expiration, and authorizes the transfer. The verification follows fixed rules. Two banks given the same mandate and the same request reach the same conclusion. The bank's audit log records the scope strings that authorized the action, traceable back to the user's signature on the mandate. ## **Self-attested credentials** A simple application of issuer delegation: the issuer delegates to itself. An identity delegates issuance authority to its own key, then issues credentials in which it is both the issuer and the subject. The mechanism lets a user attach signed assertions about their own identity without involving an external issuer. The avatar example: | Issuer | User's alias DID | | :---- | :---- | | Property | Avatar | | Value | (SVG of the user's chosen avatar) | | Subject | User's alias DID | The credential is a signed certificate of a fact about the user, made by the user. A self-attested credential carries more weight when it is part of a verifiable presentation. A user who signs a public statement and includes their self-attested display name and avatar produces a presentation that carries the statement, the time it was signed, and a verifiable visual identity associated with the signer. A correspondent who receives the presentation can render the user's avatar alongside the message in their own interface, knowing the avatar is the one the user has cryptographically attached to that alias. The integrity of the data depends on who is reading it. Anyone can self-attest to anything: an attacker could self-attest "this DID is Taylor Swift" without consequence. The value of a self-attested credential is the verifiable cryptographic linkage between the data and the DID. Whether the underlying data is to be trusted is a separate judgment, one that lives outside the credential infrastructure. ## **Human accountability** Every chain of authority in `did:julia` ends at a human key-holder. A worker AI presents a mandate issued by an orchestrator AI; the orchestrator's mandate is antecedent on a mandate from a human user; the user's identity terminates at the BLS12-381 key on a passport-verified human's device. A delegate of Julia Social's corporate DID signs a credential; the delegation was authorized by Julia Social's "2-of-2: 2-of-3, 1-of-3" identity; the executive class is staffed by named humans, and the airgapped class is operated by named humans. Walking back any not.bot signature ends at a named human signer. ## **What lives where** **[Identity Architecture (6A)](https://not.bot/technology/identity-architecture/)** covers the structure of a not.bot identity: root and alias DIDs, the cryptographic basis of the identifier, display names, and hidden aliases. **[Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/)** covers the credential architecture: single-claim credentials, the catalog Julia Social issues, the three presentation modes, antecedents and cascade revocation, holder presentation, pay-to-credential, and the no-phone-home property. **[Recovery (6D)](https://not.bot/technology/recovery/)** covers the recovery model: pre-rotated keys, assisted recovery through recovery agents, and the malicious-recovery scenario and countermeasures. The **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)** is the implementer-facing reference for the on-chain protocol, complementary to the conceptual treatment here. --- > **Recovery** — https://not.bot/technology/recovery/ · Markdown: https://not.bot/technology/recovery.md · Updated 2026-06-10 # **Recovery** A not.bot™ identity is controlled by cryptographic keys the user holds. Keys get lost. A phone falls in a lake or gets stolen. An identity that cannot survive the loss of its keys is not usable. Recovery has to do two things that work against each other. It restores control to the legitimate owner when their keys are gone, and it denies that same path to an attacker trying to seize the identity. A recovery mechanism loose enough to be convenient is also an attack surface for theft and for denial of service. The `did:julia` recovery model is configurable for each identity, so an owner can match the safeguards to what the identity protects. Recovery is the path for keys that are gone. An owner who still holds their keys does not need it. They rotate instead: the current keys sign a replacement set into place in one operation, with no delay and no recovery agents. A rotation can change the ownership model too, collapsing a multi-sig arrangement ([6C](https://not.bot/technology/delegation/)) to a single key or expanding a single key to a quorum, so long as the current owners sign the change. Rotation is the answer to a suspected compromise while the owner still controls a device. Recovery exists for the day the keys cannot sign anything. Recovery operates at two levels. The `did:julia` protocol defines recovery for a single DID: the agents who may authorize it, the delay it waits through, and the configuration it commits. A not.bot identity is a root DID and its alias DIDs ([6A](https://not.bot/technology/identity-architecture/)); recovering it means running the protocol's recovery across the whole set, and that sequence sets the timeline a user sees. ## **Recovery on a single DID: the protocol** Each `did:julia` DID carries its own recovery configuration in its on-chain state: the recovery agents, the delay, and an optional pre-rotated key. The blockchain enforces the rules in this section for any DID, whether it anchors a person, an alias, or an organization. ### **Recovery agents** A recovery agent is a DID that the owner has authorized to vouch for a recovery. When the owner needs to recover, each agent confirms the owner is who they claim to be and signs a one-time, time-limited authorization. The owner picks their recovery agents when they set up the identity, and can choose to have none. For an identity that represents something that cannot act for itself, an animal or a physical asset, the person behind it is the natural recovery agent. The custodian role ([6C](https://not.bot/technology/delegation/)) carries no recovery rights, so an owner who custodies such an identity holds the two roles as separate grants: custodian for day-to-day control, recovery agent for the day the identity's keys are lost. Recovery agents are named by DID, not by key. An agent can rotate its own keys, or run its own recovery, without breaking any configuration that names it. The owner sets their agents once and does not track the agents' key changes. ### **Assisted recovery: the delay and what a recovery resets** To recover, the owner's new device generates a fresh keypair. The owner proves their identity to each recovery agent and collects a one-time, time-limited authorization from each. Once a quorum of authorizations is in hand, the owner submits them to the blockchain together, naming the new public key as the DID's owner. The submission starts the recovery. From that moment the DID is locked for a delay set in the recovery configuration. During the delay no operation on the DID is possible, with one exception: the recovery can be canceled. When the delay passes, the recovery completes and the new key on the owner's device controls the DID. A recovery resets more than keys. The configuration a recovery commits can reset the ownership keys, set or clear custodian relationships ([6C](https://not.bot/technology/delegation/)), change the recovery delay, and change the set of recovery agents. All of it is committed when the recovery is initiated and takes hold when the recovery completes, so every part of it sits behind the same delay and the same cancellation. ### **Malicious recovery and countermeasures** The delay exists to defend against a recovery that should not be happening. The danger in assisted recovery is a recovery started by a compromised or dishonest agent. The risk is sharpest with a single agent, because no other agent has to agree. The delay window is the first defense. A recovery is visible on the blockchain from the moment it starts and does not complete until the delay passes. The legitimate owner's software can watch the chain for a pending recovery against their DID and act inside that window. The watch only holds while that software runs; a watchtower service could keep it on the owner's behalf, and the Future state section covers why none exist yet. The owner can cancel a recovery during the delay with the assistance of a quorum of the recovery agents. An owner who made a valid, timely request to cancel can show they made it. An agent that ignored the request and let the recovery proceed cannot later claim it acted in good faith. If a malicious recovery completes without being canceled, the legitimate owner can start a new recovery back to themselves and undo it. A completed theft of the identity does not lock the owner out for good. ### **Multiple agents: M-of-N and multi-class** A single agent is a single point of failure. An agent that is compromised, compelled, or tricked can start a malicious recovery, and an owner who has lost their keys leans on that one agent to cancel it. Spreading recovery across several agents removes the single point. Assisted recovery supports a quorum of agents in an M-of-N arrangement, or several classes of agents, each class with its own quorum. - A 2-of-3 arrangement across three commercial recovery agents recovers even if one agent is unavailable or compromised, and no single agent can recover the identity alone. - A "2-of-2: 2-of-3, 2-of-3" social-recovery model requires two of three friends and two of three family members, acting together. A malicious recovery would need many trusted people to collude. The same group can recover the identity after the owner's death without the legal documentation a commercial agent would wait for. - Agents in different legal jurisdictions raise the cost of compelling them as a group. More agents also make an identity harder to attack at the outset. An attacker has to find and compromise a quorum before acting, and an owner who keeps their agent set private gives the attacker nothing to start from. ### **Instant recovery: pre-rotated keys** A pre-rotated key is a replacement key the owner commits to in advance, while the current key still works. The commitment can name a full ownership model rather than a single key, so a multi-sig identity can hold a pre-rotated arrangement of its own. If the active key is lost or compromised, the owner swaps in the pre-rotated key in a single operation, with no delay and no agents. The swap commits the next pre-rotated key at the same time, so the instant-recovery path stays armed, and it cancels any recovery already in progress, so a pre-rotated key also stops a malicious assisted recovery before it can complete. The pre-rotated key carries one risk: someone compromises it before it is needed. A stolen pre-rotated key gives no warning, since nothing uses it until a recovery happens. The property that creates the risk also limits it. A key that stays unused until it is needed can be kept in stronger storage than a key in daily use. The Future state section illustrates cold-wallet and hardware-signer storage. ## **Recovering a not.bot identity: the root, the aliases, and the Recovery Server** A not.bot identity is a root DID and the associated alias DIDs ([6A](https://not.bot/technology/identity-architecture/)). The root is the recovery anchor: it never signs content or presents credentials, and it controls the aliases. Recovery operates on the root first. Once the root recovers under new keys, the aliases follow. Recovery splits into two jobs. Authorizing the recovery process belongs to the recovery agents, as the protocol defines. The mechanical side, holding the user's encrypted backup and putting each recovery transaction on the blockchain, belongs to the **Recovery Server**. A Recovery Server holds an encrypted backup of the user's identity state (the "recovery bundle"), and submits recovery transactions to the blockchain. The bundle is encrypted under a key derived from the user's recovery password. The Recovery Server operator does not have the password and cannot read the bundle. The recovery bundle is the same backup the app uses to bring an identity onto a new device, so recovering an identity and adding a device draw on the same stored data. [The not.bot App (Doc #5)](https://not.bot/learn/the-app/) covers adding a device. A recovery of the root runs the assisted-recovery sequence the protocol defines. With control of the root restored, the device downloads the recovery bundle from the Recovery Server. Downloading the bundle requires proving control of the root DID, which the device can now do. The bundle decrypts with the owner's recovery password, and the app rebuilds the identity. The new keys come from the device; the bundle carries the rest of the identity's state. The aliases recover after the root, in the sequence and on the schedule that the Recovery Server provides. ## **Recovery today** Julia Social operates the only Recovery Server in service today and is the only recovery agent available. One Julia Social service fills both roles, authorizing recoveries and holding every user's recovery bundle. A personal identity that uses assisted recovery uses a single-agent configuration with Julia Social. A single-agent configuration asks the user to trust one company with the recovery path, a position users already take with their bank or their email provider. The multi-agent and multi-class arrangements the protocol supports wait on other agents to exist. The current app does not expose pre-rotated keys, so instant recovery is a protocol capability a user cannot yet reach. Recovery runs on the root DID first, then the aliases. Julia Social's configuration uses a 48-hour delay, and the schedule is deterministic: | Step | Timing | | --- | --- | | Root DID submitted for recovery | t = 0 | | Root DID recovery completes, if not canceled | t + 48h | | Alias DIDs submitted | over the 24h after the root completes | | Each alias completes | 48h after that alias was submitted | The app becomes usable again as soon as the first alias completes. The app marks aliases still in flight as pending until they finish. End to end, recovering an identity with many aliases takes around five days. ## **Future state** Three changes will widen the recovery model, and Julia Social expects the ecosystem to supply a fourth. **Recovery services other than Julia Social.** Julia Social plans to open-source the Recovery Server, and the open-source design splits the two roles its service combines today. A user can run their own Recovery Server, keeping their recovery bundle under their own control and submitting their own recovery transactions. Authorization moves to the recovery agents the owner chooses: commercial services that hold recovery DIDs and authorize recoveries, friends and family, or a self-hosted agent. Commercial services can offer defined ownership-proof processes, including posthumous recovery with the right legal documentation. The 2-of-3 and multi-class arrangements above become usable once there are agents to fill them. **The app exposes pre-rotated keys.** The protocol supports pre-rotation today; the app does not expose it. A future version of the app will let a user arm the instant-recovery path and keep the pre-rotated key in storage of their own choosing. Two storage choices show what arming the instant-recovery path will look like once the app exposes it. A cold wallet keeps the pre-rotated key offline. The owner generates a future keypair, records its seed as a written mnemonic or stamps it into a steel backup plate that resists fire and water, and pre-rotates the identity to that key's public half. The seed never touches a connected device until the day recovery is needed, when the owner enters it by hand. Nothing reads the key until then, so the offline seed stays out of reach of any digital theft. A hardware signer holds the pre-rotated key in a secure element that does not release it. The owner reads the public key off the device, registers it as the pre-rotated key, and stores the device wherever they keep valuables. The private key stays on the device and never copies out. Recovery means producing one signature from that device, which swaps the identity to the key the device holds. **The verification-level ratchet.** Every enrollment today is notbot0, a passport scan at home. As higher enrollment levels arrive (notbot1 for partner enrollment, notbot2 for first-party facilities, both planned and defined in [Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/)), a recovery agent will be able to require that the identity verification used to recover or cancel meet or exceed the level used to enroll. The rule blocks a downgrade attack: without it, an attacker who could clear a low-assurance check would seize an identity its owner had protected with a high-assurance enrollment. This is a recovery agent's policy, not a property of `did:julia`. Each agent will set its own, and a user weighing agents should read those policies as part of the choice. Julia Social will hold recovery to the level the owner enrolled at. **Watchtower services.** A watchtower monitors the chain for pending recoveries against the identities of its subscribers and alerts each owner inside the delay window, even when the owner's app is not running. Julia Social cannot run one. An alert has to reach the user through an email address or a phone number, either of which identifies the user, and Julia Social will never hold that data. Watchtowers wait on third parties willing to hold that contact information. ## **What lives where** **[Identity Architecture (6A)](https://not.bot/technology/identity-architecture/)** covers the structure recovery acts on: the root DID as recovery anchor, the alias DIDs beneath it, and the identity's on-chain state. **[Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/)** covers the custodian capability. A recovery can set or clear custodians, but a custodian cannot start or take part in a recovery, one of the three restrictions that keep ultimate control with the owner. **[The not.bot App (Doc #5)](https://not.bot/learn/the-app/)** covers the recovery and add-a-device experience from the user's side. **[Security Model (Doc #8)](https://not.bot/technology/security/)** covers the recovery threat model and its known weaknesses, including the single-operator risk (SW1) and the offline attack on recovery bundles (SW6). The **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)** is the implementer-facing reference for the on-chain recovery operations, complementary to the conceptual treatment here. --- > **Privacy Architecture** — https://not.bot/technology/privacy/ · Markdown: https://not.bot/technology/privacy.md · Updated 2026-06-14 # **Privacy Architecture** Proving you are human should not require sacrificing your privacy. not.bot™ enforces a design principle across every component of the system: no party has access to user identity data under normal circumstances. The architecture prevents data collection at the source. Data that was never collected cannot be breached, subpoenaed, or sold. not.bot distinguishes three categories of privacy protection, and this document labels each assertion accordingly. **Architectural impossibilities** are protections enforced by system design. The architecture prevents certain data from reaching certain parties. No policy change, employee action, or security breach can expose data that was never collected. **Policy choices** are protections enforced by Julia Social's operational decisions. Data passes through Julia Social's systems but is discarded without logging. These protections depend on Julia Social honoring its commitments. Code audits and operational transparency make them verifiable. **Contractual controls** are protections enforced by legal agreements with third parties. A contract prohibits certain behavior. These protections introduce counterparty risk but provide accountability and legal recourse. ## **The parties** not.bot distributes trust across several independent parties. Each holds a different slice of data, and the architecture prevents any single party from assembling a complete picture. **The user** holds a verified identity through the not.bot app on their device. The app stores cryptographic keys, aliases, credentials, and contacts in an encrypted database. The database encryption key sits in the device's secure element (iOS Secure Enclave or equivalent Android TEE hardware). **Julia Social** operates not.bot. It issues credentials, runs supporting infrastructure, and serves as the system's credential issuer. Julia Social never receives passport data and holds as little user data as possible. **The escrow agent** ([Praxis Escrow](https://praxisescrow.com/)) is an independent US escrow company that has completed a SOC 2 Type 1 examination. Praxis operates the Escrow Server on its own infrastructure and stores the encrypted identity records the Escrow Server produces. Praxis does not hold the decryption key for those records; Julia Social does. A custom escrow contract binds Praxis to release any record only on a specific law enforcement demand for the user identified by that record, and forbids bulk release. **The Escrow Server** is software Julia Social wrote and Praxis operates. During enrollment, it fetches passport data from Signicat, processes it into multiparty computation inputs, hashes it for duplicate detection, encrypts it to a key only Julia Social can use to decrypt, and discards the cleartext. The Escrow Server also participates in the multiparty computations that produce credentials without learning the underlying personal information. **Signicat** validates passport data during enrollment and recovery. Signicat holds ISO/IEC 27001:2022 certification (DNV certificate C849517, with ISO/IEC 27018:2019 cloud-privacy controls in scope) and is a Qualified Trust Service Provider under eIDAS, listed on the EU Trusted List. Under a custom agreement, Julia Social (the customer) is excluded from downloading decoded passport data; Praxis, operating the Escrow Server, is the only entity with download rights. In normal operation, Signicat deletes passport data within seconds of the Escrow Server downloading it. Retention is capped at five minutes. **not.bot Verify** is server software operated by businesses inside their own infrastructure. Each instance runs its own private blockchain nodes. Julia Social has no visibility into which users a business verifies, when those verifications occur, or what credentials are checked. **Galactechs** provides blockchain node services. Julia Social and Galactechs share a common founder. Users who select the default configuration (random public nodes) never interact with Galactechs. **AWS** provides Julia Social's cloud infrastructure. Data stored on AWS is encrypted at rest. AWS does not possess the decryption keys. ## **Identity without identification** A user's identity in not.bot consists of a **root DID** (the foundational anchor, never shared externally) and one or more **alias DIDs** (the identifiers used for interactions). Each alias has its own cryptographic keys, credentials, and signature history. Aliases are cryptographically unlinkable: examining two aliases, their credentials, and their signatures reveals nothing about whether they belong to the same person. Even Julia Social cannot correlate two alias DIDs, nor identify which alias DIDs are associated with a root DID. **Credentials** are signed statements by an issuer about an alias. Julia Social issues credentials based on information verified during enrollment. They include personal information (name, birthdate, gender, nationality), age thresholds and brackets, and the baseline not.bot credential proving the alias belongs to a verified human. For all aliases except the first one created at enrollment, personal information credentials are disabled by default. The user enables each credential type per alias. **Site passes** are pairwise identifiers unique to a specific human-site combination. They provide sybil resistance: the same human interacting with the same site produces the same Site Pass, regardless of which alias they use. Site Passes for different sites are cryptographically unlinkable, even if those sites collude and share data. Users must consent to allow a Site Pass to be created for a particular site. **Signatures** are cryptographic structures that prove a human reviewed and approved something. They come in two visual formats. QR code signatures store encrypted data on Julia Social's servers, with the QR image containing a randomized URL, a decryption key, and a hash. JAB code signatures embed all data directly in the image. Both formats carry the signer's alias DID, message, credentials, timestamp, and a nonce. ## **Enrollment data flow** During enrollment, passport data follows a controlled path. The app reads only DG1 from the passport NFC chip (name, birthdate, gender, nationality). No facial image is read. No biometric data leaves the passport chip. The data goes from the app to Signicat for validation. Signicat checks the chip's digital signatures and passport expiry, then holds the validated data by session ID. The Escrow Server downloads the data using that session ID, tells Signicat to delete it, and Signicat complies within seconds. The Escrow Server then hashes the personal data with a pepper for duplicate detection, preprocesses and anonymizes it for multiparty computations, encrypts the cleartext to a key Julia Social holds on air-gapped hardware, stores the encrypted record, and discards the cleartext. The Escrow Server never writes cleartext identity data to persistent storage. Julia Social never sees the passport data at any point in this flow. ## **What Julia Social cannot access** Julia Social's infrastructure never has access to the following. These are architectural impossibilities. **P1.1** Passport data, including name, birthdate, gender, nationality, passport number, or photograph. **P1.2** Email addresses, phone numbers, or any other contact information. **P1.3** Payment card numbers, bank account information, or financial account details. **P1.4** Apple ID or Google Play account identifiers. **P1.5** Device contacts, location data, or any data that could fingerprint the device. **P1.6** The cleartext contents of any signature (message, alias, or credentials), in either QR or JAB format. **P1.7** Biometric data. **P1.8** Which sites a user interacts with. **P1.9** Which users a site interacts with. **P1.10** When a user creates or scans a JAB code signature. ## **What Julia Social receives but discards** Julia Social's infrastructure receives certain data during normal operation but discards it without persistent storage or logging. These are policy choices. **P2.1** Server logs contain timestamps for operational monitoring but no IP addresses, alias identifiers, credentials, or other information that could correlate a log entry to a user. **P2.2** Julia Social does not store the credentials it issues, other than Verified Signer credentials. **P2.3** Recovery endorsement requests are not stored. **P2.4** Age credential requests are not stored. **P2.5** The association between a reserved name and the root DID that registered it is not stored. **P2.6** The association between a user's root DID and their alias DIDs is not stored. Given an alias DID, Julia Social cannot determine which other aliases belong to the same person. *Exception:* For aliases holding Verified Signer badges, Julia Social retains the root-to-alias mapping to enable subscription-lapse revocation. *Exception:* Julia Social operates the only Recovery Server and observes the complete set of aliases belonging to an identity for the duration of the recovery and rekey operations. **P2.7** The unhashed original transaction ID for subscribers is not stored. **P2.8** IP addresses from faucet coin requests are held in memory for rate limiting and are never written to persistent storage. **P2.9** The coin IDs provided with faucet coin requests are not stored. ## **What Julia Social cannot derive** Even from data Julia Social does process or store, the following cannot be derived or inferred. **P3.1** Julia Social cannot determine which root DID an alias belongs to without possessing a signature created by that alias. **P3.2** Julia Social cannot determine which sites a user creates Site Passes with. **P3.3** Julia Social cannot correlate QR code signature fetches to users. **P3.4** Julia Social cannot derive passport data or credential values from the data it processes or stores. **P3.5** Julia Social cannot access the contents of QR code signatures. Julia Social hosts the encrypted signature data but does not have access to the decryption key. **P3.6** Julia Social cannot alter the contents of a QR code signature without detection. Any modification to the stored data would be detected when the scanning app verifies the decrypted result against the hash embedded in the QR code. **P3.7** Julia Social cannot access the cleartext contents of the encrypted recovery bundle. **P3.8** Julia Social cannot determine how often a user presents age credentials, nor when within a month a user crosses an age threshold. The app requests fresh age credentials only when it lacks valid ones for the current month, so the refresh rate does not track how often the user presents them. Each request returns the full set of thresholds and brackets with a new encoding, so two requests in the same month reveal no threshold crossing between them. ## **What the escrow agent cannot access** **P4.1** Praxis cannot access cleartext passport data after enrollment completes. The Escrow Server discards the cleartext before any persistent storage. **P4.2** Praxis cannot decrypt the encrypted identity records it stores. Julia Social holds the decryption key on air-gapped hardware. **P4.3** Praxis cannot determine a user's age or birthdate from the stored MPC input values. **P4.4** Praxis cannot determine how often a user presents age credentials, nor when a user crosses an age threshold, for the reasons in P3.8: the app caches credentials for the month, and every refresh re-encodes the full threshold and bracket set. ## **What sites cannot learn** Sites operating not.bot Verify receive only the information users consent to share. **P5.1** A site cannot learn a user's root DID. **P5.2** A site cannot learn which other aliases a user controls. **P5.3** A site cannot learn a user's interactions with other sites. **P5.4** A site cannot learn credential values the user did not consent to share. **P5.5** A site cannot determine whether two aliases belong to the same human unless both aliases have presented a Site Pass to that site. Matching Site Passes reveals that both aliases belong to the same person. This is the intended behavior: Site Passes are a consent-based mechanism. A user who declines to provide a Site Pass accepts that the site cannot offer sybil-resistant services. **P5.6** A site cannot forge or modify credentials. **P5.7** Colluding sites cannot determine whether credentials from different aliases originate from the same human. Credentials issued to different aliases are cryptographically independent: even when the underlying values are identical (same name, nationality, or age), the signed credentials contain no common artifact that enables correlation. ## **Contractual privacy controls** **P6.1** Praxis will not release encrypted identity data to Julia Social without Julia Social presenting a valid law enforcement demand for that specific user's data, identified by root DID. **P6.2** If Julia Social's contract with Praxis terminates, Praxis may transfer data only to a successor escrow agent bound by equivalent restrictions. If no successor is established within 90 days, Praxis must delete all data. **P6.3** Praxis will not release encrypted identity data to any party unless compelled by legal due process. ## **What external observers cannot learn** **P7.1** Blockchain observers cannot correlate alias DIDs to root DIDs. **P7.2** Blockchain observers cannot determine which credentials an alias holds. (*Exception:* Credentials presented on-chain become visible to observers.) **P7.3** Blockchain observers cannot correlate two aliases as belonging to the same person. **P7.4** Blockchain observers cannot detect when a user interacts with a site. **P7.5** Blockchain observers cannot detect when a user creates or scans a signature. **P7.6** Blockchain observers cannot determine when a new user joins. **P7.7** Blockchain observers cannot distinguish real DID operations from decoy operations. Julia Social generates continuous decoy DID operations (creates, recoveries, and rekeys for nonexistent users) using the same faucet coin mechanism as real operations, making them indistinguishable on the blockchain. **P7.8** Blockchain observers cannot detect when a credential is issued. **P7.9** Blockchain observers who detect a credential revocation event cannot determine which credential was revoked or which alias holds it. **P7.10** Network observers cannot determine a user's identity, credential values, or alias associations from network traffic. Network observers can determine that a user communicates with not.bot infrastructure and may infer operation types from timing and destination patterns. A VPN mitigates most network-level observation; encrypted DNS mitigates DNS-level observation. ## **What Signicat cannot learn** **P8.1** Signicat deletes passport data within seconds in normal operation, within five minutes by configuration, and within 50 days by contract. **P8.2** Signicat cannot determine whether a passport scan is for initial enrollment or recovery. **P8.3** Signicat cannot determine which not.bot identity is associated with a passport. **P8.4** Signicat cannot correlate multiple verification sessions for the same passport over time. **P8.5** Julia Social cannot access passport data through Signicat. ## **What infrastructure providers cannot learn** **P9.1** AWS cannot access cleartext user data. Data stored on AWS is encrypted at rest. **P9.2** Galactechs cannot access user identity or credential data. Blockchain queries contain only public DID identifiers and credential revocation indices. **P9.3** Galactechs cannot correlate blockchain queries to users. Galactechs retains only aggregate request timestamps for capacity planning. **P9.4** Apple and Google know a user installed the app and pays for a subscription (including tier). Julia Social stores only a hash of the original transaction ID and cannot reverse it to an Apple ID or Google Play account. Apple and Google cannot determine what a user does within the app. **P9.5** Apple and Google cannot correlate subscription verification requests from Julia Social with user actions. Julia Social queries only the original transaction ID, which contains no information about operations, aliases, or credentials. ## **What the Recovery Server can access** **D9.1** The Recovery Server operator stores the encrypted recovery bundle for each user. The operator cannot decrypt it. The bundle is encrypted with a key derived from the user's password, which the Recovery Server does not possess. **D9.2** The Recovery Server operator stores the user-assigned device names for all devices registered to an identity. These names are chosen by the user and do not correspond to OS-level device identifiers. Device names may contain personal information if the user chooses identifying names. ## **Compromise scenarios** **P10.1** Compromise of Julia Social's production infrastructure exposes no stored user identity data. A persistent attacker who controls Julia Social's infrastructure could begin logging data that Julia Social discards by policy, voiding all P2 protections going forward. Data discarded before the compromise cannot be recovered. **P10.2** Compromise of Praxis alone does not enable decryption of stored identity data. **P10.3** Compromise of both Julia Social's production infrastructure and Praxis does not provide access to user identities. The RSA decryption key required to begin recovering any user's identity data is held on air-gapped devices separate from production infrastructure. **P10.4** Decrypting user identity records requires compromise of Julia Social's production infrastructure (to access the alias-to-root-DID lookup), Praxis (to obtain the encrypted data), and Julia Social's air-gapped decryption infrastructure (to obtain the RSA key). Even with all three, each user's record requires a separate multi-day brute-force computation to reconstruct deliberately erased bits of that user's unique AES encryption key. **P10.5** Compromise of a user's device does not expose aliases, credentials, contacts, or signature history, provided the attacker cannot authenticate to the device. If the attacker can authenticate (known passcode, biometric spoof, or already-unlocked device), the encrypted database is decrypted in memory, from which a sophisticated attacker could potentially extract the data and the user’s cryptographic keys. The user can perform a rekey to invalidate compromised keys, but rekey does not protect data already taken. **P10.6** Compromise of a site's not.bot Verify exposes Site Passes and aliases that users shared with that site, but does not enable correlation with other sites or access to any user credentials. If the site stores the signatures or credential information it receives from users, that data is subject to the site’s data protection policies. Not.bot Verify does not store that information. **P10.7** Signatures captured by a site using not.bot Verify carry dual attribution. Each signature embeds a complete copy of the request that prompted it: the requesting server's DID, its domain-name credential, the nonce, and the claims that server asked for. A captured signature identifies both the human who produced it and the server that requested it. If a site leaks a trove of collected signatures, the trove names its own source. The same embedded request supports audit: a reviewer can ask, for any signature, which server requested it and what claims that server demanded. No tooling extracts the embedded request today; it is a latent property of every Verify signature. **P10.8** Compromise of Signicat exposes only verification sessions in progress at the time, not historical enrollment data. **P10.9** Compromise of Galactechs infrastructure does not expose user identity data. Blockchain queries contain no personal information. ## **Affirmative data disclosures** The preceding sections describe what parties cannot access. This section enumerates, for transparency, the data each party can access in cleartext. Encrypted data the party cannot decrypt, and hashed data with sufficient entropy to prevent reversal, are not listed. **Julia Social** holds: root DIDs (D1.1); alias DIDs (D1.2); a mapping from SHA2-256(alias DID, not.bot credential ID) to root DID, queryable only with both values together (D1.3); a hash of the original transaction ID for each subscriber, associated with their root DID (D1.4); reserved names and their associated alias DIDs (D1.5, public by design); Verified Signer credentials including the alias DID, root DID, and proof URL for each (D1.6); domain name credentials binding server DIDs to domain names (D1.7); the count of reserved names per root DID (D1.8); the count of aliases per root DID (D1.9). **Praxis** holds: root DIDs (D2.1); a peppered hash of passport data used for duplicate detection, further processed and not stored in its original form (D2.2); pre-computed MPC input values for non-age credentials, hashed with Argon2id using a user-specific salt and system-wide pepper (D2.3); pre-computed MPC input values for age credentials with sufficient entropy to prevent age derivation (D2.4); the total count of enrolled identities and the rate of new enrollments over time (D2.5). **Sites** hold: Site Passes for users who created them with that site (D3.1); credentials users chose to share (D3.2); alias DIDs users presented (D3.3); the site's own domain name credential (D3.4); optionally the complete history of all signatures presented to the site (D3.5). **Signicat** holds: passport data during active verification sessions, deleted within seconds under normal operation, within five minutes by configuration, and within 50 days by contract (D4.1). **AWS** holds: encrypted data at rest without decryption capability (D5.1). **Galactechs** holds (for users selecting Julia Social blockchain access): transient blockchain query content containing public DID identifiers and revocation indices, not stored (D6.1); aggregate request timestamps for capacity planning (D6.2). **Public blockchain nodes** hold: blockchain query content equivalent to D6.1, distributed across randomly-selected nodes so that no single node observes a user's complete query pattern (D7.1). **Blockchain observers** can see: when a DID was created, recovered, or rekeyed (D8.1); which public key is associated with a DID at any point (D8.2); a DID's current state (D8.3); credential revocation events (D8.4); delegation events for credential issuance (D8.5). Network observers can determine that a user communicates with not.bot infrastructure and may infer operation types from traffic patterns, but cannot determine the contents of any operation (D8.6). ## **Known privacy weakness** **PW1** The Recovery Server receives all alias spend bundles at once during recovery and rekey operations, exposing the complete set of aliases belonging to an identity in a single moment. Julia Social operates the only Recovery Server today. *Planned mitigation:* Julia Social plans to open-source the Recovery Server software and enable third-party and self-hosted operation, allowing users to remove Julia Social from this role. ## **What users control** **P12.1** Users choose which alias to use for any interaction. **P12.2** Users choose which credentials to share in any interaction. **P12.3** Users choose whether to create a Site Pass for any site. **P12.4** Users control telemetry. Telemetry is disabled by default. When enabled, it includes only screen timing data and aggregate usage metrics (screen access counts, signature and scan counts, QR versus JAB usage). Telemetry contains no identifying information, no alias or credential data, no signature contents, and no information about sites or users the person interacts with. **P12.5** Users control their recovery configuration, including password selection. **P12.6** Users control device authorization. **P12.7** Users can hide aliases from casual inspection of their device. **P12.8** Support logs are stored on-device only and are never transmitted automatically. Logs contain no identifying information, no alias or credential data, and no signature contents. Sharing logs with Julia Social support requires the user to download the log manually from the app and send it through a support channel. ## **Why this architecture** No single point of compromise can expose user identities. Revealing a user's identity requires cooperation between Julia Social and Praxis, plus access to air-gapped decryption infrastructure. Compromising any one party is insufficient. Even compromising all three provides only the ability to decrypt records one at a time, each requiring a separate multi-day brute-force key derivation. Signature creation and signature verification, the two operations users perform most often, do not require Julia Social or the Recovery Server. The app signs content using keys stored on-device. The app verifies signatures using on-chain data from blockchain nodes. Julia Social is contacted only for administrative operations: enrollment, rekey, recovery, alias creation, reserved name requests, Verified Signer credential requests, and QR signature data upload and download. This separation between administrative and runtime operations means a compromise of Julia Social does not affect ongoing signing and verification. For the full treatment of security properties and known weaknesses, see the [Security Model & Known Weaknesses](https://not.bot/technology/security/) document. For the law enforcement access workflow and accountability model, see the [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/) document. --- > **Security Model and Known Weaknesses** — https://not.bot/technology/security/ · Markdown: https://not.bot/technology/security.md · Updated 2026-06-14 # **Security Model & Known Weaknesses** This document describes the not.bot™ security model: what the system guarantees, what threats each guarantee addresses, and where the known gaps are. For the privacy properties of the system (what each party can and cannot learn), see the [Privacy Architecture](https://not.bot/technology/privacy/) document. For the law enforcement access model, see the [Law Enforcement & Accountability](https://not.bot/technology/law-enforcement/) document. ## **Authenticity** Authenticity ensures that identities, signatures, and credentials originate from the parties they claim to originate from. **S1.1** Signatures cannot be forged. A valid not.bot signature requires the private key of the signing alias, stored in the device's encrypted database, protected by the device's secure element. Creating a signature requires biometric authentication or the device passcode at the moment of signing. **S1.2** Credentials cannot be forged. Julia Social signs credentials using delegated issuer key singletons. Forging a credential requires compromising these signing keys. If a delegated key is compromised, Julia Social melts the issuer key singleton, destroying it and invalidating all credentials it signed, then re-delegates to a fresh key. **S1.3** Site Passes cannot be forged. Site Passes are computed through a three-party multiparty computation among the user's app, the site's not.bot Verify server, and Julia Social. All three parties are required to produce a valid Site Pass. **S1.4** Identity cannot be impersonated without key compromise. The BLS signing keys controlling a user's alias DIDs are stored in an encrypted database whose encryption key is held in the device's secure element. Impersonation requires either extracting the signing key from a compromised device or breaking the underlying cryptography. **S1.5** Domain ownership for not.bot Verify is cryptographically verified. Each Verify server's DID is bound to its operator's domain through DNS TXT records. Julia Social issues domain name credentials to servers that prove domain ownership. Users who receive a verification request see the requesting domain name with cryptographic assurance that the request originates from that domain. **S1.6** Recovery requires validation by the user's configured Recovery Server operator(s). In the current single-operator configuration, validation requires possession of the passport used during enrollment. Future multi-participant configurations may support alternative validation methods determined by each operator's policy. ## **Integrity** Integrity ensures that data cannot be modified without detection. **S2.1** Signed messages cannot be modified. The cryptographic proof in a signature covers the message, credentials, timestamp, and nonce. Any change invalidates the proof. **S2.2** Credentials cannot be modified after issuance. **S2.3** Blockchain state cannot be falsified to a properly-connected client. The Chia blockchain uses proof-of-space-and-time consensus, maintained by approximately 30,000 nodes worldwide. **S2.4** The encrypted recovery bundle cannot be modified without detection. **S2.5** QR code signature data hosted by Julia Social cannot be modified without detection. The scanning app verifies the decrypted result against a hash embedded in the QR code. Any alteration to the stored data causes this verification to fail. **S2.6** Credential revocation cannot be hidden from a properly-connected not.bot Verify server. Revocation is recorded as a bit flip in a revocation bitfield on the Chia blockchain. Verify checks revocation status against the blockchain in real time at each credential presentation. Verify requires a synchronized blockchain node and will not accept credentials verified against an out-of-sync node. There is no caching of revocation state. **S2.7** Credentials have defined validity periods. Age credentials are valid from the first day through the last day of the calendar month in which they are issued. Site pass credentials never expire. All other Julia Social credentials (personal information, not.bot credential, domain name credentials) are valid for three years from the first day of the month of issuance. not.bot Verify rejects expired credentials regardless of revocation status. ## **Non-repudiation** Non-repudiation ensures that signers cannot deny having signed. **S3.1** Signatures are bound to the signer's DID and a specific point in blockchain history. **S3.2** Self-attested signature timestamps are embedded in the signed structure and cannot be modified independently. **S3.3** Nonces prevent replay and establish freshness. **S3.4** A signature produced in response to a not.bot Verify request embeds a complete copy of that request, which the Verify server signed. The signature countersigns the request, binding the signer and the requesting server into one non-repudiable record. The signer cannot deny producing the signature, and the requesting server cannot deny asking for it. No tooling extracts the embedded request today; it is present in every Verify signature as a latent property. ## **Availability** Availability ensures that users can access and use their identities when needed. **S4.1** Identity recovery is possible after complete device loss. Recovery requires the user's password (to decrypt the recovery bundle) and validation by the Recovery Server operator (currently requiring the user's passport). **S4.2** Credential verification does not depend on Julia Social's availability. The app verifies signatures using on-chain data from blockchain nodes. JAB code signatures are self-contained and require no server at all. Accessing the credential presentation data for a QR code signature does require Julia Social’s availability, but verifying it does not. **S4.3** Site operations using not.bot Verify do not depend on Julia Social's availability. Verify runs in the customer's own infrastructure with its own private blockchain nodes. Verify continues processing verification requests through extended Julia Social outages. **S4.4** Subscription lapse does not destroy identity. A user's DID, aliases, and key material persist on the blockchain and on their device regardless of subscription status. **S4.5** Age credentials can be refreshed without re-enrollment. Monthly age credential updates are handled by a three-party multiparty computation among the not.bot app, Julia Social, and the Escrow Server (operated by Praxis, the escrow agent), with neither Julia Social nor the Escrow Server learning the user's birthdate. **S4.6** Julia Social cannot selectively deny service to a specific person without first possessing a signature from one of that person's aliases. Identity operations (credential issuance, recovery endorsement, age credential refresh, faucet coin provision) depend on Julia Social's cooperation, but Julia Social has no mapping from real-world identities to root DIDs. ## **Resistance to key compromise** **S5.1** Compromise of a user's device key is recoverable. The user can initiate recovery on a new device using their passport and recovery password, or perform an immediate rekey if they still control an enrolled device. **S5.2** Compromise of a user's password alone does not enable identity takeover. The password decrypts the recovery bundle, but downloading a recovery bundle requires a challenge/response signature from the root DID. An attacker with only the password cannot retrieve the bundle. **S5.3** Compromise of Julia Social's online signing keys enables credential forgery only until Julia Social cancels the delegation and melts the compromised issuer key singleton, invalidating all credentials that key signed. Julia Social limits the number of credentials signed with each issuer key singleton. **S5.4** Compromise of Praxis's systems does not enable credential forgery. The Escrow Server participates in credential issuance through MPC but does not hold Julia Social's signing keys. **S5.5** Compromise of a site's not.bot Verify keys does not enable impersonation of other sites. Each deployment's business DID and signature DIDs are independent, and each signature DID carries a domain credential that Julia Social issues after a DNS check, so a stolen key proves nothing for any domain but its own. Within the compromised site, the honest.bot credential's single-process enforcement surfaces the hijack: the moment a rogue instance starts, the legitimate server's credential is revoked, which signals the compromise. *Planned response:* an attacker who reached the site's OpenBao instance also holds its business DID key, so recovery resets the business DID that sits above the signature DIDs and re-establishes fresh domain credentials down the chain. This response is not implemented today. ## **Known security weaknesses** This section states known weaknesses in the current system alongside planned mitigations. **SW1: Single Recovery Server operator.** Julia Social currently operates the only Recovery Server. When a user has only a single Recovery Server, and that Recovery Server operator is compromised or compelled to act maliciously, it can execute a malicious recovery and refuse to endorse cancellation. The 48-hour recovery pending window provides a detection opportunity (the legitimate user's app can observe the pending recovery on the blockchain), but the current single-operator model offers no defense if the operator is the attacker or cooperates with the attacker. If a malicious recovery completes, the correct owner can still initiate a new recovery back to themselves, provided they retain access to their passport and recovery password, and provided they can secure the cooperation of their recovery server operator. *Planned mitigation:* Multi-class, multi-participant recovery will allow users to configure multiple Recovery Server operators with threshold requirements (e.g., 2-of-3 operators must endorse). No single operator will be able to endorse or block a recovery unilaterally. Julia Social plans to open-source the Recovery Server software and support both third-party commercial and self-hosted recovery agents. **SW2: Malicious app update.** A malicious or compromised app update published by Julia Social could extract BLS signing keys, enabling full impersonation. BLS12-381 keys are stored in the app's encrypted local database rather than the device's secure element, because no existing secure enclave or TEE hardware supports BLS12-381. The database encryption key is held in the secure element, preventing extraction by external attackers, but the app software has access to the decrypted keys during normal operation. A malicious update could exfiltrate these keys, the recovery bundle password, or any other data accessible to the app. *Mitigations:* Independent code audits, app store review processes, and Julia Social's reputational and legal incentives to maintain user trust. These are trust-based constraints, not architectural ones. **SW3: Unaudited MPC protocols.** The multiparty computation protocols used for credential issuance, Site Pass creation, and age credential computation have not yet received an independent security audit. A team of five PhD cryptographers from Galois, Inc., led by Dr. David Archer (Galois's principal researcher in secure multiparty computation), co-developed these protocols. Galois has done extensive MPC work for DARPA, IARPA, and the Department of Homeland Security. The provenance of the protocol design provides meaningful assurance, but it is not a substitute for independent verification. *Planned mitigation:* An independent code audit by Least Authority is planned. **SW4: No liveness check at enrollment.** The identity verification provider (Signicat) validates the passport's cryptographic authenticity but does not confirm that the person scanning the passport is its rightful holder. Someone in possession of another person's passport could enroll using that passport. The legitimate passport holder can recover the identity through the standard recovery process (S1.6), but during the period between fraudulent enrollment and successful recovery, the fraudulent enrollee controls the identity. *Mitigation:* The recovery process provides remediation, not prevention. **SW5: Duplicate passport edge case.** In the rare case where two identical passports exist for the same person (for example, a reissued passport where both old and new versions remain in circulation with identical personal information fields), two parties could each claim ownership of the same not.bot identity and alternately recover from one another. The duplicate detection hash is computed from personal information fields rather than document identifiers, so the system cannot distinguish which party is the legitimate owner. *Planned mitigation:* None. This scenario is expected to be rare in practice. **SW6: Offline brute-force against recovery bundles.** A compromised Recovery Server exposes encrypted recovery bundles to offline brute-force attack. The recovery bundle is encrypted with a key derived from the user's password using Argon2id with parameters meeting or exceeding OWASP guidelines. Downloading a recovery bundle under normal conditions requires a challenge/response signature from the root DID, preventing online attacks. But an attacker who obtains encrypted bundles through a Recovery Server compromise (see SW1) can attempt offline brute-force without rate limiting. The 8-character minimum password requirement provides insufficient protection if the user selects a low-entropy password. *Mitigations:* Users should select a strong password or use a password manager. Open-sourcing the Recovery Server software (see SW1 mitigation) will allow users to self-host their recovery bundles, removing the Recovery Server operator as an attack surface. **SW7: Multi-device JAB code race condition.** The multi-device setup flow displays a JAB code containing encrypted device-sharing data. An attacker who physically observes the victim and scans the JAB code first can win the race to retrieve the one-time setup code from the Recovery Server. The victim's device detects the race condition and warns the user to check their surroundings. The attacker cannot complete the takeover without also knowing the victim's password. *Mitigation:* Users should treat any unexplained failure during multi-device setup as a security event and move to a private location before retrying. **SW8: No device attestation.** Julia Social has not implemented device attestation. The app does not verify that it is running on genuine hardware rather than an emulator or modified device. iOS App Attest and Android Play Integrity API are available platform capabilities that would address this gap. *Status:* Added to Julia Social's development queue. Not yet scheduled. ## **Recovery timing** Recovery restores a user's identity after device loss. The process has specific timing guarantees that create windows for detection and cancellation. The root DID recovery transaction is submitted at t=0. If no cancellation occurs within 48 hours, the root DID recovery completes. The app then submits alias DID recovery transactions over the following 24 hours. Each alias recovery takes 48 hours from submission. The app becomes usable as soon as the first alias completes; aliases still pending appear flagged in the interface. Total worst-case recovery time is approximately five days. Both initiating and canceling a recovery require authorization from the user's recovery agent(s). Recovery and cancellation verification must meet or exceed the user's enrollment level: a user who enrolled through a notbot1 partner (NIST IAL2) cannot recover via a notbot0 passport scan, but can recover through any notbot1 or notbot2 facility. For the privacy implications of recovery (alias exposure to the Recovery Server), see PW1 in the [Privacy Architecture](https://not.bot/technology/privacy/) document. --- > **Law Enforcement and Accountability** — https://not.bot/technology/law-enforcement/ · Markdown: https://not.bot/technology/law-enforcement.md · Updated 2026-06-10 # **Law Enforcement & Accountability** Some uses of not.bot™ would be criminal. Someone could sign child sexual abuse material, authenticated deepfake harassment, or fraudulent financial documents. Law enforcement must be able to identify perpetrators when presented with evidence of such crimes. not.bot makes this possible while preventing the capability from being abused. Identification requires a specific signature, legal process, cooperation between multiple independent parties, and days of computation. The architecture rules out bulk surveillance, fishing expeditions, and shortcuts. ## **The identification process** Law enforcement starts with a specific not.bot signature, the piece of evidence associated with the crime. Without a signature, there is no entry point. Julia Social has no mapping from real-world identities to root DIDs. The signature is the key. **Step 1: Signature to root DID.** Law enforcement presents a valid legal demand to Julia Social along with the specific signature. Julia Social extracts the alias DID and the not.bot credential ID from the signature. Julia Social holds a mapping from SHA2-256(alias DID, not.bot credential ID) to root DID. This mapping can only be queried with both values together, and both values are available together only inside a signature. Julia Social looks up the root DID. **Step 2: Root DID to encrypted data.** Julia Social submits a release request to the escrow agent (Praxis Escrow, an independent US escrow company that has completed a SOC 2 Type 1 examination), accompanied by the law enforcement documentation. Praxis reviews the demand and releases the encrypted identity record. This step takes approximately five business days and carries a significant financial cost. **Step 3: Decryption.** Julia Social performs decryption on air-gapped infrastructure that never connects to the internet. Each user's identity data is encrypted with a unique AES key. The air-gapped RSA key is used to decrypt the AES key used to encrypt the data. During enrollment, the Escrow Server deliberately erases some of the bits of the AES key before RSA encryption. To decrypt a record, Julia Social must reconstruct the missing bits by brute-force, trying all possible combinations until a valid decryption is found. This computation takes 3-7 days per record. **Step 4: Disclosure.** Julia Social provides the decrypted identity information (name, birthdate, gender, nationality) to law enforcement. Total time from demand to disclosure: approximately nine to fourteen days. There is no expedited process. ## **Why bulk surveillance is impossible** The architecture blocks bulk data extraction at every layer. **No bulk lookup exists.** The alias-to-root-DID mapping (Step 1\) requires both the alias DID and the not.bot credential ID. These values appear together only inside signatures. Julia Social cannot enumerate its users, list their aliases, or run a query like "give me all identities." Each lookup requires a specific signature as input. **The escrow agent gates release.** Praxis is an independent third party. It reviews each law enforcement demand before releasing an encrypted record. A request for "records matching a profile" has no meaning in this system, because each record is identified only by a root DID. By contract, Praxis cannot release any record without a specific law enforcement demand for that record, and cannot release records in bulk. **Decryption does not scale.** Each user's record is encrypted with a unique key whose bits were partially erased. Decrypting one record requires a multi-day brute-force computation on air-gapped hardware. Decrypting a hundred records requires a hundred separate computations. The per-record cost makes mass decryption impractical. **Three-party cooperation required.** An attacker or overreaching agency would need simultaneous access to Julia Social's production systems (for the alias-to-root mapping), Praxis's storage (for the encrypted data), and Julia Social's air-gapped decryption infrastructure (for the RSA key and brute-force capability). Compromising one or two of these three is insufficient. ## **Jurisdictional boundaries** Julia Social is a US-based company. Non-US law enforcement agencies must submit requests through a US agency. Julia Social only responds to valid US legal process. ## **Deterrence with accountability** not.bot makes a deliberate design choice: criminal misuse can be investigated, but investigation requires specific evidence (a signature), legal process, multiple independent parties, and significant time and financial cost. The system provides deterrence (a criminal who signs content with not.bot can be identified) alongside accountability safeguards (identification cannot happen without evidence and due process). This model serves both civil-liberties and regulatory audiences. Privacy advocates can verify that bulk surveillance is architecturally impossible and that identification requires real evidence. Regulators and enterprise buyers can verify that the system cooperates with lawful investigation. The same architecture satisfies both requirements because the constraints are structural, not policy decisions that could change. The escrow architecture exists for this purpose. Julia Social could have designed a system where identification is impossible (by not storing encrypted identity data at all) or trivial (by holding identity data in cleartext). The three-party model with an independent escrow agent, air-gapped decryption, and deliberate key erosion sits at a specific point on that spectrum: identification is possible, constrained, auditable, and slow. For the full set of privacy properties that govern what each party can and cannot access, see the [Privacy Architecture](https://not.bot/technology/privacy/) document. --- > **Enrollment and Identity Proofing** — https://not.bot/technology/enrollment/ · Markdown: https://not.bot/technology/enrollment.md · Updated 2026-06-10 # **Enrollment and Identity Proofing** Enrollment is how a person becomes a verified human in not.bot™. The user scans a government passport, the system confirms the passport is authentic and has not enrolled before, and the Chia blockchain receives a new root DID that anchors the person's identity. This document describes the enrollment flow in production today, the identity-proofing strength each verification level attests to, and what a relying party learns from those levels. One verification level ships today: **notbot0**, at-home enrollment via NFC passport scan. Two stronger levels, **notbot1** and **notbot2**, are planned. ## **The notbot0 enrollment flow** A user enrolls from home with the not.bot app and a passport. The app reads the passport's NFC chip, a passport-validation provider ([Signicat](https://www.signicat.com/)) confirms the chip data is authentic, and the Escrow Server (software Julia Social wrote, operated by [Praxis](https://praxisescrow.com/), the independent escrow agent) confirms the passport has not enrolled before and stores an encrypted identity record that only Julia Social can later decrypt. The cleartext passport data is discarded. No party holds the user's data after enrollment completes. ### **Authentication and passport scan** The user scans the passport's NFC chip, sending the data to Signicat. The app reads only DG1, the machine-readable-zone text: full name, date of birth, gender, and nationality. The app does not read DG2, the facial image. No biometric data leaves the passport chip. Signicat validates the chip data, confirms the issuing government's digital signatures on it, and confirms the passport has not expired. On success, Signicat holds the validated data for up to five minutes, keyed by a session ID. Signicat holds ISO/IEC 27001:2022 certification (DNV certificate C849517) and is a Qualified Trust Service Provider under eIDAS, listed on the EU Trusted List. Signicat's identity and document proofing is certified to ETSI TS 119 461, the trust-service identity-proofing standard. ### **Duplicate detection and root DID creation** The app requests a new root DID from the Julia Social backend and passes the session ID. Julia Social asks the Escrow Server whether the session ID belongs to a new person or a returning one. The Escrow Server downloads the data from Signicat, tells Signicat to delete it (Signicat complies within seconds), and extracts the personal text: full name, birthdate, gender, nationality. It hashes that text with a pepper and checks the hash against the hashes it has seen before. A new hash means a new person. The Escrow Server, operated by Praxis Escrow, preprocesses and anonymizes the data into inputs for the multiparty computations that later produce credentials, and then encrypts the data, stores the encrypted record, stores the hash for future duplicate detection, and discards the cleartext. Praxis does not have the decryption key. Julia Social has the decryption key on air-gapped hardware. Julia Social has no access to the Escrow Server or the encrypted data, enforced by contract. The Escrow Server never writes cleartext identity data to persistent storage. Julia Social then creates a new root DID on the Chia blockchain, associates it with the new person at the Escrow Server, and returns it to the app. The app creates an initial alias with a full set of credentials, and the user sets a recovery password. A known hash means a returning person. The app offers the recovery flow, the path for a user who lost their device and needs to move onto a new one. [Recovery (Doc #6D)](https://not.bot/technology/recovery/) covers that sequence. Duplicate detection runs on personal-information fields, not on the passport number. A user who obtains a new passport after a legal name change presents fields that do not match the stored hash, so the system treats them as a new person. That user creates a new root DID and re-enrolls; the prior identity and its aliases, credentials, and signature history cannot be carried over. Julia Social plans to provide support for name changes and similar changes to a person's identity data in a future release. ### **Faucet-funded transactions** Creating the root DID is an on-chain operation, and so are alias creation, recovery, and rekey. Julia Social funds these through a faucet coin. Users never hold XCH and never pay a blockchain fee. A Julia DID cannot be melted; the root DID persists as the user's anchor. ### **What each party holds after enrollment** | Party | Holds | Can decrypt | |-------|-------|-------------| | Signicat | Nothing (deleted within seconds of the Escrow Server download) | n/a | | Praxis (Escrow Server) | Peppered duplicate-detection hash, anonymized MPC inputs, encrypted identity record | No | | Julia Social | The root DID | No (holds the record decryption key on air-gapped hardware, not the record) | | User's device | Root DID, private keys in the secure element | Yes (its own keys) | Julia Social never sees the passport data at any point in this flow. The [Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/) document specifies the full data flow and the architectural impossibilities it enforces. ## **What the verification levels attest to** A verification level is a claim about identity-proofing strength, issued as a distinct verifiable credential with its own URI. The levels do not gate other claims. Every enrolled user holds the same collection of presentable claims regardless of level: age thresholds, age brackets, personal-information fields, Site Pass, and account or domain names. The level tells a relying party how much confidence to place in the person behind those claims. **notbot0** (current state). The user scanned a government passport's NFC chip. Signicat validated the chip's digital signatures and confirmed the data against the ICAO Public Key Directory. Praxis confirmed the passport had not enrolled another not.bot identity. notbot0 includes no liveness check. notbot0 attests that an authentic, unexpired passport was present and unique, not that the person scanning it was the rightful holder. **notbot1** (planned). The user completed identity proofing at a contracted third-party enrollment partner: a bank, hospital, or enterprise that enrolls users into not.bot for its own purposes. The partner contract requires NIST SP 800-63A Identity Assurance Level 2 In-Person (IAL2) procedures, which add in-person proofing against the live person. Julia Social does not audit these partners. Enforcement is consequence-based: on suspicion of substantial fraudulent issuance, Julia Social melts the partner's issuer key singleton, which invalidates every credential that singleton signed in one on-chain transaction, and affected users re-enroll elsewhere. [Delegation and Organizational Identity (Doc #6C)](https://not.bot/technology/delegation/) covers the singleton mechanism. **notbot2** (planned). The user completed identity proofing at a first-party facility contracting with Julia Social to provide enrollment. The proofing process and facility design are not public at this stage. The levels are cumulative. A notbot1 holder also holds notbot0. A notbot2 holder holds all three. The [Roadmap (Doc #20)](https://not.bot/learn/roadmap/) tracks notbot1 and notbot2 as planned work. A verification level reflects a point-in-time check. Julia Social does no ongoing monitoring of the document a user enrolled with. If a passport is revoked inside the three-year window, for example when the holder naturalizes into another country, or if the holder's name, gender, or other passport data changes, Julia Social does not learn of it and makes no change to the credentials in the app. The passport must be unexpired at enrollment; expiration after enrollment has no effect on a not.bot identity. A user whose passport data has changed can re-enroll with the new document, which the system treats as a new person. ## **The relying-party perspective** A relying party requests the lowest level its use case needs. Requesting a higher level than the situation calls for shrinks the pool of users who can respond, since most enrolled users hold notbot0 alone. Most relying parties request notbot0. The user presents the claim or claims the relying party requested, and the default is to present only what was asked. A user can volunteer additional claims, but a relying party should neither expect nor require that. The response carries the claim property URI and an encoded value. A relying party does not learn the user's maximum verification level unless the user volunteers it: a notbot2 holder can answer a notbot0 request with a notbot0 response and reveal nothing higher. A relying party reads two separate things from a presentation: the verification level, which says how the person was proofed, and the claim itself, which says what the proofed data shows. The two do not interact. The level is the relying party's measure of confidence in the person behind the claim, whatever the claim happens to be. The personal-information credentials, first name, family name, gender, and nationality, are issued from the passport at enrollment and expire three years later. They state what the passport showed on the day the user enrolled. [Credentials (Doc #6B)](https://not.bot/technology/credentials/) specifies the full claims catalog, how a user enables or disables each credential per alias, and why the same value on two aliases cannot be correlated. The birthdate-related credentials, the birthdate, its components, exact age, age thresholds, and age brackets, are computed through a three-party MPC among the not.bot app, Julia Social, and Praxis (the independent escrow agent that operates the Escrow Server), in which neither Julia Social nor Praxis learns the birthdate. Each carries a validity window of one calendar month: Valid-From is the first of the month, and Valid-To is the last day. The app requests fresh credentials for an alias whenever a presentation needs them and it does not already have them. The user can refresh them by hand with a button in the app. When the user crosses an age threshold and needs to present updated age credentials, the app requests new credentials that reflect the new age. Every request produces credentials with a new encoding, so neither Julia Social nor Praxis can tell from two requests in the same month that the user crossed a threshold between them. All birthdate-related credentials refresh together, and every threshold and bracket is issued each time, including the ones that do not apply to the user, so the set of credentials requested never reveals which ones apply. [Human Verification (Doc #3)](https://not.bot/learn/human-verification/) covers how a relying party requests and consumes these through not.bot Verify. --- > **Cryptographic Foundations** — https://not.bot/technology/cryptographic-foundations/ · Markdown: https://not.bot/technology/cryptographic-foundations.md · Updated 2026-06-10 # **Cryptographic Foundations** This document collects the cryptography that not.bot™ depends on into one place: the BLS12-381 signature scheme and its aggregation property, multiparty computation at the level of what each protocol guarantees, key management on the user's device, revocation bitfields, faucet coins, and dummy transactions. It explains why each primitive was chosen and what property it provides. The protocol structures these primitives sit inside are covered in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**, and the shipped Chialisp puzzle set is documented in **[Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/)**. This document does not repeat the protocol tables or code-level constants from those documents. --- ## **BLS12-381 and signature aggregation** `did:julia` uses BLS signatures on the BLS12-381 curve for every signature in the system: DID authentication, credential claims, message signing, and asset control. The choice of curve is a hard requirement for two reasons that point the same way: BLS12-381 is the native signature scheme of the Chia blockchain, and signature aggregation is the property the credential model depends on. BLS signatures have a property no other scheme in common use provides at this level: any number of signatures, from any number of independent signers, combine into one fixed-size signature. The combination is non-interactive. The signers do not coordinate, do not exchange messages, and do not need to know about each other. A verifier checks one aggregate signature and learns that every underlying signature is valid. A 96-byte BLS signature stays 96 bytes whether it represents one signer or fifty. A complete did:julia signature runs larger than a bare BLS signature, because it is not a bare BLS signature. It is the signer's whole identity acting. The signed object carries the embedded DID, so a recipient reads the signer's identity from the signature with no PKI lookup, and it carries the structured contents the identity signed rather than the curve point alone. A raw BLS12-381 curve point is 96 bytes; a whole-identity signature runs to roughly 3.5 kilobytes uncompressed, near 2 kilobytes compressed. The protocol structure of the signed object is in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. ### **The Chia substrate uses it natively** BLS12-381 is the signature scheme Chia uses for every coin. A coin spend is authorized by a BLS signature that the consensus rules check at low cost, so a `did:julia` identity, built from Chia coins, uses BLS for on-chain authorization. This reaches credentials, not only coin control: a credential claim presented on-chain is verified inside Chialisp, which has a native operator for BLS signatures. BLS was a key reason Julia Social selected Chia: the curve the identity system needs is the curve the chain already verifies. The next section gives the second reason, which holds even apart from on-chain cost. ### **Why claim composition needs it** The second reason, the one no alternative curve could meet, is credential-claim composition. A not.bot presentation can carry claims from many independent issuers at once: a not.bot credential from Julia Social, an age credential, a professional license from a licensing board, an employment credential from an employer. Each issuer signed its own claim with its own key, at its own time, with no knowledge of the others. A normal presentation carries a few claims, so the saving in verification work and in signature size is slight. Aggregating those claims into one signature provides atomicity. The presenter's authentication signature and every claim's issuer signature combine into a single signature over the whole presentation. The verifier receives an all-or-nothing unit: it can confirm the bundle, but it cannot separate out one claim's signature and keep it. A verifier cannot disaggregate a presentation to lift a subset of claims and reuse them for another purpose, and a party that collects presentations cannot build a stockpile of reusable credentials. The one route that could undo this, a signature-subtraction attack, is closed by a required nonce, described under Nonce protection and signature subtraction below. Composition is the requirement that singles out BLS. Coin ownership and multisig authorization also benefit from aggregation, but they could be served by other constructions. Claim composition across uncoordinated issuers cannot: the alternatives are either interactive, like Schnorr multisig, or never reach constant size, like the research-stage half-aggregation of Schnorr and EdDSA. The protocol-level treatment is in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**, and the public positioning argument is in **[Why Chia? (Doc #10)](https://not.bot/technology/why-chia/)**. ### **The BLS-only constraint** `did:julia` supports BLS12-381 keys and no others. It does not support P-256, secp256k1, Ed25519, or passkey keys at the identity layer. None of those provides the constant-size non-interactive aggregation claim composition needs. Julia Social accepts the constraint because the capability it buys is structural to the rest of the system. --- ## **Key management** A not.bot identity is controlled by a BLS12-381 key (and derivations) held on the user's device. The not.bot app stores aliases, credentials, contacts, private keys, and the encrypted recovery bundle in an encrypted database. The database encryption key sits in the device's secure element: the iOS Secure Enclave or an equivalent Android TEE. The secure element is tamper-resistant hardware designed to keep a key from being extracted even when the operating system is compromised. The BLS signing keys live inside the encrypted database, not inside the secure element. No shipping secure-enclave or TEE hardware supports the BLS12-381 key type that Chia uses, so the keys cannot be sealed in hardware the way an Ed25519 key could be. The secure element protects the database encryption key, which gives defense in depth, and the BLS keys remain accessible to the app software when the database is open. The app does not allow enrollment on an Android device that lacks hardware-backed key storage. Every signing operation requires biometric authentication or the device passcode. A signature is produced when a human present at the device authorizes it, not when software decides to. Key rotation, recovery, and pre-rotated keys are the mechanisms that protect against key loss and compromise; **[Recovery (Doc #6D)](https://not.bot/technology/recovery/)** covers them from the user's side and **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)** covers the on-chain mechanics. --- ## **Multiparty computation** Julia Social credentials must be computed by two or more parties together, in a way that produces a correct, signed result without any single party learning the inputs that went into it. not.bot uses multiparty computation (MPC) for this. An MPC is a protocol in which multiple parties compute a function together over their private inputs and learn only the output. This holds for every credential Julia Social issues. Even the personal-information credentials taken from a passport, the user's name, gender, and nationality, are produced this way, so Julia Social signs them without seeing their values. The subsections below cover the cases where the computation does more than sign a value blind. This document describes what each MPC accomplishes and what it guarantees. It does not describe the protocol internals, the circuits, or the constructions. ### **The not.bot ID** Every alias holds a not.bot credential proving it belongs to a verified human. The credential carries a not.bot ID, computed through an MPC between Julia Social and the user's app. Neither party can predict or steer the value. Julia Social receives the not.bot ID to construct and sign the credential, and the value cannot be connected back to the user's passport data. The not.bot ID later supports law enforcement identification when a valid demand exists; **[Law Enforcement and Accountability (Doc #9)](https://not.bot/technology/law-enforcement/)** describes that path. ### **Age credentials** Age credentials state a user's exact age, age-over thresholds such as over-18 and over-21, and age brackets. Julia Social must sign these without learning the user's age or birthdate. A three-party MPC among the not.bot app, Julia Social, and the Escrow Server (operated by Praxis, the independent escrow agent) produces age credentials with the right values, signed by Julia Social, without Julia Social or the Escrow Server learning the birthdate. As a user crosses into a new threshold or bracket, fresh credentials reflect the change without Julia Social or the Escrow Server learning that the crossing happened. Age credentials expire monthly and refresh through the same protocol. ### **Site Pass** A Site Pass is a pairwise identifier unique to one human-site combination. The same human at the same site produces the same Site Pass regardless of which alias is used, which gives a site sybil resistance: it can recognize one human behind two aliases without learning anything else. Site Passes for different sites are cryptographically unlinkable, even if those sites collude. Site Pass computation runs an MPC with three participants: the user's app, the site's not.bot Verify instance, and Julia Social. Julia Social and the site never interact while executing the protocol, so Julia Social cannot learn which site a user is creating a Site Pass with. ### **DID-holder uniqueness for servers** A user's device proves it is the sole holder of its keys through the secure element. A server cannot rely on that hardware. not.bot Verify establishes single-holder control of its DID through an MPC that runs during each interaction. Possessing a copy of the key material is not enough: a second server instance running the same keys cannot stand in as the legitimate holder, because the protocol detects the conflict. This is the same process-binding guarantee that honest.bot™ provides for AI agents, where identity binds to a running process rather than to a key. honest.bot is a roadmap product (targeted for Q4 2026); the underlying MPC runs in production today inside not.bot Verify. **[honest.bot Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/)** covers the agent model. ### **Entropy in credential data** Many credential values carry little information on their own. An over-18 credential is one of two values, true or false. Even a first or family name holds negligible entropy in cryptographic terms. A credential whose form depended on its value alone would be open to frequency analysis: an observer comparing credentials could infer the value, or match two credentials that carry the same value. Every credential incorporates entropy from a cryptographically secure source, so two credentials over the same value never share a form, and no frequency or entropy analysis can recover the value or link the credentials. The architectural privacy claim across all of this holds: Julia Social cannot access user identity data. The MPC guarantees enforce it by construction, not by promise. --- ## **Revocation bitfields** An issuer needs to revoke individual credentials without contacting every verifier and without revealing which credential was revoked. `did:julia` records revocation in a Merkleized bitfield carried in the issuer key singleton. Each issued credential maps to a position in the field. A set bit marks a credential as revoked, and a verifier checks the bit during presentation. The bitfield is Merkleized so an update touches one on-chain transaction and a verifier can prove the state of one position without holding the whole field. The issuer key holder can update revocation on its own, or the issuer DID can command an update. A coarser control exists alongside it: melting an issuer key invalidates every credential that key ever signed at once. The exact bitfield sizes and update mode numbers are code-level details and live only in **[Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/)**; the credential-side treatment of cascade revocation is in **[Credentials, Presentations, and Selective Disclosure (Doc #6B)](https://not.bot/technology/credentials/)**. The position an issuer assigns within the bitfield is a privacy property. Each credential claim takes one index in the issuer's on-chain field, and the field is public. An issuer that hands out indices in issuance order writes that order onto the chain: a reader who compares two credential claims learns which was issued first. An issuer assigns indices so they do not track issuance order, for example by drawing each index at random across the field, which keeps issuance order and volume off the chain. This is the mechanism. The issuer-facing rule for assigning indices is in **[Credentials, Presentations, and Selective Disclosure (Doc #6B)](https://not.bot/technology/credentials/)**. --- ## **Faucet coins** Creating and operating a Julia DID requires small amounts of XCH to fund coins and pay blockchain fees. A user never holds XCH. The faucet supplies the value through a construction that the user cannot divert and a tax authority cannot treat as the user receiving cryptocurrency. Julia Social mints batches of faucet coins. To fund a user operation, Julia Social signs a faucet coin spend with a concurrent-spend assertion that references the user's coin, producing an incomplete spend bundle. The user's spend asserts back at the faucet coin. Neither spend can confirm without the other, so the faucet coin cannot be redirected to any other purpose. A RESERVE_FEE condition pins the value to the blockchain fee. The user never holds, receives, or accounts for XCH. The protocol-level description is in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. --- ## **Dummy transactions** A public blockchain records the timing and structure of every transaction. Without protection, several alias DIDs rekeying in the same block would form a distinctive on-chain pattern that ties them to one person. Julia Social defeats that correlation with decoys. Julia Social operates a service that submits faucet-funded spends performing DID creation, rekey, and recovery operations. The decoys match the structure of real user transactions, and an outside observer cannot tell a decoy from a real operation. The added noise frustrates timing analysis, clustering, and identity correlation. The formal observer-protection assertions are in **[Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/)**. --- ## **Nonce protection and signature subtraction** Signature aggregation introduces an attack worth guarding against. An attacker who holds an aggregate signature and one of its component signatures could subtract the component out and recover a reusable signature over the remaining part of the message. This is a signature-subtraction attack, and it would let an attacker lift a single claim out of a presentation and replay it elsewhere. `did:julia` prevents signature subtraction with nonces. Credential and message presentations include a nonce announcement that binds the aggregate signature to that specific presentation. A signature carrying a presentation-bound nonce cannot be disaggregated into a clean signature over a single claim, so a component cannot be extracted and reused. Receiving a holder presentation does not let the recipient re-present the underlying claim as their own. The protocol structure for nonces is in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. --- ## **Self-certifying identifiers** A Julia DID is a cryptographic commitment to the key that created it. The prelauncher coin embeds the original BLS public key, so the launcher ID that serves as the DID identifier commits to that key. Because every state change is a recorded spend, a DID's full key history verifies from genesis. This makes a DID self-certifying. A verifier can confirm, with no prior record of the DID and no blockchain access at presentation time, that the DID was created with a specific key, that the current key is the legitimate successor, and that the presenter controls it. The presenter reveals the original key and every spend that changed the DID, with one aggregated BLS signature covering them all. An offline verifier holding only a snapshot of an issuer's signing keys and revocation bitfields can then check a credential from a DID it has never seen. The protocol-level treatment of self-certifying lineage and offline verification is in **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. --- ## **Related documents** - **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. Protocol structure for every primitive on this page. - **[Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/)**. Code-level constants, including bitfield sizes and mode numbers. - **[Why Chia? (Doc #10)](https://not.bot/technology/why-chia/)**. The public case for the BLS aggregation and blockchain choice. - **[Privacy Architecture (Doc #7)](https://not.bot/technology/privacy/)**. The formal privacy assertions, including observer protection. - **[Credentials, Presentations, and Selective Disclosure (Doc #6B)](https://not.bot/technology/credentials/)**. The credential and revocation model. - **[Recovery (Doc #6D)](https://not.bot/technology/recovery/)**. Key rotation, recovery, and pre-rotated keys. - **[honest.bot Verifiable Agent Identity (Doc #4)](https://not.bot/learn/honest-bot/)**. The process-binding MPC for AI agents. --- > **System Architecture and Degraded-Mode Operation** — https://not.bot/technology/system-architecture/ · Markdown: https://not.bot/technology/system-architecture.md · Updated 2026-06-17 # **System Architecture and Degraded-Mode Operation** This document maps the components of the not.bot™ system, the trust boundaries between them, and what each component can and cannot reach. It then states what continues to work when any one component fails. The organizing fact is a split between two kinds of dependency. Administrative operations (enrollment, recovery, alias creation, credential issuance) need Julia Social and the Recovery Server. The operations users perform most, signing and verifying content, need neither. They run against the Chia blockchain and nothing else. This split is the resilience argument. An enterprise evaluating not.bot for production asks what breaks when the vendor's servers go down. For signing and verification, the answer is nothing. A signature created last year verifies today whether or not Julia Social is available. For the data each party holds and cannot access, see the [Privacy Architecture](https://not.bot/technology/privacy/) document. For the security guarantees behind each component, see the [Security Model and Known Weaknesses](https://not.bot/technology/security/) document. ## **Components** The system distributes work across independent parties. Each runs its own infrastructure and holds a different slice of the system's state. **The not.bot app** runs on the user's iOS or Android device. It stores the user's cryptographic keys, aliases, credentials, and contacts in an encrypted database whose key sits in the device's secure element. The app creates signatures, scans and verifies signatures, presents credentials to sites, and reaches Julia Social for administrative operations. **Julia Social** operates not.bot. It issues credentials and runs the credential-issuance infrastructure, hosts QR signature payloads, runs the faucet that funds users' on-chain operations, mediates the reserved-names registry (the interim service until on-chain Julia Vanity Names ship), manages subscriptions, operates the decoy-transaction service that protects on-chain privacy, and serves administrative requests from the app. Julia Social holds as little user data as possible and never receives any user-identifying data. **The Recovery Server** stores each user's encrypted recovery bundle and authorizes recoveries. Julia Social operates the only Recovery Server today. The app contacts it for recovery support and multi-device coordination, never for signing or verification. **The Escrow Server** is software Julia Social wrote and Praxis, the independent escrow agent, operates on Praxis infrastructure. It processes passport data into credential inputs at enrollment and participates in the multiparty computations that produce credentials. It is an enrollment-time and credential-issuance participant, not a runtime one. **Signicat** validates passport data during enrollment and recovery. It holds passport data for seconds in normal operation and is reachable only during those two flows. **Chia blockchain nodes** hold the canonical record of DID state, key history, and credential revocation. The app reads this record to create and verify signatures. The app reaches nodes in one of three modes (see Blockchain Access below). **not.bot Verify** is server software a business runs inside its own infrastructure to request and verify credentials from not.bot users. A Verify deployment runs its own Chia nodes and its own key store. The user's app talks to the business's Verify servers, never to Julia Social, during a verification. **not.bot Sign My Work** is a web tool for signing content at volume, targeted for release at the end of June 2026 (future state). Signing through Sign My Work still requires the not.bot app on the signer's phone to authorize each signature. ## **Trust boundaries** Three boundaries shape what any party can observe. The **device boundary** holds the user's keys. The signing keys never leave the app's encrypted database, and the database key never leaves the secure element. No server, including Julia Social, holds a user's signing key. The **escrow boundary** separates the encrypted identity record from its decryption key. Praxis holds the encrypted records and cannot decrypt them. Julia Social holds the decryption key on air-gapped hardware and does not hold the records. Reading any user's identity requires crossing both sides of this boundary plus a per-record brute-force step. By contract, Praxis cannot release encrypted records to Julia Social without a valid law enforcement demand, even after the contract between them ends: at termination the records may move only to a successor escrow agent bound by the same restrictions, never back to Julia Social, and Praxis must delete them if no successor is named within 90 days. The [Privacy Architecture](https://not.bot/technology/privacy/) document states these contractual controls. The **deployment boundary** isolates each not.bot Verify instance. A business's Verify servers, key store, and Chia nodes run inside the business's own infrastructure. Julia Social has no path into a running deployment and no visibility into which users a business verifies or when. Once enrollment completes, only one component can reach decrypted user data on its own: the user's device. The app holds both the encrypted database and, in the secure element, the key that opens it. No server holds both halves. Praxis holds encrypted identity records without the decryption key, Julia Social holds that key without the records, and the Recovery Server holds an encrypted recovery bundle it cannot read. The only other party that ever sees cleartext is a verifier the user chooses to share with, and then only the specific claims the user releases. ## **Administrative-time dependencies versus runtime dependencies** The app contacts Julia Social for administrative operations only: enrollment, rekey, recovery initiate and cancel, alias creation, reserved-name requests, Verified Signer credential requests, and QR signature payload upload and download. The app contacts the Recovery Server for multi-device coordination: contacts, alias settings, network settings, password changes, and adding or resetting devices. Every on-chain operation also draws a faucet coin from Julia Social, since users hold no XCH and cannot pay a blockchain fee. For some operations that funding is the only thing Julia Social provides. For example, a rekey is built and signed on the user's device and executed on chain; the app reaches Julia Social only for the faucet coin, not to authorize the change. None of these operations happen during signing or verification. Signing and verifying content reach neither Julia Social, the Escrow Server nor the Recovery Server. The app signs with on-device keys and verifies against on-chain data from blockchain nodes. The only runtime dependency for these operations is blockchain access, and that access runs by default against a pool of public nodes with no Julia Social involvement. A user signs and verifies content many times. A user enrolls once, and recovery is a rare event. The system places its server dependencies on the rare operations and keeps the common ones independent. ## **Blockchain access** The app needs blockchain data to create and verify signatures: DID status, key history, and revocation state. It reaches the chain in one of three modes. | Mode | Description | Default | |------|-------------|---------| | Random public nodes | The app opens connections to multiple nodes at startup, queries connected nodes when it needs chain state, and opens more connections on demand. | Yes | | Julia Social and Galactechs public node | A specific public node Julia Social and Galactechs operate. | No | | User-specified node | A node address the user configures, including a node the user runs. | No | The default mode reaches no Julia Social infrastructure. The Chia network includes about 30,000 nodes, so a pool of 30 or more connections with on-demand fallback stays available under adverse conditions. A user who runs their own node removes every shared dependency from signing and verification. A not.bot Verify deployment does not use these modes. The deployment runs its own Chia nodes, at least one with three recommended, inside the business's infrastructure. ## **QR and JAB code resilience** Signatures come in two visual formats with different dependency profiles. A **JAB code** embeds the complete signature data in the image. Creating and scanning a JAB code signature reaches no server. A JAB code verifies in any network condition, which is what lets it survive screenshots, forwarding, and re-encoding. A **QR code** embeds a URL, a hash, and a decryption key. Julia Social hosts the full payload at that URL. A verifier scanning a QR code fetches the payload from Julia Social, then uses the hash and key to confirm and decrypt it. If Julia Social is unreachable, the verifier cannot retrieve the payload and QR verification fails. The tradeoff is size: QR codes take much less visual space and carry a server dependency for retrieval; JAB codes take more space and carry none. The QR dependency does not apply to not.bot Verify. A Verify deployment serves verification data from its own infrastructure. ## **Offline and in-person verification today** A buyer evaluating not.bot for a door, a gate, or a checkout lane asks what verifies with no network today. The answer depends on the format and on how deep the check goes. A JAB code carries its full signature in the image, so confirming the embedded content and its signature needs no network. Confirming the signer's current key state and revocation, the full chain of trust, needs the chain or a snapshot of issuer state. A JAB scan with no signal confirms that the content matches its embedded signature; it cannot confirm that the signing key was not rotated or revoked after the signature was made. A not.bot Verify deployment verifies against its own Chia nodes inside the business's infrastructure. It needs those nodes synced and reaches no Julia Social server, so it runs through a Julia Social outage. It is an online verifier against its own chain access, not a no-network one. The did:julia protocol supports fully offline verification against a snapshot. A verifier holding a snapshot of the relevant issuer state, the issuer DIDs, their active signing keys, and current revocation records, can verify a credential from a holder it has never seen, with no network. The [Credentials, Presentations, and Selective Disclosure](https://not.bot/technology/credentials/) document describes this mode. The app code that exposes it for in-person signing and verification has not shipped; the [Roadmap](https://not.bot/learn/roadmap/) tracks it, along with removing the chain check that signature creation performs today. Today: offline JAB content verification ships, online verification against the chain through Verify or the app ships and needs no Julia Social, and the fully offline snapshot mode is a protocol capability a later app release will expose. ## **Degraded-mode behavior by component** The following states what stops and what continues when each component is unreachable. **Julia Social administrative services down.** Signing continues, using on-device keys and the blockchain. JAB verification continues. QR verification stops, because the payload lives at Julia Social. App-to-Verify interaction continues, because Verify runs independent of Julia Social for any outage shorter than the once-a-month billing connection it requires (see not.bot Verify resilience). Enrollment, rekey, recovery, alias creation, and credential issuance stop until service returns. **Recovery Server down.** Signing and both forms of verification continue. App-to-Verify interaction continues. Multi-device operations stop. Recovery initiate and cancel stop, because they need both the Recovery Server and Julia Social. **Escrow Server or Signicat down.** New enrollments and recoveries stop, since both flows process passport data. Existing identities sign and verify without interruption, because neither component sits in the signing or verification path. Age-credential refresh, a three-party computation among the not.bot app, Julia Social, and the Escrow Server, pauses until the Escrow Server returns. **Blockchain nodes unreachable.** Signature creation stops, because the app checks the chain during signing today. Removing that check is a roadmap item. JAB verification continues, since the signature data is already embedded; full chain-of-trust verification against current key and revocation state needs the chain. The default pool of 30 or more connections makes total unreachability unlikely. Enrollment and recovery need Julia Social regardless of node state. **A not.bot Verify deployment's Chia nodes down.** That deployment cannot process verifications, because Verify checks revocation against its own synchronized nodes and accepts no credential verified against an out-of-sync node. The business runs three nodes to keep this from happening. A failure here is contained to that one deployment and affects no other business and no app-side signing or verification. **The user's device lost.** Signing and verifying from that device stop. The identity survives. The user recovers it on a new device with their recovery password and passport, since the DID, aliases, and key history persist on the blockchain. Recovery is an administrative operation and needs Julia Social and the Recovery Server. The pattern across these states: every failure of a Julia Social component leaves signing and JAB verification intact. The one runtime dependency that can stop signing is the blockchain itself, and the default access mode spreads that dependency across thousands of independent nodes. ## **not.bot Verify resilience** A not.bot Verify deployment is built for production uptime and keeps serving verifications through Julia Social outages. Julia Social sits off the verification path, and a deployment reaches it at two points, neither during a verification. A signature server acquires its honest.bot™ credential when it starts up. The deployment also attempts an hourly connection to Julia Social to report billing statistics, and a missed attempt does not interrupt verification. The one limit is billing: a deployment must reach Julia Social at least once a month to keep operating, so verification continues through any Julia Social outage shorter than a month. A deployment runs four components inside the business's Kubernetes cluster. OpenBao holds every DID's BLS12-381 private key and signs through that store, so no key leaves the cluster. The admin service manages the signature-DID pool and operates on the business's internal network with no public path. Signature servers run behind an internal load balancer with no public path, each holding one signature DID and serving user verification requests through the business's SDK adapter. Chia nodes follow the chain for the admin service and the signature servers. The deployment relies on two services the business provides, PostgreSQL for application data and Keycloak for operator login, neither part of not.bot Verify. During a verification, traffic flows from the user's phone to the business's SDK adapter to the business's signature servers. No packets reach Julia Social. The full exchange stays inside the business's infrastructure and the user's device. The internal verification reference is the [not.bot Verify: Julia Web SDK Reference](https://not.bot/technology/web-sdk/). ## **not.bot Sign My Work (future state)** not.bot Sign My Work, targeted for the end of June 2026, signs content from a browser at volume for newsrooms, brands, and public figures. The signatures still originate on the signer's phone: Sign My Work drives the workflow, and the not.bot app authorizes each signature, so a verified human stands behind every signed item regardless of volume. Sign My Work hosts an encrypted known-good copy of each signed item. The decryption key is embedded in the signature, and Sign My Work does not hold it, so Sign My Work cannot read the content it stores. A verifier who finds the content in the wild compares it against the stored original. Treatment here stays brief because Sign My Work has not shipped; the [Roadmap](https://not.bot/learn/roadmap/) covers it in full. ## **Why this architecture** A vendor that holds the keys to your continued operation is a single point of failure. not.bot removes Julia Social from the operations that matter most. A user signs and verifies content against the blockchain, with keys that never leave their device, and a business verifies humans inside its own infrastructure against its own nodes. Julia Social's servers carry enrollment, recovery, and credential issuance, the once-or-rare operations, and their outage leaves daily signing and verification untouched. The same separation bounds the blast radius of a compromise. A Julia Social breach exposes no signing key and no decryptable identity record, and it cannot stop a JAB code from verifying. A Verify deployment failure stays inside one business. A lost device strands no identity, because the identity lives on a public chain and recovers onto new hardware. For the security properties behind these claims, see the [Security Model and Known Weaknesses](https://not.bot/technology/security/) document. For the data-access boundaries, see the [Privacy Architecture](https://not.bot/technology/privacy/) document. ## **Related documents** - **[Privacy Architecture](https://not.bot/technology/privacy/):** the parties and what each can and cannot access. - **[Security Model and Known Weaknesses](https://not.bot/technology/security/):** authenticity, integrity, availability, and the known gaps. - **[The not.bot App](https://not.bot/learn/the-app/):** the app whose connections this document maps. - **[Human Verification and not.bot Verify](https://not.bot/learn/human-verification/):** the Verify product and its deployment model. - **[Why Chia?](https://not.bot/technology/why-chia/):** the blockchain that signing and verification depend on. - **[did:julia Technical Specification](https://not.bot/technology/did-julia-specification/):** the protocol behind on-chain DID state and self-certifying verification. - **[Roadmap](https://not.bot/learn/roadmap/):** not.bot Sign My Work, offline signing, and removing the blockchain check from signature creation. --- > **did:julia Technical Specification** — https://not.bot/technology/did-julia-specification/ · Markdown: https://not.bot/technology/did-julia-specification.md · Updated 2026-06-11 # did:julia Technical Specification This document describes the `did:julia` protocol at the design level: singleton structure, state model, transaction families, message model, presentation modes, and security properties. The companion code-level reference is **[Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/)**, which documents the shipped Chialisp puzzle set. --- ## 1. Scope `did:julia` is a DID method implemented on Chia using singleton coins and Chialisp puzzles. A Julia DID is a long-lived on-chain identity whose stable identifier is a singleton launcher ID. Authentication configuration, recovery configuration, custody configuration, and DID Document location are carried forward as state in each singleton generation. The protocol supports: - single-key and multi-key ownership - multi-class multisig for organizational governance - DIDs custodied by a separate DID - routine rekeying - time-locked recovery - pre-rotated-key recovery - DID-controlled asset coins - delegated credential issuance - subject and holder credential presentation modes - delegated credential presentation - DID-signed message announcements - DID Document pointer announcements - off-chain verifiable presentations that cannot be submitted on-chain - faucet-funded user operation without requiring users to hold XCH --- ## 2. Chia Execution Model Every Chia coin has a puzzle and a solution. Spending the coin evaluates the puzzle with the solution and produces conditions. The blockchain does not store conditions; a verifier replays the spend to derive them. The protocol rests on three Chia mechanisms: - **Singletons:** A singleton coin has a permanent launcher ID and one live generation at a time. The launcher ID becomes the stable DID identifier. - **Announcements and messages:** Puzzle announcements support block-scoped attestations; `SEND_MESSAGE` / `RECEIVE_MESSAGE` support spend-bundle-scoped coordination between coins. - **BLS signature aggregation:** `did:julia` uses BLS12-381 signatures throughout. Any number of signatures from any number of signers aggregate into one fixed-size signature, with no coordination between the signers. A verifier checks one aggregate signature per spend bundle no matter how many signers it represents. The DID state is represented as curried data. A spend that changes state creates the next singleton generation with a different puzzle hash. A spend that does not change state can remain compatible with concurrent spends because its puzzle hash remains the same. --- ## 3. DID Singleton Model ### 3.1 Identifier The DID identifier is the singleton launcher ID of the Julia DID coin. The launcher ID remains stable while the singleton coin is recreated across generations. ### 3.2 State The DID singleton carries the following logical state: | Field | Purpose | |-------|---------| | DID puzzle hash | Identifies the DID method puzzle | | DID launcher ID | Stable DID identifier | | Recovery status | Indicates no recovery or active pending recovery | | Authentication configuration | Key Merkle tree, class structure, and quorum requirements | | Custodian DIDs | DIDs authorized to control this DID through custody | | Recovery configuration | Recovery participants, quorum rules, delay, and prerotation data | | DID Document pointer | DataLayer singleton launcher ID for the DID Document | | Pending recovery parameters | New authentication, custodian, and recovery values committed during active recovery | The shipped code represents this state as a Chialisp list and commits to it with `sha256tree`. Doc #19 gives the exact current field ordering. ### 3.3 Genesis and Lineage `did:julia` uses a prelauncher before the standard singleton launcher. The prelauncher embeds a BLS public key, making the Julia DID launcher ID a commitment to the original key used to create the DID. Because the launcher ID commits to the original key and every state change is a recorded spend, a DID's full key history is verifiable from genesis. Section 14 describes the fully offline presentations this enables. ### 3.4 Permanence A Julia DID cannot be melted. The launcher ID is permanent. An owner can brick a DID, removing all keys, recovery agents, and custodians, but the singleton and its history remain on chain. Melt is excluded by design. A melt is permanent: if a malicious recovery took temporary control of a DID, the attacker could melt it and leave the owner nothing to recover. A brick request gets no such shortcut, and recovery agents asked to brick a DID will ask a lot of questions first. --- ## 4. Fast-Forward Compatibility Many identity operations do not change DID state. `did:julia` is designed so those operations can remain valid even if another spend of the same DID is confirmed first, as long as the state is unchanged. The design avoids parent-specific authorization in regular DID spends: - It uses `ASSERT_MY_PUZZLEHASH` rather than asserting the specific parent coin ID. - It uses `AGG_SIG_PUZZLE` for DID-owner authorization rather than coin-ID-bound signatures. - It binds authorization to the puzzle hash, which commits to the current DID state. If a spend changes state, the next singleton generation has a different puzzle hash, and old spend bundles tied to the old state no longer apply. If the state does not change, multiple spend bundles can target the same logical DID generation, and the first to confirm does not invalidate the rest. --- ## 5. Authentication Model `did:julia` supports three normal authentication modes. ### 5.1 Single-Key Authentication A single signer proves membership in the DID's authentication key tree. The DID configuration must require one class and no more, and the selected class must require one member and no more. The signature is over the tree hash of the operation solution, binding the signer to the specific operation being authorized. ### 5.2 Multi-Key and Multi-Class Authentication Multi-class multisig allows both threshold-style and organizational governance arrangements. Keys are leaves in a Merkle tree. Internal nodes at a configured depth represent classes, and each class can require a specified number of members. Validation checks: - each participant's Merkle path reaches the committed root - each participant belongs to a valid class - no key is counted twice - enough members satisfy enough required classes This supports configurations such as "two engineering keys and one executive key" rather than only flat M-of-N thresholds. The ownership models these modes serve are covered in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). ### 5.3 Custodied Authentication A DID can authorize one or more custodian DIDs. A custodied DID does not verify a direct BLS signature from the subject; instead it requires a spend-bundle message from an authorized custodian DID that commits to the requested operation. Custody is still DID-native: the custodian is identified by DID launcher ID, and the receiving DID verifies that the command came from the expected custodian DID puzzle hash. Every custodian action is attributable: the custodied DID's spend record identifies the commanding custodian DID. A custodian cannot rotate the owner's keys, cannot participate in recovery on behalf of the custodied identity, and cannot extend custodial control to a third identity. These restrictions preserve the owner's ultimate authority. Custody serves power-of-attorney and guardianship arrangements, commercial enterprise custody, and keyless DIDs for devices and physical assets; [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/) covers the use-case families. --- ## 6. Operation Routing The DID singleton delegates to an authentication entrypoint, and the authenticated path delegates to operation puzzles. In the shipped implementation, routing is enforced with embedded child puzzle hashes. At the protocol level, the important property is that a DID spend authorizes a bounded set of operation families rather than arbitrary code injection. Operation families include: - message signing - asset coin control - invalidation for off-chain presentations - DID Document announcement and update - guarded arbitrary condition passthrough - routine rekey - custodian command - issuer key launch and management - credential presentation - delegated credential presentation - recovery authorization Normal authentication operations are blocked while a time-locked recovery is active. Recovery cancellation and completion remain available through the recovery paths. Multiple compatible operations can combine in a single DID spend: one spend can sign a message, present credentials, control asset coins, and announce the DID Document pointer together. Operations that change DID state (rekey, recovery, DID Document pointer update) combine with announcements and passthrough but not with other state-changing operations. --- ## 7. Cross-Coin Communication `did:julia` uses a `JDID` namespace for protocol messages and announcements. At the protocol level there are two communication classes: - **Spend-bundle-scoped messages:** `SEND_MESSAGE` / `RECEIVE_MESSAGE` pairs require both participating coin spends to appear in the same spend bundle and to agree on message content. - **Block-scoped announcements:** `CREATE_PUZZLE_ANNOUNCEMENT` / `ASSERT_PUZZLE_ANNOUNCEMENT` pairs let one spend assert that another puzzle emitted a specific announcement in the same block. Message-style communication is used for command and control, such as DID-owned asset coins, custody, recovery participant authorization, issuer key launch, revocation updates, and issuer key melting. Announcement-style communication is used for attestations, such as credential presentation, holder/delegation proof, issuer key liveness, DID Document location, signed messages, timestamps, and nonces. The exact prefixes and mode values are code-version details. They are documented in Doc #19 where each shipped puzzle uses them. --- ## 8. DID-Owned and Credential-Controlled Coins ### 8.1 DID-Owned Coins A DID-owned coin can use a Julia DID inner puzzle. The coin spends when it receives a command from the owning DID that commits to the conditions it should emit. This allows the DID to control XCH, CATs, NFTs, DataLayer singletons, or other Chia assets without putting the full DID authentication logic inside every asset coin. Because ownership binds to the launcher ID rather than a key, rekey and recovery carry asset control with the identity. [Identity Architecture (6A)](https://not.bot/technology/identity-architecture/) covers DID asset ownership and the web front-end model it supports. ### 8.2 Credential-Controlled Coins A credential-controlled coin can be spendable by a party that presents a qualifying credential. The coin requires both: - proof that the spender's DID presented the required credential claim - a DID command authorizing the exact output conditions This supports pay-to-credential patterns: the control criterion is not a specific key but possession of a valid credential. Because the credential lifecycle governs access, granting and expiring spend rights are off-chain operations, and a revocation update cancels rights in batches with one on-chain transaction. The coin itself sees on-chain activity only when a right is exercised. [Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/) covers the pay-to-credential pattern, and [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/) gives a worked example with delegated agent access. --- ## 9. DID Documents A W3C DID Document is the resolvable description of a DID: verification methods, service endpoints, and other metadata, published in a DID-method-specific way and retrieved through a DID-method-specific resolver. The DID is distinct from its DID Document. The only required element of a DID Document is the DID value itself, which is implicit, so a `did:julia` DID is usable with no DID Document lookup at all. `did:julia` encodes DID Document contents as structured key-value pairs and publishes them through Chia DataLayer. The DID singleton state carries a pointer (a DataLayer singleton launcher ID) rather than the document contents. A DID can: - announce the current DID Document pointer during a spend - update the pointer as an authenticated state change The pointer mechanism is part of the shipped protocol. The publication path that writes DID Document contents to DataLayer and resolves them for readers is planned and not yet implemented. The DataLayer substrate itself is in production in the Chia ecosystem, so the remaining work is integration rather than new infrastructure. --- ## 10. Credentials and Issuer Keys Credential issuance is delegated to issuer key singletons. An issuer key singleton is tied to an issuer DID and contains: - issuer DID launcher ID - issuer key singleton launcher ID - BLS public key - revocation state - key validity window - maximum credential expiration - allowed credential property set - optional payment requirement for liveness presentation The issuer key singleton is also the protocol's issuance-delegation mechanism, the on-chain structure behind the issuer-delegation use cases in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). A DID launches an issuer key for its own signing operations or for a delegate, with the validity window, maximum credential expiration, and allowed property set bounding what the delegate can issue. The issuer DID keeps lifecycle control over keys it launched and can melt the key if needed, invalidating every credential that key ever signed. The issuer DID can also revoke individual credentials by ID. An issuer key can attest that it is live and unmelted. Credential presentation depends on this liveness check, so melting an issuer key invalidates the practical presentability of credentials signed by that key. The attestation spend is available to anyone, but requires a fee, set by the issuer. Revocation is represented by a Merkleized bitfield. An issuer key holder can update revocation on its own, or the issuer DID can command an update. The shipped Chialisp code defines the exact bitfield structure and update modes; see Doc #19. --- ## 11. Property Names and Value Encodings Every credential claim names one property and commits to one value. The property name is a URI of the form `encoding:authority/path`. The credential claim itself stores `sha2-256(property name)` rather than the cleartext name, and the claim value is reduced through the encoding pipeline to a 32-byte commitment. ### 11.1 Property Name Grammar A property name has three components, matched to URI structure: | Component | Role | Example | |-----------|------|---------| | Encoding | The value-encoding pipeline, left of `://` | `sha2-256\|CBOR` | | Authority | The DID whose namespace defines the property semantics | `.` or a base58 DID | | Path | The issuer's taxonomy for the property | `/v1/pii/age_range_18_20` | Examples of complete property names: - `cleartext://./.julia-payment` - `notbot://./v1/notbotN` - `sha2-256|CBOR://./v1/domain_name` The authority is the DID that defines the semantics of the property. When the authority is the issuing DID, `.` denotes it and the full DID is omitted; otherwise the authority is a DID encoded in base58 without the `did:julia` prefix. The path is the issuer's own taxonomy and carries the property's semantic identity, for example `/v1/pii/age_range_18_20`. ### 11.2 Property Name Hashing The cleartext property name is included in every presentation of the claim. The signed claim commits only to `sha2-256(property name)`. A verifier re-hashes the expected cleartext name and matches it against the hash in the claim. The chain does not reveal the cleartext property name. ### 11.3 Encoding Pipeline The encoding segment specifies the pipeline that reduces the cleartext value to the 32-byte claim value. Encodings compose with `|`, applied left to right: `sha2-256|CBOR` CBOR-encodes the value, then applies SHA2-256. A verifier reverses or replays the pipeline against the presented value and matches the result to the claim's value commitment. The encoding registry defines the following stages: | Encoding | Role | |----------|------| | cleartext | Identity. The value fits in 32 bytes and is not transformed. | | sha2-256 | Hash. Commits to value data that does not fit in 32 bytes. | | argon2id | Key-derivation function. Hardened commitment for low-entropy values. | | aes256gcm | Symmetric encryption. | | rsa3072 | Asymmetric encryption. Restricts decryption to a specific verifier. | | zip | Compression. | | CBOR | Serialization. dCBOR encoding of structured data. | Raw parameters for each stage, including the Argon2id memory, iteration, and parallelism constants, salt encoding, and AES and RSA nonce and fingerprint conventions, are specified in [Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/). ### 11.4 Reserved Namespaces The `julia` and `notbot` property prefixes are reserved for Julia Social. Decoding a value under a reserved prefix requires Julia Social software. --- ## 12. Credential Presentation A credential claim presentation validates: - the claim subject or holder mode - issuer DID - subject DID - issuer-delegated public key - delegate authorized to issue claim with this property - valid claim expiration date - valid claim inception date - non-revocation - antecedent requirements met - valid claim signature An antecedent requirement conditions one claim on another: the claim is valid for presentation only when its specified antecedent claims are presented with it. Antecedents are the mechanism behind cascade revocation and structural disclosure; the credential-level treatment is in [Credentials, Presentations, and Selective Disclosure (6B)](https://not.bot/technology/credentials/). A presentation can compose claims from any number of independent issuers. Each claim carries its issuer key's BLS signature, and in a spend bundle every required signature, the presenter's authentication and all of the claim signatures, verifies as one fixed-size aggregate. The verifier checks one signature no matter how many credentials the presentation contains, and no issuer coordinated with any other. This composition property is the reason `did:julia` requires BLS12-381; [Why Chia?](https://not.bot/technology/why-chia/) makes the public case. The presentation emits puzzle announcements that other spends can assert. ### 12.1 Subject and Holder Presentations A subject presentation says the presenting DID is the subject of the credential. A holder presentation says the presenting DID holds or relays the credential; the holder need not be the subject. ### 12.2 Delegated Presentations A delegatable claim can be passed through a chain of delegations. Each link must authorize the relevant claim for the next delegatee. The terminal delegatee then presents the claim as its own authority for the limited delegated purpose. Delegation allows organizations, representatives, agents, or systems to act under an authority first issued to another DID, while preserving an auditable chain back to the issuer and subject. Delegated presentation, and signing on another identity's behalf, has no separate on-chain mechanism: the authority travels as ordinary credentials. It therefore inherits the full credential lifecycle, including expiration, antecedent requirements, subdelegation through the standard chain, and revocation through the issuer key's revocation state. Mandate credentials, subdelegation, and worked examples (an AI travel-booking cascade, a structured mandate for a personal finance agent) are in [Delegation and Organizational Identity (6C)](https://not.bot/technology/delegation/). --- ## 13. Signed Messages A `did:julia` signature is the signer's entire identity acting, not a detached key. The signer's DID is embedded in the signature. A verifier resolves the signer from the signature itself against the chain, with no PKI, no certificate, and no external key directory. Whatever ownership model the identity defines, single-key, multi-key, or multi-class multisig, is the model that must be satisfied to produce the signature. ### 13.1 What a Signature Embeds A signature embeds the signer's DID and the signatures that satisfy the identity's ownership model, so the signature carries the signer's identity rather than a bare key. The signer also embeds a message, the content the signer attests to. A signature can embed two further elements: - a self-attested timestamp (optional; see 13.2); - a nonce, a number used once (optional). Each is embedded in the signature and cannot be separated from it, so a verifier cannot strip the timestamp or the nonce off the signature and cannot lift the signature onto other content. When the signer attests to structured content rather than a plain string, the signer encodes that content as the message using dCBOR, for example a document hash together with the metadata that scopes it. ### 13.2 Self-Attested Timestamp The timestamp is the signer's own clock. It is self-attested, not notarized and not supplied by a third party. A verifier weighs it as a trust property of the signer rather than as independent time. It is always UTC, so no timezone field is carried. ### 13.3 Extensibility A signature can embed elements beyond the message, timestamp, and nonce. Each additional element binds into the signature on the same terms, embedded and inseparable. ### 13.4 Embedded Request When a signature answers a request, the request travels inside the response. A not.bot Verify signature embeds a complete copy of the signed request that prompted it: the requesting server's DID, the server's domain-name credential, the nonce, and the claims the server asked for. The request is itself a signed message from the Verify server, so the response carries the server's own signature over its request. The embedded request binds on the same terms as every other element in section 13.1. A verifier cannot separate it from the response, and cannot move the response onto a different request. Reading the signature recovers both parties to the exchange: the human identity that produced the signature and the server identity that requested it, together with the claim set that server demanded. The embedded request is present in every Verify signature. No tooling extracts or displays it yet, so it is a latent property of the signature rather than an exposed feature. --- ## 14. Off-Chain Presentations `did:julia` supports spend bundles that prove DID control and credential possession without being intended for blockchain submission. ### 14.1 Invalidated Spend Bundles The invalidation operation adds an impossible condition, making the spend bundle fail if submitted on-chain. A verifier can still replay the spend bundle on its own machine to confirm that all signatures, assertions, credential proofs, and DID state commitments line up. Optional time-window assertions can bound the validity period of an off-chain presentation. This is the mechanism behind fully offline or online-off-chain verifiable presentations: the proof is a well-formed Chia spend bundle except for the deliberate invalidating condition. ### 14.2 Self-Certifying Lineage Proof The prelauncher's key commitment (section 3.3) makes a DID self-certifying: its full key history can be verified with no blockchain access. The presenter reveals the original BLS public key and every subsequent spend that mutated the DID, with one aggregated BLS signature covering them all. The presentation spend is the last spend in the chain. All prior spends are proof that the keys in the current version of the coin are the correct keys for the DID with that launcher ID; the presentation spend itself exercises those keys. A fully offline verifier walks the chain from the prelauncher forward and ends holding the DID's current state and the proof that the presenter controls it. A signed message or presentation stays verifiable after the signer rotates keys. Verification resolves the signer's lineage from the launcher commitment rather than from a current key, so a signature produced under a retired key still verifies against the DID it named. ### 14.3 Offline Credential Verification Verifiable credentials state claims by an issuer about a subject, and the subject is identified by DID. A verifier holding a recent snapshot of an issuer's credential-signing keys and revocation bitfields can verify a credential presentation from a DID it has never seen before, while fully offline. --- ## 15. Funding and Transaction Mechanics ### 15.1 Faucet Creating a DID requires small amounts of XCH to fund the prelauncher, launcher, and initial singleton coins, plus blockchain fees. The faucet mechanism supplies this without the user holding XCH. Julia Social mints batches of faucet coins. To fund a user operation, the service signs a faucet coin spend with a concurrent-spend assertion referencing the user's coin, producing an incomplete spend bundle. The user's spend asserts back at the faucet coin. Neither spend can confirm without the other, so the faucet coin cannot be diverted to any other purpose. The faucet coin uses RESERVE_FEE to ensure the value can only be used to pay the blockchain fee. The user never holds, receives, or accounts for XCH. ### 15.2 Transaction Rate Chia produces a transaction block about every 52 seconds, and a singleton can be spent at most once per transaction block. Fast-forward compatibility keeps this from becoming a bottleneck: any number of unchanged-state spend bundles can be submitted at the same time without coordination, and off-chain presentations never consume a blockchain spend, so they can be created in unlimited quantities. For on-chain operations, combining several operations in one spend (section 6) keeps the per-transaction-block limit from binding in practice. ### 15.3 Dummy Transactions Julia Social operates a decoy service that submits faucet-funded spends performing DID creation, rekey, and recovery operations. The decoys match the structure of real user transactions, and an outside observer cannot tell them apart. Their purpose is privacy: without decoys, several alias DIDs rekeying in the same block would form a distinctive on-chain pattern linking them to one identity. The decoys add noise that defeats timing analysis, clustering, and identity correlation. The formal observer-protection assertions live in [Privacy Architecture](https://not.bot/technology/privacy/). --- ## 16. Recovery `did:julia` supports three recovery-related flows. This section describes the on-chain mechanics; the user-facing recovery design is covered in [Recovery (6D)](https://not.bot/technology/recovery/). ### 16.1 Time-Locked Assisted Recovery Recovery participants are DIDs, not raw keys. A recovery configuration specifies participant classes and quorum requirements. To initiate recovery, the required participants authorize a proposed replacement state. Initiation commits pending replacement values and starts a delay. During the delay, normal authenticated operations are blocked. After the delay, anyone can complete the recovery, applying the pending replacement state. ### 16.2 Recovery Cancellation The configured recovery participants can cancel a pending recovery before completion. Cancellation clears the pending recovery state and restores normal operation under the existing authentication configuration. ### 16.3 Pre-Rotated-Key Recovery The DID can also commit to a future key configuration before it is needed. If current keys are compromised or lost, the pre-rotated keys can take over at once, with no assisted-recovery delay. The pre-rotation flow also commits the next pre-rotated configuration so the safety property continues after use. --- ## 17. Security Properties ### 17.1 Hash-Enforced Routing The implementation restricts delegated child puzzles by hash. This prevents an authenticated DID spend from substituting arbitrary behavior into the identity-layer call graph. ### 17.2 Namespace Guard The protocol reserves the `JDID` namespace for identity-layer messages and announcements. The guarded passthrough operation rejects user-supplied protocol-looking messages and announcements so application-level conditions cannot spoof DID, credential, issuer, or recovery signals. ### 17.3 Nonce Protection Credential and message presentations can include nonce announcements. Nonces prevent replay and protect against BLS signature-subtraction attacks where an attacker attempts to extract a reusable component from an aggregate signature. ### 17.4 Recovery Lockout Normal authenticated operations are blocked while assisted recovery is pending. This prevents a compromised current key holder from racing arbitrary state changes during the recovery window. ### 17.5 State-Bound Authorization Authorization is bound to puzzle hashes that commit to DID state. A state change changes the puzzle hash, invalidating old state-bound authorizations. ### 17.6 Issuer Key Melt Credential issuance authority is separated into issuer key singletons. Melting an issuer key gives the issuer DID a coarse emergency revocation mechanism for all credentials signed by that issuer key. --- ## 18. Relationship to Doc #19 This document omits, by design, exact Chialisp signatures, line counts, child-puzzle allowlists, error-code tables, and per-file implementation details. Those details belong in **[Chialisp Code Reference (Doc #19)](https://not.bot/technology/chialisp/)** and may change when the open-source puzzle set changes. Protocol facts that should remain stable here: - Julia DIDs are Chia singletons identified by launcher ID. - DID state is committed into puzzle hashes. - Authentication supports single-key, multi-class multisig, and custody. - Recovery supports time-locked assisted recovery, cancellation, and pre-rotation. - Credential issuance uses issuer key singletons. - Credential presentation is Chia-spend-verifiable and can run on-chain or carry a deliberate invalidating condition for off-chain use. - DID-controlled coins are commanded by DID spends rather than embedding all DID logic in each asset coin. - Presentations compose claims from independent issuers under one aggregate BLS signature. - User operations are faucet-funded; users never hold XCH. - A Julia DID cannot be melted; the launcher ID is permanent. --- > **Chialisp Code Reference** — https://not.bot/technology/chialisp/ · Markdown: https://not.bot/technology/chialisp.md · Updated 2026-06-05 # Julia-DID Chialisp Code Reference This document is a reference for the shipped Chialisp source. For the protocol-level design, see **[did:julia Technical Specification (Doc #15)](https://not.bot/technology/did-julia-specification/)**. The Chialisp tree contains 27 production/build puzzle files (`.clsp`), 9 shared library files (`.clib`), two precompiled Chia singleton hex files, and a Makefile. All source paths below are relative to the public Chialisp repository root. --- ## 1. Codebase Organization ### 1.1 Build Order The repository includes a Makefile that builds the puzzles in the correct order. This matters because many puzzles embed compiled hashes of other puzzles with `embed-file`; a parent puzzle cannot be compiled until the child puzzle hashes it embeds already exist. That is the only build rule this reference relies on: use the Makefile rather than compiling files by hand in arbitrary order. ### 1.2 How DID Spends Route The main DID singleton puzzle, `julia_did.clsp`, is the first puzzle run for a DID spend. After checking the DID state hash and lineage, it routes to one of seven top-level entrypoints: | Entrypoint | Route type | What it does | |------------|------------|--------------| | `singlesig.clsp` | Normal authentication | Authenticates one key, then calls an allowed operation | | `multisig.clsp` | Normal authentication | Authenticates a multi-class signer set, then calls an allowed operation | | `custody_minion.clsp` | Normal authentication by custodian DID | Requires a custodian DID command, then calls an allowed operation | | `recovery_initiate.clsp` | Direct recovery entrypoint | Starts a pending assisted recovery | | `recovery_cancel.clsp` | Direct recovery entrypoint | Cancels a pending assisted recovery | | `recovery_complete.clsp` | Direct recovery entrypoint | Completes an assisted recovery | | `recovery_prerotation.clsp` | Direct recovery entrypoint | Switches to pre-rotated keys | Normal authentication entrypoints can call two kinds of child operations: - combineable operations, which can continue to another child puzzle - standalone operations, which perform one action and stop ### 1.3 Combineable Operations The combineable operations have a required invocation order: ```text sign_message -> coin_control -> invalidate -> DIDdoc_announce -> pass_thru -> present_delegated -> present_claims ``` Any combineable operation can be skipped. For example, authenticated callers can call `present_claims` directly; `sign_message` can call `present_claims` directly; `DIDdoc_announce` can call `present_delegated` directly. The chain above shows the order when all combineable operations are used together. Each wrapper prepends its own conditions before passing through child conditions: | Puzzle | Adds | |--------|------| | `sign_message.clsp` | signed-message, timestamp, and nonce announcements | | `coin_control.clsp` | `JDIDP` command messages to other coins | | `invalidate.clsp` | impossible spend condition and optional time bounds | | `DIDdoc_announce.clsp` | DID document pointer announcement | | `pass_thru.clsp` | guarded arbitrary caller-supplied conditions | | `present_delegated.clsp` | delegated-claim assertions and presentation announcement | | `present_claims.clsp` | direct credential presentation announcements and claim validation conditions | ### 1.4 Standalone DID Operations These operations are called individually by an authentication entrypoint and do not continue into the wrapper chain. | Puzzle | Allowed caller | Purpose | |--------|----------------|---------| | `custodian.clsp` | `singlesig`, `multisig` | Sends a command from a custodian DID to a minion DID | | `DIDdoc_set.clsp` | `singlesig`, `multisig`, `custody_minion` | Updates the DID Document pointer | | `issuer_key_control.clsp` | `singlesig`, `multisig`, `custody_minion` | Sends revocation-update or melt commands to issuer key singletons | | `launch_issuer_key.clsp` | `singlesig`, `multisig`, `custody_minion` | Launches issuer key singletons | | `rekey.clsp` | `singlesig`, `multisig` | Replaces the DID authentication configuration | | `recovery_authorize.clsp` | `singlesig`, `multisig` | Sends a recovery initiation or cancellation authorization message from a recovery-agent DID | ### 1.5 Recovery Paths Recovery has two distinct call patterns. Four recovery puzzles are direct entrypoints selected by `julia_did.clsp`, bypassing normal authentication. `recovery_authorize.clsp` is different: it is a standalone operation called by the recovery-agent DID through `singlesig` or `multisig`. | Recovery puzzle | Called by | Requires | Effect | |-----------------|-----------|----------|--------| | `recovery_initiate.clsp` | `julia_did` directly | Recovery-agent quorum messages and no active recovery | Starts pending recovery and records replacement state | | `recovery_cancel.clsp` | `julia_did` directly | Recovery-agent quorum messages and active recovery | Clears pending recovery | | `recovery_complete.clsp` | `julia_did` directly | Active recovery and elapsed relative height | Applies replacement state; anyone can complete once mature | | `recovery_prerotation.clsp` | `julia_did` directly | Signatures from pre-rotated keys | Switches to pre-rotated keys and commits the next prerotation | | `recovery_authorize.clsp` | `singlesig` or `multisig` | Current control of a recovery-agent DID | Sends an initiation or cancellation authorization message to another DID | ### 1.6 Issuer Key and Companion Coin Interactions Issuer key singletons are separate from the DID singleton: - `launch_issuer_key.clsp` is a DID operation that creates issuer key singleton launchers. - `issuer_key.clsp` is the issuer key singleton puzzle. - `issuer_key_functions.clsp` implements issuer key management modes for revocation updates and melt. - `issuer_key_control.clsp` is the DID-side operation that sends commands to issuer key singletons. Companion coin puzzles are not DID sub-puzzles: - `p2_JDID.clsp` is used as an inner puzzle for coins controlled by a DID. It spends only when it receives a `JDIDP` command from the owning DID. - `p2_claim.clsp` is used as an inner puzzle for coins controlled by a qualifying credential presentation and a DID command. - `faucet_coin.clsp` is an independent faucet puzzle and is not part of the DID call graph. ### 1.7 Common Return Convention Most sub-puzzles are called with: ```clojure (curried-args solution) ``` They return: ```clojure (updated-curried-args conditions) ``` The top-level `julia_did.clsp` consumes that return value, creates the next singleton generation with the updated curried-args hash, and emits the returned conditions. Leaf operations that do not change DID state return the original `curried-args`. ### 1.8 DID Curried Arguments The DID singleton state is passed through the codebase as `curried-args`: | Position | Field | Purpose | |---:|------|---------| | 1 | `julia-DID-puzzlehash` | Hash of the raw `julia_did.clsp` puzzle | | 2 | `my-launcher-id` | Permanent DID identifier | | 3 | `recovery-timeout-block` / `recovery-delay` | `0` when no recovery is pending; nonzero during recovery | | 4 | `multisig-info` | Authentication tree and class quorum configuration | | 5 | `valid-custodian-DIDs` | DID launcher IDs authorized as custodians | | 6 | `recovery-info` | Recovery agent and prerotation configuration | | 7 | `DID-doc` | DataLayer singleton launcher ID for the DID Document | | 8 | pending recovery parameters | Present only while recovery is active or where a token-consuming puzzle appends a marker | `julia_did.clsp` and `issuer_key.clsp` are curried with `CURRIED-ARGS-HASH`, not the full state. The full state is revealed in the solution and checked with `sha256tree`. ### 1.9 Chialisp Conventions - Most files include `*standard-cl-26*`. - Uppercase names in a `mod` signature are curried parameters; lowercase names are solution parameters. - `embed-file` imports compiled puzzle hashes, not source. - Bare `(x )` expressions raise integer errors. - `AGG_SIG_PUZZLE` and `ASSERT_MY_PUZZLEHASH` are used in normal singleton spends for fast-forward-compatible authorization. - `ASSERT_MY_PARENT_ID` appears in eve spends, where the launcher relationship is being established. --- ## 2. Puzzle Reference ### 2.1 Top-Level and Companion Puzzles #### `julia_did.clsp` Main DID singleton puzzle. **Mod signature:** `(CURRIED-ARGS-HASH curried-args parent-info solution)` **State input:** Verifies `CURRIED-ARGS-HASH == sha256tree(curried-args)`. **Regular spend behavior:** - Destructures the DID curried args. - Confirms `launcher-coin-id == my-launcher-id`. - Computes valid entrypoint hashes for `singlesig`, `multisig`, `custody_minion`, `recovery_initiate`, `recovery_cancel`, `recovery_complete`, and `recovery_prerotation`. - Runs the selected entrypoint through `puzzle-selector`. - Emits `ASSERT_MY_PUZZLEHASH`. - Creates the next DID singleton child with `julia-DID-curried-puzzlehash(julia-DID-puzzlehash, sha256tree(new-curried-args))`. - Emits `REMARK new-curried-args`. - Appends child conditions returned by the entrypoint. **Eve spend behavior:** - Asserts the singleton launcher as parent with `ASSERT_MY_PARENT_ID`. - Creates the first DID singleton child. - Emits `REMARK curried-args`. - Sends `JDIDL` to the prelauncher coin. **Errors:** `15` failed lineage proof; `16` invalid curried args hash. #### `prelauncher.clsp` Prelauncher for Julia DID coins and root of the fast-forward lineage proof. **Mod signature:** `(PUBKEY julia-did-puzzlehash my-coin-id did-coin-curried-args-hash)` **Conditions emitted:** - `ASSERT_MY_COIN_ID my-coin-id` - `CREATE_COIN singleton_launcher 1` - `RECEIVE_MESSAGE 0x3F "JDIDL" did-coin-id` The puzzle is curried with `PUBKEY`; the remaining values are solution parameters. #### `p2_JDID.clsp` Inner puzzle for coins owned by a Julia DID. **Mod signature:** `(JDID_LAUNCHER_ID JDID-curried-args-hash conditions)` **Behavior:** - Computes the owning DID coin puzzle hash from `julia_did.clsp.hash.bin`, the DID launcher ID, and the DID curried-args hash. - Requires `RECEIVE_MESSAGE 0x17 (concat "JDIDP" (sha256tree conditions)) `. - Emits the supplied `conditions`. This puzzle does not validate the business meaning of the emitted conditions; it trusts the owning DID's authenticated `coin_control` path. #### `p2_claim.clsp` Inner puzzle for coins controlled by possession of a valid credential claim. **Mod signature:** `(JDID_LAUNCHER_ID my-coin-id spender-launcher-id spender-curried-args-hash conditions)` **Behavior:** - Asserts its own coin ID. - Computes the spender DID puzzle hash. - Requires an asserted puzzle announcement from the spender DID proving a `JDIDV` claim for the hardcoded payment property `sha256("cleartext://./.julia-payment")`, this coin ID, and the payee DID launcher ID. - Requires `RECEIVE_MESSAGE 0x17 (concat "JDIDP" (sha256tree conditions)) `. - Emits the supplied `conditions`. #### `faucet_coin.clsp` Simple faucet coin puzzle used by the Julia Social faucet. **Mod signature:** `(PUBKEY SERIAL conditions)` `SERIAL` allows multiple otherwise-identical faucet coins to be created. The puzzle emits the supplied `conditions` only when authorized by: ```clojure (AGG_SIG_ME PUBKEY (sha256tree conditions)) ``` Unlike the DID puzzles, this puzzle uses `AGG_SIG_ME`, binding authorization to the specific coin spend. --- ### 2.2 Authentication Entry Points #### `singlesig.clsp` Single-key authentication entrypoint. **Mod signature:** `(curried-args solution)` **Solution shape:** `fee-coin`, one pubkey Merkle path, sides, and child puzzle input. **Validation:** - DID must require exactly one class. - Exactly one pubkey path must be supplied. - The path must validate against `multisig-info`. - The selected class must require exactly one member. - Recovery must not be active. **Conditions added:** - `AGG_SIG_PUZZLE (sha256tree solution)` - Optional `ASSERT_CONCURRENT_SPEND fee-coin` **Allowed children:** `sign_message`, `coin_control`, `custodian`, `DIDdoc_announce`, `DIDdoc_set`, `invalidate`, `issuer_key_control`, `launch_issuer_key`, `pass_thru`, `present_claims`, `present_delegated`, `rekey`, `recovery_authorize`. **Errors:** `30`, `31`, `32`, `33`, `34`, plus `110` from `puzzle-selector`. #### `multisig.clsp` Multi-signer, multi-class authentication entrypoint. **Mod signature:** `(curried-args solution)` **Solution shape:** `fee-coin`, participant Merkle paths, path sides, and child puzzle input. **Validation:** - Uses `multiclass` to validate participants against `multisig-info`. - Recovery must not be active. - Child puzzle hash must be in the allowlist. **Conditions added:** - One `AGG_SIG_PUZZLE (sha256tree solution)` per validated participant. - Optional `ASSERT_CONCURRENT_SPEND fee-coin`. **Allowed children:** Same as `singlesig.clsp`. **Errors:** `17`, plus `103`-`106` from `multiclass` and `110` from `puzzle-selector`. #### `custody_minion.clsp` Authentication entrypoint for DIDs controlled by an external custodian DID. **Mod signature:** `(curried-args solution)` **Solution shape:** custodian DID launcher ID, custodian curried-args hash, and child puzzle input. **Validation:** - The custodian DID must appear in `valid-custodian-DIDs`. - Recovery must not be active. - Requires `RECEIVE_MESSAGE 0x12 (concat "JDIDC" child-solution-hash) `. - Asserts this minion DID's current puzzle hash. **Allowed children:** `sign_message`, `coin_control`, `DIDdoc_announce`, `DIDdoc_set`, `invalidate`, `issuer_key_control`, `launch_issuer_key`, `pass_thru`, `present_claims`, `present_delegated`. **Errors:** `5`, `6`, plus `110` from `puzzle-selector`. --- ### 2.3 DID Operation Puzzles #### `sign_message.clsp` Adds DID-signed message announcements, timestamps, and nonces, then optionally delegates. **Mod signature:** `(curried-args solution)` **Solution shape:** messages list, datetime, nonce, optional child puzzle input. **Conditions added:** - One `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDM" message)` per message. - Optional `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDT" datetime)`. - Optional `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDN" nonce)`. **Allowed children:** `coin_control`, `DIDdoc_announce`, `invalidate`, `pass_thru`, `present_claims`, `present_delegated`. **Errors:** `110` for invalid child. #### `coin_control.clsp` Sends DID-authorized command messages to other coins. **Mod signature:** `(curried-args solution)` **Solution shape:** count, `count` pairs of message and coin ID, then optional child puzzle input. For each pair, emits: ```clojure (SEND_MESSAGE 0x17 (concat "JDIDP" message) coin-id) ``` The code does not check whether the receiving coin uses `p2_JDID` or `p2_claim`; it only emits the command message. **Allowed children:** `DIDdoc_announce`, `invalidate`, `pass_thru`, `present_claims`, `present_delegated`. **Errors:** `110` for invalid child. #### `invalidate.clsp` Adds conditions that make a spend bundle unusable on-chain while preserving verifiability. **Mod signature:** `(curried-args solution)` **Solution shape:** `invalidate-flag`, `valid-from-seconds`, `valid-to-seconds`, optional child puzzle input. **Conditions added:** - If `invalidate-flag` is truthy: `ASSERT_CONCURRENT_SPEND` on the all-zero coin ID. - If `valid-from-seconds` is set: `ASSERT_SECONDS_ABSOLUTE`. - If `valid-to-seconds` is set: `ASSERT_BEFORE_SECONDS_ABSOLUTE`. **Allowed children:** `DIDdoc_announce`, `pass_thru`, `present_claims`, `present_delegated`. **Errors:** `110` for invalid child. #### `DIDdoc_announce.clsp` Announces the DataLayer singleton ID associated with the DID Document. **Mod signature:** `(curried-args solution)` **Condition added:** ```clojure (CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDD" DID-doc)) ``` **Allowed children:** `pass_thru`, `present_claims`, `present_delegated`. **Errors:** `110` for invalid child. #### `DIDdoc_set.clsp` Updates the DID Document pointer. **Mod signature:** `(curried-args solution)` **Solution shape:** `new-DID-doc`. **State change:** Replaces the `DID-doc` field in `curried-args`. **Conditions added:** none. #### `pass_thru.clsp` Allows arbitrary caller-supplied conditions after guarding the `JDID` namespace. **Mod signature:** `(curried-args solution)` **Solution shape:** count, `count` conditions, optional child puzzle input. **Validation:** - Rejects structured coin/puzzle announcements. - Rejects coin/puzzle announcements whose byte content starts with `JDID`. - Rejects structured `SEND_MESSAGE` payloads. - Rejects `SEND_MESSAGE` payloads whose byte content starts with `JDID`. **Allowed children:** `present_claims`, `present_delegated`. **Errors:** `18`, `19`, `20`, `21`, `36`. #### `custodian.clsp` Allows a custodian DID to command a custodied DID that uses `custody_minion.clsp`. **Mod signature:** `(curried-args solution)` **Solution shape:** minion DID launcher ID, minion curried-args hash, child solution hash. **Conditions added:** - `SEND_MESSAGE 0x12 (concat "JDIDC" child-solution-hash) ` - `ASSERT_MY_PUZZLEHASH ` **State change:** none. #### `rekey.clsp` Routine key update using current authentication. **Mod signature:** `(curried-args solution)` **Solution shape:** `new-multisig-info`. **State change:** Replaces the `multisig-info` field. **Conditions added:** none. --- ### 2.4 Recovery Puzzles #### `recovery_initiate.clsp` Starts a time-locked recovery by committing pending replacement state. **Mod signature:** `(curried-args solution)` **Solution shape:** participant Merkle paths, participant curried-arg hashes, new multisig info, new custodian DID list, new recovery info. **Validation:** - Recovery must not already be active. - Participants must satisfy `recovery-info` via `multiclass`. - Participant and curried-arg-hash lists must balance. **State change:** - Sets `recovery-timeout-block` to the configured recovery delay. - Appends pending replacement values: new multisig info, new custodian DIDs, and new recovery info. **Conditions added:** One `RECEIVE_MESSAGE 22 (concat "JDIDR" new-params-hash) ` per required recovery participant. **Errors:** `27`, `28`, `29`, plus `multiclass` and Merkle-path errors. #### `recovery_authorize.clsp` Run by a recovery participant DID to authorize initiation or cancellation on another DID. **Mod signature:** `(curried-args solution)` **Solution shape:** target DID launcher ID, target curried-args hash, `initiate-or-cancel`, `new-params-hash`, `expiration-block`. **State change:** Appends a trailing `0` marker to its own curried args. **Conditions added:** - `SEND_MESSAGE 22 (concat "JDID" initiate-or-cancel new-params-hash) ` - `ASSERT_BEFORE_HEIGHT_ABSOLUTE expiration-block` `initiate-or-cancel` must be `"R"` or `"X"`. **Errors:** `22`. #### `recovery_cancel.clsp` Cancels an active recovery. **Mod signature:** `(curried-args solution)` **Solution shape:** participant Merkle paths and participant curried-arg hashes. **Validation:** - Recovery must be active. - Participants must satisfy `recovery-info`. - Participant and curried-arg-hash lists must balance. **State change:** Resets `recovery-timeout-block` to `0` and removes pending recovery state. **Conditions added:** One `RECEIVE_MESSAGE 22 "JDIDX" ` per required recovery participant. **Errors:** `23`, `24`, `25`, plus `multiclass` and Merkle-path errors. #### `recovery_complete.clsp` Completes an active recovery after the delay. **Mod signature:** `(curried-args solution)` **Validation:** Recovery must be active. **State change:** Applies pending `new-multisig-info`, `new-custodian-DIDs`, and `new-recovery-info`; resets recovery delay to `0`. **Conditions added:** `ASSERT_HEIGHT_RELATIVE recovery-delay`. Anyone can spend this puzzle once the relative height condition can be satisfied. **Errors:** `26`. #### `recovery_prerotation.clsp` Switches immediately to a pre-committed key configuration and commits the next prerotation. **Mod signature:** `(curried-args solution)` **Solution shape:** fee coin, participant Merkle paths, path sides, new prerotation multisig info. **Validation:** Participants must satisfy the prerotation multisig info stored inside `recovery-info`. **State change:** - Replaces `multisig-info` with the previous prerotation multisig info. - Stores the supplied next prerotation info inside `recovery-info`. - Cancels any active recovery by setting recovery delay to `0`. **Conditions added:** - One `AGG_SIG_PUZZLE (sha256tree solution)` per prerotation signer. - Optional `ASSERT_CONCURRENT_SPEND fee-coin`. --- ### 2.5 Issuer Key Puzzles #### `launch_issuer_key.clsp` Creates issuer key singleton launchers from the owning DID. **Mod signature:** `(curried-args solution)` **Solution shape:** DID parent, DID launcher ID, raw issuer-key puzzle hash, followed by one or more issuer key definitions: public key, `valid-from`, `valid-to`, maximum credential expiration, allowed property root, mode-1 payment puzzle hash, mode-1 payment mojos. **Conditions added per key:** - `CREATE_COIN singleton_launcher amount` - `RECEIVE_MESSAGE 0x3F "JDIDI" ` **Additional condition:** `ASSERT_MY_COIN_ID my-coin-id`. **Implementation note:** Launcher coin amounts increase across multiple launches while issuer key singleton children use amount `1`. **Error:** `41` if `mode-1-payment-mojos > 1`, blocking free anyone-can-spend payment coins. #### `issuer_key.clsp` Issuer key singleton puzzle. **Mod signature:** `(CURRIED-ARGS-HASH curried-args parent-info spend-mode spend-mode-args)` **Issuer key curried args:** 1. `issuer-did-launcher-id` 2. `issuer-key-puzzlehash` 3. `julia-did-puzzlehash` 4. `my-launcher-id` 5. `public-key` 6. `revocation-bitfield-root` 7. `valid-from` 8. `valid-to` 9. `max-expiration` 10. `cred-property-hash-root` 11. `mode-1-payment-puzzlehash` 12. `mode-1-payment-mojos` **Eve spend behavior:** - `ASSERT_MY_PARENT_ID launcher-coin-id` - Creates the first issuer key singleton child. - Emits `REMARK curried-args`. - Sends `JDIDI` to the issuer DID coin. **Regular spend behavior:** - Checks `CURRIED-ARGS-HASH`. - Verifies launcher lineage. - Emits `ASSERT_MY_PUZZLEHASH`. - Mode `1`: recreates the singleton unchanged, emits `REMARK curried-args`, emits `CREATE_PUZZLE_ANNOUNCEMENT "JDIDA"`, and optionally creates the configured payment coin. - Other modes: require `issuer_key_functions.clsp` as the spend-mode puzzle and delegate to it. **Errors:** `9`, `10`, `11`, `42`. #### `issuer_key_functions.clsp` Management functions for an issuer key singleton. **Mod signature:** `(curried-args spend-mode spend-mode-args)` **Mode 2: update revocation by key** - Verifies current bitfield proof. - Replaces one bitfield leaf and computes the new root. - Requires `AGG_SIG_PUZZLE public-key (sha256tree spend-mode-args)`. - Creates the next issuer key singleton child and emits `REMARK new-curried-args`. - Optionally asserts a concurrent fee coin. **Mode 3: update revocation by DID** - Verifies current bitfield proof. - Replaces one bitfield leaf and computes the new root. - Requires `RECEIVE_MESSAGE 0x16 (concat "JDIDK" (sha256tree (list index new-leaf))) `. - Creates the next issuer key singleton child and emits `REMARK new-curried-args`. **Mode 5: melt** - Requires `RECEIVE_MESSAGE 0x12 "JDIDZ" `. - Emits the Chia singleton melt `CREATE_COIN 0 -113`. **Errors:** `12`, `13`, `14`. #### `issuer_key_control.clsp` DID-side issuer key management operation. **Mod signature:** `(curried-args solution)` **Solution shape:** mode plus mode-specific target issuer key values. **Mode 3:** Emits `SEND_MESSAGE 0x16 (concat "JDIDK" (sha256tree (list index new-leaf))) `. **Mode 5:** Emits `SEND_MESSAGE 0x12 "JDIDZ" `. **State change:** none. **Error:** `35` for invalid mode. --- ### 2.6 Credential Presentation Puzzles #### `present_claims.clsp` Validates and presents credential claims. **Mod signature:** `(curried-args solution)` **Solution shape:** nonce plus claims-with-proofs. **Behavior:** - Emits `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDN" nonce)`. - Calls `validate-claims` with this DID launcher ID, the raw `julia_did` puzzle hash, the raw `issuer_key` puzzle hash, and the supplied claims-with-proofs. - Returns unchanged `curried-args`. See `include/validate_claims.clib` for per-claim validation details. #### `present_delegated.clsp` Presents claims delegated through one or more DID holders. **Mod signature:** `(curried-args solution)` **Solution shape:** count, delegation paths, optional `present_claims` child input. **Behavior:** - Asserts the original claim's holder/delegation announcement. - Walks each delegation path. - Requires the terminal delegatee to be this DID. - Emits `CREATE_PUZZLE_ANNOUNCEMENT (concat "JDIDV" claim-property-hash claim-value-hash issuer-did-launcher-id)` for delegated presentation as subject. - Optionally runs `present_claims.clsp` as a child to present original claims in the same spend. **Errors:** `37`, `38`, `39`. --- ## 3. Library Reference ### `include/sha256tree.clib` Recursive CLVM tree hash implementation: - Atom: `sha256(1, atom)` - Pair: `sha256(2, sha256tree(left), sha256tree(right))` ### `include/condition_codes.clib` Defines Chia condition constants used throughout the codebase, including signature, coin creation, announcements, messaging, self-inspection, relative/absolute time assertions, and `REMARK`. ### `include/curry_and_treehash.clib` Computes the puzzle hash of a curried function without performing the curry. Used by `did_puzzles.clib` to reconstruct expected DID and issuer key puzzle hashes inside other puzzles. ### `include/did_puzzles.clib` Puzzle hash helpers: - `prelauncher-coin-puzzlehash` - `issuer-key-curried-puzzlehash` - `issuer-key-coin-puzzlehash` - `julia-DID-curried-puzzlehash` - `julia-DID-coin-puzzlehash` Embeds the standard singleton top layer and singleton launcher hashes. ### `include/puzzle_selector.clib` Generic allowlist router. It compares a supplied puzzle hash against valid hashes and executes the puzzle if matched. Raises `110` when no match is found. ### `include/parse_merkle_path.clib` Validates a Merkle path and extracts `(class . leaf)`. Raises `107` for class depth beyond leaf depth, `108` for invalid class depth, and `109` for root mismatch. ### `include/multiclass.clib` Validates multi-class quorum requirements. It parses participant Merkle paths, verifies class membership, enforces unique participant leaves, and checks that enough classes are satisfied. Errors: `103`, `104`, `105`, `106`. ### `include/bitfield.clib` Revocation bitfield utilities: - `verify-tree` - `check-bit` - `set-leaf` Errors: `100` offset too large, `101` negative offset, `102` invalid tree proof. ### `include/validate_claims.clib` Credential claim validation logic. For each claim, validates subject/holder mode, issuer DID consistency, public-key consistency, expiration bounds, issuer-key validity period, revocation status, property authorization, and antecedent requirements. Per valid claim it emits claim/holder announcements, asserts issuer-key liveness via `JDIDA`, adds time-window assertions, and requires `AGG_SIG_UNSAFE` from the issuer key over the claim tree hash. Error: `112` claim validation failed. --- ## 4. Error Codes | Code | Source | Meaning | |------|--------|---------| | 5 | `custody_minion.clsp` | Custodian DID is not authorized | | 6 | `custody_minion.clsp` | Recovery is active | | 9 | `issuer_key.clsp` | Invalid issuer key functions puzzle | | 10 | `issuer_key.clsp` | Invalid issuer key lineage | | 11 | `issuer_key.clsp` | Invalid issuer key curried args hash | | 12 | `issuer_key_functions.clsp` | Invalid bitfield proof in mode 2 | | 13 | `issuer_key_functions.clsp` | Invalid bitfield proof in mode 3 | | 14 | `issuer_key_functions.clsp` | Invalid issuer key spend mode | | 15 | `julia_did.clsp` | Invalid DID lineage | | 16 | `julia_did.clsp` | Invalid DID curried args hash | | 17 | `multisig.clsp` | Recovery is active | | 18 | `pass_thru.clsp` | Structured announcement rejected | | 19 | `pass_thru.clsp` | `JDID`-prefixed announcement rejected | | 20 | `pass_thru.clsp` | Structured message rejected | | 21 | `pass_thru.clsp` | `JDID`-prefixed message rejected | | 22 | `recovery_authorize.clsp` | Invalid recovery authorize flag | | 23 | `recovery_cancel.clsp` | Participant/hash list mismatch | | 24 | `recovery_cancel.clsp` | Participant/hash list mismatch | | 25 | `recovery_cancel.clsp` | Recovery is not active | | 26 | `recovery_complete.clsp` | Recovery is not active | | 27 | `recovery_initiate.clsp` | Participant/hash list mismatch | | 28 | `recovery_initiate.clsp` | Participant/hash list mismatch | | 29 | `recovery_initiate.clsp` | Recovery is already active | | 30 | `singlesig.clsp` | Selected class requires more than one member | | 31 | `singlesig.clsp` | Selected key class is not valid | | 32 | `singlesig.clsp` | DID requires more than one class | | 33 | `singlesig.clsp` | More than one pubkey path supplied | | 34 | `singlesig.clsp` | Recovery is active | | 35 | `issuer_key_control.clsp` | Invalid issuer key control mode | | 36 | `pass_thru.clsp` | Invalid child puzzle | | 37 | `present_delegated.clsp` | Invalid child puzzle | | 38 | `present_delegated.clsp` | Terminal delegatee is not this DID | | 39 | `present_delegated.clsp` | Claim not found in delegation list | | 41 | `launch_issuer_key.clsp` | Free anyone-can-spend payment coin rejected | | 42 | `issuer_key.clsp` | Odd singleton child amount rejected | | 100 | `bitfield.clib` | Bit offset exceeds `0x01FF` | | 101 | `bitfield.clib` | Negative bit offset | | 102 | `bitfield.clib` | Invalid bitfield tree proof | | 103 | `multiclass.clib` | Participant class is not valid | | 104 | `multiclass.clib` | Class quorum requirements not met | | 105 | `multiclass.clib` | Duplicate participant leaf | | 106 | `multiclass.clib` | Duplicate leaf across classes | | 107 | `parse_merkle_path.clib` | Class depth exceeds leaf depth | | 108 | `parse_merkle_path.clib` | Invalid class depth | | 109 | `parse_merkle_path.clib` | Merkle root mismatch | | 110 | Routing helpers | Puzzle hash not in allowed set | | 112 | `validate_claims.clib` | Claim validation failed | --- ## 5. File Inventory ### 5.1 Production/Build Puzzles | File | Lines | Category | Summary | |------|------:|----------|---------| | `DIDdoc_announce.clsp` | 44 | DID Document | Announces DID Document DataLayer singleton ID | | `DIDdoc_set.clsp` | 50 | DID Document | Updates DID Document pointer | | `coin_control.clsp` | 60 | Operations | Sends `JDIDP` commands to controlled coins | | `custodian.clsp` | 59 | Custody | Sends `JDIDC` commands to minion DIDs | | `custody_minion.clsp` | 110 | Authentication | Authenticates by custodian DID command | | `faucet_coin.clsp` | 19 | Faucet | Faucet spend puzzle authorized by `AGG_SIG_ME` | | `invalidate.clsp` | 76 | Operations | Adds unsatisfiable or time-window conditions | | `issuer_key.clsp` | 93 | Issuer key | Issuer key singleton | | `issuer_key_control.clsp` | 73 | Issuer key | DID-side issuer key commands | | `issuer_key_functions.clsp` | 178 | Issuer key | Issuer key management modes | | `julia_did.clsp` | 95 | Top-level | Main DID singleton | | `launch_issuer_key.clsp` | 75 | Issuer key | Launches issuer key singletons | | `multisig.clsp` | 96 | Authentication | Multi-class multisig authentication | | `p2_JDID.clsp` | 23 | Companion | Inner puzzle for DID-owned coins | | `p2_claim.clsp` | 31 | Companion | Inner puzzle for credential-controlled coins | | `pass_thru.clsp` | 90 | Operations | Guarded arbitrary condition passthrough | | `prelauncher.clsp` | 26 | Top-level | DID prelauncher | | `present_claims.clsp` | 29 | Credentials | Direct claim presentation | | `present_delegated.clsp` | 158 | Credentials | Delegated claim presentation | | `recovery_authorize.clsp` | 46 | Recovery | Recovery participant authorization token | | `recovery_cancel.clsp` | 108 | Recovery | Cancels pending recovery | | `recovery_complete.clsp` | 57 | Recovery | Completes pending recovery | | `recovery_initiate.clsp` | 117 | Recovery | Starts pending recovery | | `recovery_prerotation.clsp` | 73 | Recovery | Switches to pre-rotated keys | | `rekey.clsp` | 43 | Operations | Routine key rotation | | `sign_message.clsp` | 82 | Operations | DID message/timestamp/nonce announcements | | `singlesig.clsp` | 117 | Authentication | Single-signer authentication | ### 5.2 Libraries | File | Lines | Summary | |------|------:|---------| | `include/bitfield.clib` | 92 | Revocation bitfield Merkle utilities | | `include/condition_codes.clib` | 77 | Chia condition constants | | `include/curry_and_treehash.clib` | 68 | Curried puzzle hash computation | | `include/did_puzzles.clib` | 46 | DID and issuer key puzzle hash helpers | | `include/multiclass.clib` | 135 | Multi-class quorum validation | | `include/parse_merkle_path.clib` | 66 | Merkle path parsing and class extraction | | `include/puzzle_selector.clib` | 28 | Hash allowlist router | | `include/sha256tree.clib` | 10 | CLVM tree hash | | `include/validate_claims.clib` | 184 | Claim validation | ### 5.3 Other Build Files | File | Summary | |------|---------| | `singleton_launcher.clsp.hex` | Precompiled Chia singleton launcher | | `singleton_top_layer_v1_1.clsp.hex` | Precompiled Chia singleton top layer | | `Makefile` | Build and test orchestration | --- > **Why Chia?** — https://not.bot/technology/why-chia/ · Markdown: https://not.bot/technology/why-chia.md · Updated 2026-06-17 # **Why Chia?** not.bot™ is a system of cryptographic identity for humans. At launch, a person will enroll by scanning the NFC chip in their passport, and can then prove they are a human, prove their age, or sign content so that others can confirm its author, without disclosing their name or linking their separate accounts. Each not.bot identity is an instance of the did:julia method, recorded on the Chia blockchain. Building on a public blockchain, and on Chia in particular, is a foundational design decision. This document describes the reasoning behind it: why an identity system of this kind requires a public blockchain and why Chia among the available blockchains. ## **Why a public blockchain for digital identity?** An identity system of this kind has to satisfy several requirements at once. An identity must be verifiable by any party to whom it is presented. It must remain under the control of the entity it describes rather than an operator. And its use should not produce a record of when and where it was used. Other identity architectures satisfy some of these requirements and not others. A central registry places one operator in control of the records; that operator can alter or deny a record, and its failure removes access for everyone. An identity provider that mediates each use observes every transaction, which makes the architecture a means of surveillance. A public blockchain removes the operator from the position of control. It provides four properties relevant to identity: - **A record under no single party's control.** Julia Social cannot alter an identity, seize it, or create one in another person's name. The blockchain holds the record, and its integrity rests on the consensus of the network rather than on the conduct of a company. - **Verification independent of the issuer.** Any party to whom an identity is presented can confirm it against the blockchain. Julia Social is not contacted and need not be available for an identity to function. - **No disclosure on use.** Presenting an identity contacts no central service. No party is informed that a person signed in to a site or signed a document. - **Independent verification.** A party can operate its own Chia node and verify against it, which removes any dependence on a third party and keeps verification queries inside the party's own infrastructure. Together these properties allow an identity to be verifiable by any party while remaining outside the control of any single one, a combination that a server operated by one company cannot provide. ## **Why Chia specifically?** Public blockchains differ in ways that determine their suitability for identity. did:julia depends on a specific set of properties. Chia provides all of them, and few other blockchains provide more than a subset. This section states the requirements, describes how Chia satisfies each, and compares the main alternatives. ### **Requirements** did:julia requires the following of its underlying blockchain: - Each identity exists as a discrete object controlled by its owner, with no shared state accessible to a central party. - The conditions for using an identity are programmable, so that ownership, recovery, delegation, and revocation are defined within the identity itself. - Verifiable Credentials from independent issuers combine into a single Verifiable Presentation, allowing several credentials to be presented and verified together. - Verifiers cannot extract individual credentials from a presentation. - A signed assertion can be presented to a counterparty and verified off-chain, without a transaction reaching the blockchain. - A node used for verification runs at low enough cost that an individual user or a small organization can operate one. - A large set of publicly-accessible nodes, so that a verifier who does not run a node can query one at random without identifying itself. - The consensus securing the record withstands attack from any party short of a majority of the network. - Credential revocation is recorded on the blockchain and checkable against any node. - A person can transact on the blockchain without first acquiring the native cryptocurrency. ### **How Chia satisfies the requirements** **Signature aggregation.** Chia uses BLS12-381 signatures. A set of BLS signatures produced by different signers can be combined into a single signature that a verifier checks in one operation, with no interaction among the signers. did:julia uses this property for credential composition: issuers sign each credential individually, and a holder presenting several credentials at once combines them into a single signature. A presentation of multiple facts, for example that the subject is a human, is over 21, and holds a valid professional license, is verified as one aggregated signature. The verifier is unable to disaggregate the individual credentials out of the presentation. **Independent identity state.** Chia uses a coin model in which each coin is a discrete object carrying its own spending rules, with no shared global state. Each did:julia identity is a singleton, a coin with an id for which the chain allows one unspent instance and no more. Updating the identity spends the current coin and creates its successor under the same id, so the identity persists as a single object with an unbroken history. The coin stores its state, including the keys that control it, as curried data: values fixed into its program when the coin is created, which no other party can change. Julia Social operates no central contract in which identities reside, so no identity can be altered or frozen by Julia Social. Control of an identity rests only with the holder of its key(s). **Programmable rules and offline verification.** Chia's programming language, Chialisp, specifies the conditions under which a coin may be spent. Chialisp is a functional language: the same program given the same inputs produces the same outputs. A transaction prepared from such programs has one possible effect, the one its author wrote, and a verifier can confirm that effect in advance by requesting a few coin states from any node. did:julia encodes ownership, recovery, delegation, and revocation in the identity coin itself. Because an identity commits to the key that created it and records its own history, a verifier can confirm an identity without prior knowledge of it and without contacting a server, including when offline. The Chialisp contracts that implement the method are open source as of this document's publication, which allows independent review of the rules that govern a not.bot identity. **Concurrent operation.** A Chia mechanism called fast-forward binds the validity of a prepared transaction to the spending rules rather than to a specific coin generation: a transaction prepared against an earlier state of the identity still applies after the identity advances, provided the rules are unchanged. Several devices can prepare valid operations on one identity at the same time without conflict. **Off-chain presentation.** Singletons, fast-forward, and functional determinism combine into the capability that distinguishes did:julia: a signature that works without touching the chain. The owner of an identity prepares a spend bundle against the identity coin whose program emits a statement, the activity or content the owner chose to sign, then signs the bundle and sends it to a counterparty in place of broadcasting it. The counterparty requests a few coin states from any node and confirms that the bundle is valid, that its one possible effect is the emission of that statement, and that the identity behind the singleton signed it. Fast-forward keeps the bundle verifiable after the identity advances on chain. No transaction reaches the blockchain, no fee is paid, and the chain holds no record that the exchange took place. **Low-cost node operation.** Chia's consensus mechanism, proof of space and time, runs a full verifying node on commodity hardware rather than on specialized equipment. About 30,000 nodes operate the network, a number that follows from the low cost of joining it. A user or organization can run a node and verify identities and credentials without reliance on any third party. **Verification without observation.** The node network is a privacy mechanism as well as an availability mechanism. A verifier checking an identity selects a node at random from the tens of thousands available and connects without identifying itself. Each node answers an anonymous query against the public record, with nothing to link one query to another, so no operator can assemble a record of who verifies whom. A verifier who runs its own node closes the remaining gap: the query never leaves the verifier's hardware, and no outside party learns that the identity was used. **Consensus security.** The identity record is as trustworthy as the chain that holds it. Chia's proof of space and time pairs storage with a sequence of verifiable time proofs computed by machines called timelords. Chia Network designed and deployed ASIC timelords that compute these proofs near the physical limit, so an attacker cannot gain ground with faster hardware and must control a majority of the network's storage space to rewrite the chain. **On-chain revocation.** Revocation of a credential is recorded on the blockchain and is checkable against any node. Confirming revocation status requires no issuer-operated service and discloses nothing to the issuer or any 3rd party. ### **Comparison with other blockchains** Three blockchains illustrate why Julia Social uses the Chia blockchain rather than a better-known alternative. **Bitcoin** uses a coin model comparable to Chia's, which isolates identity state, but its scripting language cannot express the identity logic did:julia requires. **Ethereum and other account-model blockchains** are programmable but maintain state in shared accounts and contracts. An identity implemented on such a blockchain resides within a contract that some party deployed and can control, which reintroduces the central operator that a public ledger is intended to remove. Many contracts carry upgrade paths that let the deployer change the rules after users depend on them. No one can change the program of a Chia coin after the coin is created, so the owner of an identity knows at each moment what rules govern it. These blockchains also lack non-interactive signature aggregation. **Cardano** is the closest comparison, the other production blockchain with a programmable coin model. Chia remains better suited to identity in three respects. Chia's signatures aggregate credentials as a native operation, where Cardano performs the equivalent cryptography within metered scripts. A did:julia identity is a coin held directly by its owner, where identity frameworks on Cardano operate at a layer above the base ledger. And Chia supports concurrent operations on a single identity, where Cardano's model requires serialization and retry for transactions that contend for the same state. The same difference governs off-chain presentation: a prepared Cardano transaction pins the exact UTXO it spends and goes stale the moment the identity advances, where fast-forward keeps a Chia presentation verifiable against the identity's current state. For the requirements of did:julia, Chia provides as native operations what Cardano provides through additional layers. ## **not.bot and cryptocurrency** not.bot is built to use the blockchain as a database. Users do not think of an application by reference to the database it uses; the database is an implementation detail chosen for its fit to the task. An Uber rider judges the ride and gives no thought to the database behind it. Julia Social uses the Chia blockchain in the same role, as a specialized database suited to digital identity. It operates beneath the application and is not part of what the user sees. A not.bot user does not hold or transact in cryptocurrency. There is no not.bot token, and nothing in the system is bought, sold, or held for speculation. Each blockchain transaction incurs a small fee, which Julia Social supplies through a mechanism called the faucet: the fee is provided by Julia Social and bound to the user's transaction, so that the user never receives or holds any XCH, the native unit of the Chia blockchain. The user maintains no wallet, and because no asset is transferred to the user, there is no cryptocurrency receipt and no opportunity for a taxable event. The architecture does not preclude cryptocurrency use. A not.bot identity can act on the blockchain when its owner directs it to. A planned feature will allow a website to present a transaction to the not.bot app for signature by the user's identity, which supports a range of applications that includes cryptocurrency trading. The capability is available to users who want it and absent from the experience of those who do not. ## **Related documents** - **[Overview](https://not.bot/learn/overview/):** what not.bot is, across the app, Verify, and Sign My Work. - **[Identity Architecture](https://not.bot/technology/identity-architecture/):** DIDs, aliases, and the did:julia method. - **[Privacy Architecture](https://not.bot/technology/privacy/):** what Julia Social can and cannot observe. - **[Cryptographic Foundations](https://not.bot/technology/cryptographic-foundations/):** BLS signatures, aggregation, and key management. - **[did:julia Technical Specification](https://not.bot/technology/did-julia-specification/):** the method in full, for implementers. --- > **not.bot Verify: Architecture and Privacy** — https://not.bot/technology/verify-architecture/ · Markdown: https://not.bot/technology/verify-architecture.md · Updated 2026-06-14 # Architecture & Privacy Guide ## not.bot™ Verify: Architecture & Privacy Guide ## Contents 1. [Introduction](#1-introduction) 2. [Decentralized Identifiers](#2-decentralized-identifiers) 3. [System Components](#3-system-components) 4. [Architecture at a Glance](#4-architecture-at-a-glance) 5. [The Verification Flow](#5-the-verification-flow) 6. [Signature Server Identity](#6-signature-server-identity) 7. [The honest.bot Credential](#7-the-honestbot-credential) 8. [Claims and Verification Levels](#8-claims-and-verification-levels) 9. [Data Flows and Privacy](#9-data-flows-and-privacy) 10. [Operational Independence](#10-operational-independence) 11. [Support](#11-support) --- ## 1. Introduction not.bot Verify is the server-side infrastructure that connects your application to the not.bot app on users' phones. It runs entirely inside your infrastructure. No traffic from the user verification flow passes through Julia Social. This document covers the architecture, trust model, and privacy properties of not.bot Verify. For infrastructure prerequisites, see the **Pre-flight Checklist**. For the step-by-step install, see the **Deployment Checklist**. For runtime configuration, scaling, and failure modes, see the **Operations & Reference Guide**. --- ## 2. Decentralized Identifiers not.bot Verify uses Chia DIDs (Decentralized Identifiers). A DID is an identifier on the Chia blockchain. Whoever holds the corresponding private key controls the DID and can sign messages with it. Verifiers check those signatures against the on-chain record without trusting any central authority. You will work with two kinds of DIDs: - **Business DID.** You get one. It represents your company. After a DNS check, Julia Social issues a credential that ties the DID to your domain. - **Signature DIDs.** One per running signature server. The admin service maintains the pool, minting new DIDs as servers need them. Each signature server picks up an available DID at startup. Every DID's private key lives in your OpenBao instance. None of these keys leave your infrastructure. --- ## 3. System Components There are four components to not.bot Verify, plus two prerequisites. **Core components:** - **Admin service.** One instance required. It hosts the web interface where you create your business DID, register Chia nodes, and mint signature DIDs. It also reports your monthly active user count to Julia Social once an hour for billing. - **Signature server.** Run as many as you need, behind a load balancer. Each one handles user-facing verification requests. Run at least two for redundancy. - **Chia node.** Run at least one; three is recommended. Each node maintains a current view of the Chia blockchain, used by the admin service and the signature servers. Chia nodes do not mine cryptocurrency by default. - **OpenBao with the Chiakeys plugin.** OpenBao holds every DID's private key. OpenBao does not support Chia's BLS12-381 signature scheme out of the box, so the deployment includes a plugin that adds support. **Prerequisites:** - **PostgreSQL** for application data. - **Keycloak** for admin operator login. --- ## 4. Architecture at a Glance not.bot Verify runs as a set of components inside your infrastructure. Your frontend and the user's phone reach one public-facing service: your application backend, with the SDK adapter mounted, behind your existing edge. The adapter proxies the verification exchange to your signature servers over an internal path. Nothing else in the deployment is exposed to the public internet. Julia Social sits outside your perimeter, reached only for administrative operations and two hourly aggregate counts. ```mermaid --- config: layout: elk --- flowchart TB subgraph internet["Public internet"] users["End users' browsers / your frontend"] app["not.bot app (user's phone)"] end subgraph perimeter["Your security perimeter"] edge["Your existing edge: WAF / reverse proxy
(not part of Verify)"] backend["Application backend + SDK adapter
(your only public-facing service; runs outside the cluster)"] operators["Operators (internal network)"] pg["PostgreSQL (you provide)"] kc["Keycloak (you provide)"] subgraph cluster["Your Kubernetes cluster (private, no public ingress)"] adminlb["Admin LB (internal)"] admin["Admin service"] siglb["Signature-server LB (internal)
→ nginx ingress"] sig["Signature servers (load balanced)"] bao["OpenBao + Chiakeys (DID keys)"] chia["Chia nodes"] end end subgraph external["External to your perimeter"] js["Julia Social"] chianet["Public Chia network"] end users --> edge app --> edge edge --> backend backend -->|"proxies /signature/*"| siglb siglb --> sig operators --> adminlb adminlb --> admin sig <-->|"scoped token → DID keys"| bao admin --> bao sig <-->|"mTLS"| chia admin <-->|"mTLS"| chia sig --> pg admin --> pg admin <-->|"OIDC"| kc chia <-->|"peer sync"| chianet admin -->|"hourly MAU count (billing)"| js sig -->|"honest.bot credential at startup + hourly count"| js ``` --- ## 5. The Verification Flow ### From the user's perspective 1. Your application backend uses the not.bot Verify SDK to start a signature request. The SDK is a server-side library that runs in your backend. You configure it with the address of your signature server load balancer, the claims you require, and an `on_success` callback the SDK invokes when a verification completes. 2. The load balancer routes the call to one of your signature servers. That server returns a request ID. 3. The SDK wraps the request ID into a universal link URL and generates a QR code for it. Your backend delivers the URL or the QR to whatever frontend your user is looking at. 4. The user opens the link. On a phone, the universal link opens the not.bot app. On a desktop browser, the user scans the QR with their phone, which opens the not.bot app. If the app is not installed, the link sends the user to the app store. 5. The not.bot app communicates, via your SDK adapter, with the same signature server that issued the request ID. The user approves or declines inside the app. The signature server signs the response using its signature DID's key. 6. The SDK delivers the result to your backend. On success, it invokes your `on_success` callback with the verified response and the signed data. On failure, it invokes `on_failure` with the reason. Your frontend learns the outcome by polling `GET /signature/status`. At no point in this flow does any network traffic hit Julia Social. The user's phone talks only to your SDK adapter, which proxies the exchange to your signature servers. Those servers sign through your OpenBao instance and read chain state from your Chia nodes. Julia Social sees none of it. ### From your backend's perspective 1. Your frontend calls `GET /signature/notbot` on the SDK adapter. The adapter calls `POST /signature/start` on one of your signature servers through the load balancer. The signature server returns a request ID. The adapter maps the request ID to the user's session and returns the ID to your frontend. 2. Your frontend builds a universal link URL from the request ID and presents it to the user as a tappable link (on mobile) or a QR code (on desktop). If the user does not have the not.bot app installed, the link redirects them to the appropriate app store. 3. The not.bot app opens and connects to your SDK adapter's endpoints. The cryptographic exchange happens across `POST /signature/notbot/{request_id}`, `POST /signature/verify/{request_id}`, and the WebSocket routes. The adapter proxies each call to your signature servers. Your backend code does not participate in this exchange. 4. When verification succeeds, the adapter calls your `on_success` callback with the verified response and the original session. The response contains the user's alias DID, any claims you requested, the Site Pass (if enabled), a timestamp, and the cryptographic presentation. 5. Your frontend can poll `GET /signature/status` or use its own signaling mechanism to detect that verification completed, then update the UI. ### Network path During the verification exchange, traffic flows between the user's phone and your signature servers through your SDK adapter. No packets reach Julia Social at any point. The user's phone never contacts Julia Social. Your signature servers never contact Julia Social. The entire exchange stays within your infrastructure and the user's device. ### Session behavior The adapter maps each request ID to the session that initiated it. When verification completes, the adapter looks up the originating session and passes it to your `on_success` callback, even if the verification response arrives on a different HTTP connection (which it will, since the not.bot app is a separate client). This is how the verified result ends up in the correct user's session despite the verification being completed by a different device. The request-to-session mapping lives in memory in the adapter process. If you run multiple instances of your backend behind a load balancer, you will need sticky sessions or a shared session store so that the verification response routes back to the adapter instance that holds the mapping. --- ## 6. Signature Server Identity ### DID assignment at startup When a signature server starts up, it contacts the admin service and asks for an assignment. The admin service hands back an unused signature DID and a scoped OpenBao token for that DID's key. The business DID then delegates your domain credential to the signature server's DID, which is what lets the signature server present proof that it represents your domain. ### Heartbeat and release While running, each signature server sends a heartbeat to the admin service. On clean shutdown, the signature server releases its DID back to the pool. If heartbeats stop, the admin service releases the DID after a timeout. It is not possible for two running processes to hold the same signature DID at once. ### Scaling Your scale ceiling is your replica count and HPA configuration. The signature DID pool auto-sizes: the admin service maintains at least two unallocated DIDs at all times and mints a replacement whenever a signature server consumes one. Operators do not size the pool. --- ## 7. The honest.bot Credential Each signature server acquires an honest.bot™ credential from Julia Social at startup, bound to the server's signature DID. Julia Social enforces that only one process in the world holds a given honest.bot credential at a time. This is defense in depth against a compromise of a signature server's signing access. OpenBao is your first line of defense. A signature DID's private key lives in OpenBao and never enters the signature server process; the server signs by calling OpenBao with a scoped token, so a compromised server holds no raw key to copy. The honest.bot credential covers the residual risk. An attacker who gets far enough to use a server's OpenBao access, its signature DID, and your domain credential could stand up a server that presents as your site, and users would extend it the trust they extend you. The single-process enforcement closes that gap. The moment the attacker's instance comes up, that enforcement revokes the legitimate server's honest.bot credential. A credential that stops validating means your signing identity is in use somewhere you did not put it, so the revocation is your signal that a compromise has occurred. Today that detection is the protection: the revoked credential tells you the access has leaked. An attacker who reached your OpenBao instance holds your business DID key as well, so the response resets the business DID that sits above your signature DIDs and re-establishes fresh credentials down the chain, rendering the attacker's instance useless. This response is planned, not yet implemented. The not.bot app verifies the honest.bot credential on every interaction without contacting Julia Social, so this protection adds no round-trip at verification time. Acquiring the credential is the one reason a signature server contacts Julia Social at startup. After that, a running server serves verifications with no further Julia Social involvement (see Section 10). --- ## 8. Claims and Verification Levels The SDK defines claim properties for bot detection (`Notbot0`), age verification (`AgeOver18`, `AgeOver21`, and a full range of age brackets), PII fields (`FirstName`, `FamilyName`, `Nationality`), and Site Passes (`SitePass`). The full list of available claims is in `shared/claim_properties.txt` in the SDK repository. **Site Passes.** When `require_site_pass` is enabled, the verification generates a Site Pass: a per-user-per-site identifier that lets you recognize returning users without learning their real identity. ### Verification levels A claim's verification level tells you how strongly the person behind it was identity-proofed at enrollment. - **Notbot0** (available now). The user scanned the NFC chip in a government passport; the app read the chip and a certified identity-verification partner validated its signatures against the ICAO Public Key Directory. This is the level behind every not.bot verification today. - **Notbot1** (planned). The user was proofed in person at a third-party enrollment partner following NIST SP 800-63A IAL2 procedures. - **Notbot2** (planned). The user was proofed at a first-party facility contracting directly with Julia Social. Every Verify deployment operates at Notbot0 today. Notbot1 and Notbot2 are on the roadmap. --- ## 9. Data Flows and Privacy ### What leaves your infrastructure Two outbound data flows reach Julia Social, both on a scheduled cadence: - The admin service sends your monthly active user count once per hour for billing. The count is a single integer. No user identifiers, IP addresses, request details, or session data accompany it. - Each signature server sends the count of successful signature requests once per hour for diagnostics on Julia Social's side. Again, a single integer. No request content, user data, or signature payloads are included. These two integers are the sum total of what Julia Social receives from your deployment. ### What stays inside Everything else. User verification requests, the cryptographic exchange between the not.bot app and your signature servers, the signed responses, the verified results the SDK passes to your backend, DID keys, database records, session state, Chia blockchain queries. All of it stays within your infrastructure and the user's device. No packet from the user verification flow reaches a Julia Social server. ### Julia Social is not a supply-chain data risk No customer data, user data, request content, or signature payloads flow to Julia Social at any point, whether during setup, normal operation, or failure. The two hourly counts described above are aggregate integers with no identifying information attached. There is no telemetry, no analytics pipeline, no log shipping, and no crash reporting directed at Julia Social. Your DID keys live in your OpenBao instance. Your user records live in your PostgreSQL instance. Your Chia nodes sync from the public blockchain, not from Julia Social. The SDK runs in your backend. The not.bot app talks to your signature servers. Julia Social has no access to any of it. --- ## 10. Operational Independence ### Julia Social is not a runtime dependency A running not.bot Verify deployment does not depend on Julia Social for day-to-day operation. Your signature servers contact Julia Social at startup to acquire the honest.bot credential (see Section 7), and then never again except for the hourly diagnostic count. Once a signature server has its credential, it serves verification requests with no further Julia Social involvement. If Julia Social becomes unreachable: - **Running signature servers continue to operate.** Existing honest.bot credentials remain valid. Users continue to verify. Your application backend continues to receive results. - **New signature servers cannot start** because they cannot acquire the honest.bot credential. If you need to scale up or replace a crashed server during a Julia Social outage, the replacement blocks at the credential acquisition step until connectivity returns. - **The admin service's hourly MAU report queues and retries.** No data is lost; the counts catch up once the connection resumes. - **The admin interface remains usable.** You can still log in, view status, and manage blockchain nodes. The only operations that require Julia Social are the initial deployment-config upload, domain credential issuance and signature DID minting, none of which are needed for steady-state processing. In short: Julia Social connectivity matters during initial setup and when starting new signature servers. For a running deployment, it does not matter at all. --- ## 11. Support Email [support@julia.social](mailto:support@julia.social) for deployment issues, configuration questions, or credential reissuance. --- > **not.bot Verify: Preflight Checklist** — https://not.bot/technology/verify-preflight-checklist/ · Markdown: https://not.bot/technology/verify-preflight-checklist.md · Updated 2026-06-11 # Pre-flight Checklist ## not.bot™ Verify: Pre-flight Checklist Complete every item before you open the Deployment Checklist. Missing prerequisites cause most first-deploy failures. --- ### Infrastructure | # | Requirement | How to verify | Done | |---|-------------|---------------|------| | 1 | Kubernetes cluster with a configured kubectl context | `kubectl cluster-info` returns a running control plane | ☐ | | 2 | Helm 3 installed | `helm version` shows v3.x | ☐ | | 3 | helm-diff plugin installed | `helm plugin list` includes `diff` | ☐ | | 4 | PostgreSQL 14 or later, reachable from inside the cluster | `psql -h -U -c "SELECT version();"` shows 14+ | ☐ | | 5 | Keycloak 22 or later, reachable from inside the cluster | Browse to your Keycloak admin console and confirm login | ☐ | | 6 | A container registry your cluster can pull from | `docker pull /any-existing-image` succeeds | ☐ | | 7 | Cluster supports internal LoadBalancer Services | Managed K8s (EKS/GKE/AKS) supports this by default. On bare-metal, `kubectl get pods -n metallb-system` shows running pods | ☐ | ### Workstation tools | # | Requirement | How to verify | Done | |---|-------------|---------------|------| | 8 | openssl | `openssl version` returns a version | ☐ | | 9 | OpenBao CLI (`bao`) installed | `bao --version` returns a version | ☐ | > If you intend to rebuild the OpenBao image from source for supply-chain validation, also install Docker with buildx. See Deployment Checklist Appendix A. The mainline flow uses the pre-built image shipped in the chart and requires no compiler toolchain. ### Access | # | Requirement | How to verify | Done | |---|-------------|---------------|------| | 10 | DNS control for the domain in your deployment-config.json | You can add a TXT record at the root of that domain | ☐ | | 11 | DNS control for the internal zone holding your admin service hostname | You can add a CNAME for Decision H in that zone | ☐ | | 12 | Permission to create namespaces in the Kubernetes cluster | `kubectl auth can-i create namespaces` returns `yes` | ☐ | | 13 | Permission to create secrets in the Kubernetes cluster | `kubectl auth can-i create secrets` returns `yes` | ☐ | ### Deployment package | # | Requirement | How to verify | Done | |---|-------------|---------------|------| | 14 | deployment-config.json from your welcome email | File contains your customerId, organizationName, apiKey, billingServerUrl, and domain | ☐ | | 15 | not.bot_verify_deployment.zip from your welcome email | Unzips to a `helm/` directory with three subdirectories: admin-service, openBao, signer-service | ☐ | ### Decisions to make before you start You will need these values during deployment. Decide on them now so you are not stopping mid-checklist. | # | Decision | Your value | |---|----------|------------| | A | Kubernetes namespace for OpenBao | _______________ | | B | Kubernetes namespace for the admin service | _______________ | | C | Kubernetes namespace for signature servers | _______________ | | D | OpenBao namespace name (internal to OpenBao, not Kubernetes) | _______________ | | E | PostgreSQL database name | _______________ | | F | PostgreSQL admin user — name (default `notbot_admin`) and password | name: _______________ password: _______________ | | G | PostgreSQL signer user — name (default `notbot_signer`) and password | name: _______________ password: _______________ | | H | Internal hostname operators use to reach the admin UI (e.g. admin.internal.example.com) | _______________ | | I | Internal hostname for the signature server load balancer (e.g. signer.internal.example.com) | _______________ | | J | TLS certificate for the admin LB (cloud-managed cert ARN/resource ID, or path to BYO cert + key) | _______________ | | K | TLS certificate for the signature server LB (Decision **I**'s hostname). May be the same multi-SAN cert as Decision **J** or a separate cert. | _______________ | Decision H appears in Keycloak redirects, Helm values, and your internal DNS zone. Decision I appears in Helm values, your internal DNS zone, and the SDK configuration. Use the exact same value everywhere each one appears. --- If any item above is incomplete, resolve it before proceeding. The Deployment Checklist assumes all of these are in place. --- > **not.bot Verify: Deployment Checklist** — https://not.bot/technology/verify-deployment-checklist/ · Markdown: https://not.bot/technology/verify-deployment-checklist.md · Updated 2026-06-11 # Deployment Checklist ## not.bot™ Verify: Deployment Checklist Complete the Pre-flight Checklist before you start. Each phase below assumes the previous phase is done. Open the Operations & Reference Guide alongside this document if you need context for any step. Pre-flight decision labels (A through K) appear throughout. Fill in the value you wrote down in the Pre-flight Checklist wherever you see one. --- ## Phase 1: OpenBao ### 1.1 Install the OpenBao chart The OpenBao image shipped in the chart (`harbor.juliasocial-dev.com/library/openbao-bls`, pinned by digest) already has the Chiakeys plugin baked in. No build step is required for the mainline deployment. If you need to rebuild the image from source for supply-chain validation, see Appendix A. ```bash unzip not.bot_verify_deployment.zip cd helm/openBao helm dependency update kubectl create namespace cd ../.. helm install openbao ./helm/openBao -n ``` **Verify:** `kubectl get pods -n ` shows the openbao pod Running. ### 1.2 Initialize and unseal ```bash kubectl port-forward svc/openbao 8200:8200 -n ``` In a second terminal: ```bash bao operator init -key-shares=1 -key-threshold=1 ``` Save the **Unseal Key** and **Root Token** in your break-glass secret store. Losing the unseal key destroys the data in OpenBao. ```bash bao operator unseal read -rs -p "Enter Token: " && echo "$REPLY" | bao login - ``` > **OpenBao reseals on every pod restart.** Keep the unseal key accessible to whoever is on call. Consider OpenBao auto-unseal if your environment supports it. ### 1.3 Create the secrets engine, namespace, and scoped token ```bash bao namespace create export VAULT_NAMESPACE= bao secrets enable -path=chiakeys bls bao secrets enable -path=secret -version=2 kv ``` > The `secret` KV-v2 engine holds non-DID secrets that the admin service writes during normal operation — for example, the CA cert and key pair you upload when registering a Chia node in §6.2 are stored at `secret/data/blockchain-nodes//certificate`. The path name `secret` is fixed; the admin service is not configurable here. Create `policy.hcl`: ```hcl path "chiakeys/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "secret/data/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "secret/metadata/*" { capabilities = ["create", "read", "update", "delete", "list"] } ``` Apply and create the scoped token: ```bash bao policy write -policy policy.hcl bao token create -policy=-policy -orphan -ttl=720h ``` Save the token. You will use it in Phase 5 (admin service) and never the root token. > **`-orphan` is required.** Without it, the new token is a child of the root token, and §1.4's `bao token revoke -self` cascades the revocation to every child — invalidating this scoped token before the admin service ever uses it. The failure surfaces later, when the admin service first writes to OpenBao, as a misleading `permission denied` on the chiakeys path. `-orphan` detaches the token so it survives the root revocation. > > `-ttl=720h` (30 days) gives you a renewal window long enough to cover the deployment timeline. The default TTL in some OpenBao configurations is short enough to expire before you finish. ### 1.4 Revoke the root token ```bash bao token revoke -self rm -f ~/.vault-token ``` --- ## Phase 2: PostgreSQL Connect to your PostgreSQL instance as a superuser and run: Below, ``/`` refer to the admin user name and password from Decision **F**, and ``/`` refer to the signer user name and password from Decision **G**. The default names are `notbot_admin` and `notbot_signer`; you may keep them or substitute your own. ```sql CREATE USER WITH PASSWORD ''; CREATE USER WITH PASSWORD ''; CREATE DATABASE OWNER ; ``` Grant the signer user read/write on tables created by the admin user (the admin service creates the schema on first startup): ```sql \c ALTER DEFAULT PRIVILEGES FOR ROLE GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ; ALTER DEFAULT PRIVILEGES FOR ROLE GRANT USAGE, SELECT ON SEQUENCES TO ; GRANT USAGE, CREATE ON SCHEMA public TO ; ``` > The current signature server runs its own database migrations at startup. That means the signer user needs `CREATE` on the target schema until the migration ownership model is changed. Without this grant, Phase 8 fails on PostgreSQL 15+ with `permission denied for schema public` while the signer runs migrations. **Verify:** `psql -h -U -d -c "SELECT 1;"` succeeds with password **F**, and the same with `` and password **G**. --- ## Phase 3: Keycloak In your Keycloak admin console: 1. Create realm `admin-service`. 2. In that realm, create client `admin-service` with: - Client authentication: **ON** - Valid redirect URIs: `https:///*` - Web origins: `https://` 3. Open the client's Credentials tab and copy the client secret. 4. Create at least one user in the realm. Set **all** of: username, email, first name, last name, password. Mark **Email verified: ON** and **Temporary password: OFF**. Modern Keycloak realms require `email`, `firstName`, and `lastName` by default for any user with the `user` role; missing any of these causes the eventual login (Phase 6.1) to fail with a misleading `invalid_grant` / `Account is not fully set up` error. Decision **H** is the admin UI hostname. The redirect URI must use the same hostname you will set in `app.baseUrl` and the admin-service ingress later. --- ## Phase 4: Chia node The Chia node charts live in a public repo. Read `readme.md` in that repo for chart-level detail. ### 4.1 Generate the private CA ```bash openssl genrsa -out private_ca.key 4096 openssl req -x509 -new -nodes -key private_ca.key -sha256 -days 3650 \ -out private_ca.crt \ -subj "/C=US/ST=Private/L=Private/O=Chia/OU=RPC/CN=Chia Private CA" chmod 600 private_ca.key chmod 644 private_ca.crt ``` Use the same CA and key on every Chia node. You will upload them again in Phase 6 when you register each node. ### 4.2 Build and push the node image ```bash git clone https://github.com/GalactechsLLC/helm-chia-nodes.git cd helm-chia-nodes DOCKER_REPO="/path" ./docker_build.sh ``` ### 4.3 Create the environment values file ```bash cd helm/chia-node ``` Create a new file named `values-.yaml`. The suffix is yours to pick (commonly `my-mainnet`); the file does not exist in the repo — you are creating it. The README in the helm-chia-nodes repo documents the full values structure; the minimum overrides for not.bot Verify are: ```yaml chia-blockchain: nameOverride: "chia-node" fullnameOverride: "chia-node" image: repository: "/path" tag: "" chia: ca: private_ca_crt: | -----BEGIN CERTIFICATE----- ...contents of private_ca.crt... -----END CERTIFICATE----- private_ca_key: | -----BEGIN PRIVATE KEY----- ...contents of private_ca.key... -----END PRIVATE KEY----- ``` > **Block scalar indentation must be consistent.** Every line of the cert and key sits at the same indent under the field name. Wrong indentation produces a pod restart loop. > **Volume size.** The chart's default `volume.size` is `500Gi`. See Operations & Reference Guide §5.6 for sizing context before changing this. Mainnet first-sync briefly co-locates a 121 GiB compressed checkpoint and the SQLite it extracts to — a smaller PVC will run out of space during extraction. ### 4.4 Create the namespace, update dependencies, diff, and deploy The deploy scripts read `CI_NAMESPACE` from `helm/env`, which ships with `CI_NAMESPACE="infrastructure"`. Create that namespace before running the scripts. If you want a different namespace, edit the env file first and create whatever you chose instead. > not.bot Verify operates on Chia mainnet only. The upstream `helm-chia-nodes` repo ships a separate `helm/env_testnet` file for testnet deploys — do not use it. Stick with `ENV_FILE=./env`. ```bash kubectl create namespace infrastructure cd .. # back to helm/ CI_ENVIRONMENT= ENV_FILE=./env ./update-chart.sh CI_ENVIRONMENT= ENV_FILE=./env ./diff.sh CI_ENVIRONMENT= ENV_FILE=./env ./upgrade.sh ``` > The upstream scripts include a `Is the Above Correct? [y/N]` confirmation prompt. If you run them over a non-interactive shell (SSH without `-t`, CI pipeline, etc.) they will hang waiting for input. Either run from an interactive terminal, or pipe `yes y` to each: > > ```bash > yes y | CI_ENVIRONMENT= ENV_FILE=./env ./upgrade.sh > ``` **Verify:** ```bash kubectl get pods -n infrastructure kubectl logs -f -n infrastructure ``` The pod reaches Running within a minute or two. A restart loop usually points at malformed CA YAML or a missing storage volume. ### 4.5 Wait for chain sync The first deploy downloads a checkpoint from `torrents.chia.net` and walks forward to chain head. You cannot create the business DID or mint signature DIDs against an out-of-sync node. Continue deploying the admin service while this runs; sync only blocks the on-chain steps in Phase 6. For redundancy, repeat steps 4.3 and 4.4 with a separate values file and release name to bring up additional nodes. Use the same private CA on each. --- ## Phase 5: Admin service ### 5.1 Extract and configure ```bash cd helm/admin-service ``` Open `values.yaml`. Fill in these blocks. Sensitive values are supplied through a Kubernetes Secret you create in §5.2; the chart references that Secret with `*SecretKeyRef` fields and does not render plaintext production credentials into its own Secret. ```yaml database: url: "jdbc:postgresql://:5432/" username: "" adminPasswordSecretKeyRef: name: "admin-service-secrets" key: "POSTGRES_PASSWORD" signerDatabase: host: "" port: 5432 database: "" username: "" passwordSecretKeyRef: name: "admin-service-secrets" key: "SIGNER_DB_PASSWORD" keycloak: issuerUri: "http://keycloak..svc.cluster.local:8080/realms/admin-service" externalUrl: "https://" clientId: "admin-service" clientSecretSecretKeyRef: name: "admin-service-secrets" key: "KEYCLOAK_CLIENT_SECRET" openbao: enabled: true addr: "http://openbao..svc.cluster.local:8200" namespace: "" tokenSecretKeyRef: name: "admin-service-secrets" key: "OPENBAO_TOKEN" app: baseUrl: "https://" environment: "production" springProfile: "prod" juliaServer: host: "identity.julia.social" port: 443 secure: true baseUrl: "" # empty derives from host/port/secure ``` If you use a different Kubernetes Secret name or key names in §5.2, update the four `*SecretKeyRef` blocks above to match. **TLS trust:** the admin service fetches Keycloak's JWKS over HTTPS, so the JVM must trust whatever CA signed your Keycloak's cert. Public CAs (Let's Encrypt, DigiCert, etc.) are already trusted — no action needed. **Internal CAs** (corporate PKI, self-signed for evaluation) require adding the CA's public cert to the chart's `extraCaCerts` map: ```yaml extraCaCerts: my-internal-ca: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- ``` The chart's init container builds a custom JVM trust store containing both the image's default cacerts and any entries you list here. Leave `extraCaCerts` empty if Keycloak's cert is from a public CA. See Appendix B for the single-VM evaluation flow. > `issuerUri` is what the admin service backend uses to fetch Keycloak's public keys. It must point at *your* Keycloak — Keycloak is a prerequisite you provide, not part of not.bot Verify, so substitute `` and the service name with wherever your Keycloak actually lives. Examples: > > - In-cluster Keycloak in namespace `identity`: `http://keycloak.identity.svc.cluster.local:8080/realms/admin-service` > - External Keycloak (managed, on another cluster, etc.): `https://keycloak.example.com/realms/admin-service` — drop the cluster.local suffix and use HTTPS if exposed publicly > - Single-VM Appendix B deployment: `https://keycloak.your-domain.example/realms/admin-service` — must match the `KC_HOSTNAME` Keycloak is started with in §B.10 (Keycloak stamps that into every token's `iss` claim). The admin pod resolves this hostname to the in-cluster Keycloak via the CoreDNS hosts override (§B.12) and trusts the local CA via `extraCaCerts` (§B.13 §5.1). Do **not** point `issuerUri` at the `cluster.local` ExternalName here — the issuer claim would not match and login would fail. > > `externalUrl` is what the operator's browser hits during login (must be HTTPS). A mismatch between the issuer claim in tokens Keycloak issues and the `issuerUri` here is the most common login failure. If logins fail with an issuer error, decode the JWT (e.g. jwt.io offline mode) and read the `iss` claim — `issuerUri` must equal whatever you find there. ### 5.2 Expose on the internal network Operators reach the admin service through a `LoadBalancer` Service annotated for internal-only placement. The cloud provider provisions a private endpoint with a stable hostname; you point your internal DNS at it. > **Single-VM / non-cloud deployments:** the cloud-LB annotations below don't apply. See Appendix B for the ingress-nginx + local CA path (set `service.type: ClusterIP` and define an Ingress). Create the namespace and the Secret referenced by §5.1: ```bash kubectl create namespace kubectl create secret generic admin-service-secrets -n \ --from-literal=POSTGRES_PASSWORD='' \ --from-literal=SIGNER_DB_PASSWORD='' \ --from-literal=KEYCLOAK_CLIENT_SECRET='' \ --from-literal=OPENBAO_TOKEN='' ``` > The shipped admin-service image (`harbor.juliasocial-dev.com/library/admin-service`) is in Harbor's public `library` namespace and pulls anonymously. No `imagePullSecret` is needed for the mainline deployment. If you mirror the image into a private registry, create a docker-registry Secret in namespace **B** and set `imagePullSecret` in `values.yaml` to its name. In `values.yaml`, set the service to `LoadBalancer` and add the internal-LB annotation for your cloud provider. Uncomment one: ```yaml service: type: LoadBalancer annotations: # AWS: service.beta.kubernetes.io/aws-load-balancer-scheme: "internal" # GKE: networking.gke.io/load-balancer-type: "Internal" # Azure: service.beta.kubernetes.io/azure-load-balancer-internal: "true" ``` After install (step 5.3), get the LB's private hostname: ```bash kubectl get svc admin-service -n ``` Create a CNAME in your internal DNS pointing **H** at that hostname. The hostname must match `app.baseUrl` from step 5.1 and the Keycloak redirect URIs from Phase 3. > TLS terminates at the LB. Add the certificate from Decision **J** to the `service.annotations` block above using your provider's annotation (`aws-load-balancer-ssl-cert` on AWS, managed cert resource on GCP, listener configuration on Azure). The admin service inside the pod serves plain HTTP on 8080. ### 5.3 Install and verify ```bash cd ../.. helm install admin-service ./helm/admin-service -n ``` **Verify:** ```bash kubectl get pods -n -l app.kubernetes.io/name=admin-service kubectl logs -n -l app.kubernetes.io/name=admin-service ``` Initial startup takes about 40 seconds. A pod stuck in `CrashLoopBackOff` traces back to one of the upstream dependencies; the log names which. Browse to `https://`. The Keycloak login page appears. Do not log in yet. Phase 6 covers first login. --- ## Phase 6: Business identity setup Confirm before starting: - At least one Chia node from Phase 4 reports synced. - You have DNS control for the `domain` value in your `deployment-config.json`. - You have an operator account in the Keycloak realm from Phase 3. ### 6.1 First login Browse to `https://`. Click Login. Authenticate through Keycloak with the operator account. The dashboard shows the deployment as unconfigured. ### 6.2 Register Chia nodes Register your Chia node(s) before uploading `deployment-config.json`. The admin UI rejects the upload until at least one blockchain node is configured, because the upload triggers an on-chain transaction (business DID creation) that needs a node to broadcast through. For each node from Phase 4, open Blockchain → Add Node and fill in: - **Host or IP Address:** the in-cluster DNS name where the node's full_node RPC is reachable (e.g. `chia-node.infrastructure.svc.cluster.local`). - **Port:** `8555` (Chia mainnet full_node RPC). - **CA Certificate (PEM Format):** paste the contents of `private_ca.crt` from §4.1. Either paste the PEM block directly or use the "Upload .crt file" button. - **Private Key (PEM Format):** paste the contents of `private_ca.key` from §4.1. This is the **CA's private key**, not a client key. The admin service uses the CA cert+key as material to mint short-lived client certificates when it calls the chia node's RPC, and to delegate the same capability to your signature servers later. Treat this file with the same care as any private CA key. The form also shows a `Network` row (read-only display, always "Mainnet" — not.bot Verify is mainnet-only) and a `Use Secure Connection (SSL/TLS)` checkbox that is pre-checked and disabled (the chia full_node RPC is mTLS-only, so SSL is mandatory). Neither requires operator action; the CA Certificate and Private Key fields below are what you actually fill in. > The chia full_node TLS certificate's only Subject Alternative Name is `DNS:chia.net` — a Chia design convention. The admin service handles this internally (overriding SNI to `chia.net` regardless of the Host you provide above). Generic HTTP clients connecting to chia full_node RPC would need to do the same; you do not need to configure anything for the admin service itself. Wait until at least one node shows "synced" in the admin UI before continuing. The on-chain transaction in §6.3 requires a synced node. See Operations & Reference Guide §5.2 for what "synced" means and how long the first sync takes. ### 6.3 Upload deployment-config.json In the admin interface, upload your `deployment-config.json`. The admin service contacts the billing server to register the deployment, which consumes the one-time API key from the file. > **The API key is one-time-use, and ANY upload error consumes it.** If the upload returns an error — whether the message says "Billing service is currently experiencing issues" (transient-looking), `customerId or organizationName not recognized`, or anything else — the key is consumed upstream regardless of what the error suggests. Retrying with the same `deployment-config.json` will always fail. Email `support@julia.social` for a re-issued welcome email containing a fresh key, then retry with the new file. Common upload failures and what they actually mean: - **The cluster cannot reach `billingServerUrl` over HTTPS.** Fix egress, then request a re-issue. - **"Billing service is currently experiencing issues" (or similar 5xx-ish wording).** The upstream registration failed *after* the key was consumed. The error sounds transient but is permanent on your side — request a re-issue. - **`customerId` or `organizationName` does not match Julia Social's records.** Stop and contact support before retrying — your welcome email may have been generated incorrectly. - **"You must register at least one blockchain node before uploading deployment-config.json"** (or similar). You skipped §6.2 — go back and register a Chia node first, then re-upload. ### 6.4 Verify the business DID appeared The §6.3 upload triggers business DID creation automatically — the admin service generates a BLS12-381 keypair in OpenBao and submits the DID transaction through a registered node. You don't click anything; the work happens in the background. Open Business Identity in the admin UI and confirm the business DID is listed. It typically appears within a couple of minutes of the upload completing. If it's not visible after five minutes, check the admin-service logs for the on-chain transaction submission: ```bash kubectl logs -n -l app.kubernetes.io/name=admin-service | grep -i "business.*did" ``` Common reasons the DID does not appear: the registered Chia node fell out of sync between §6.2 and §6.3 (check Blockchain → node status), OpenBao sealed or unreachable (check `kubectl get pods -n ` and the chiakeys path with `bao secrets list`), or the admin service failed to write through the Vault path (look for `permission denied` in the logs — likely a policy or KV-v2 mount issue from §1.3). ### 6.5 Verify the domain The admin interface displays a "Verify Domain" button. Clicking it opens a modal that walks through the DNS step. Under "Step 1: Add DNS Record" the modal shows the complete TXT record value (the `julia-did=` prefix plus the full DID) with a copy button — paste that value into a TXT record at the apex of your domain. Wait for propagation. Confirm with: ```bash dig +short TXT ``` The output starts with `julia-did=`. Click Verify Domain in the admin interface. If verification fails: check the value is character-for-character identical (some DNS UIs add quotes or split long values), wait longer for propagation, and retry. Leave the TXT record in place. --- ## Phase 7: Signature DID pool The admin service maintains a pool of unallocated signature DIDs (target of at least two) in the background. DIDs are minted via Julia's identity service and recorded on chain. The pool refills automatically as signature servers consume DIDs at startup; you do not provision the pool manually. **Verify:** open Signature DIDs in the admin UI and confirm at least one DID is listed with state "available." If you see zero DIDs more than five minutes after the §6.3 upload completes, check the admin-service logs for Julia identity service errors (look for `POST request to Julia service endpoint: /new_signature_did` or similar). If your admin UI build still exposes an **Add Signature DID** button and the pool has not populated automatically, click it once as an interim fallback, then confirm the new DID appears as available. --- ## Phase 8: Signature servers ### 8.1 Configure ```bash cd helm/signer-service ``` Edit `values.yaml`: The signer needs a small bootstrap config — enough to contact the admin service at startup, after which it receives the rest of its config (DID assignment, OpenBao token, database credentials, Chia node info with TLS material) from the admin's `/admin/signatureServerSetup` response. The chart's values: ```yaml deployment: name: julia-signer replicaCount: 2 image: repository: "harbor.juliasocial-dev.com/library/julia_signer" tag: "build_1776796141" pullPolicy: Always service: targetPort: 8080 adminService: hostname: "admin-service..svc.cluster.local" port: 8080 secure: false chiaNetwork: "Mainnet" rustLog: "info" apiKeySecret: name: "julia-signer-secrets" key: "API_KEY" ingress: enabled: true hosts: - host: paths: - /(/+)?(.*) tls: - hosts: - secretName: signer-tls ``` **Retrieve the API key value from the admin database.** The admin service generates a `businesses.api_key` row when you complete §6.3. There is no admin-UI surface for this value today, so you must query Postgres directly: ```bash psql -h -U -d -c "SELECT api_key FROM businesses LIMIT 1;" ``` The value begins with `ltk_`. Create the signer Secret in namespace **C** with that value: ```bash kubectl create secret generic julia-signer-secrets \ --from-literal=API_KEY='' \ -n ``` The chart reads that same Secret key into both env vars the signer requires: `ADMIN_API_KEY` (signer → admin authentication) and `API_KEY` (SDK adapter / not.bot app → signer authentication). This direct database query is an interim bootstrap path; a future release will move this credential to OpenBao-mediated setup so operators do not handle it. The signer Ingress terminates TLS at the cluster edge using a pre-created Kubernetes TLS Secret. Create the Secret in the signer namespace (**C**) from Decision **K**: ```bash kubectl create secret tls signer-tls \ --cert= \ --key= \ -n ``` For cloud-managed certs (ACM, GCP managed cert) you have an alternative path: terminate TLS at a cloud LB above the Ingress and leave `tls: []` empty here. Decision **K**'s answer dictates which path to use. > **Do NOT set `CHIA_FULL_NODE`, `CHIA_FULL_NODE_PORT`, `CHIA_FULL_NODE_SSL`, `PRIVATE_CA_CRT`, or `PRIVATE_CA_KEY` as overrides.** The binary populates these itself from the admin response after startup. Setting `CHIA_FULL_NODE_SSL` in particular switches the TLS path from inline-PEM-from-admin (correct) to filesystem-paths (broken — the binary fails with `No such file or directory` looking for cert files that aren't there). ### 8.2 Install ```bash kubectl create namespace cd ../.. helm install julia-signer ./helm/signer-service -n ``` > The shipped signer image (`harbor.juliasocial-dev.com/library/julia_signer`) is in Harbor's public `library` namespace and pulls anonymously. No `imagePullSecret` is needed. Point internal DNS for **I** at your nginx ingress controller's internal address. This ingress is internal-only, reached by your SDK adapter, the same posture as the admin LB in Phase 5. It is not exposed to the public internet. > **Single-VM / non-cloud deployments:** use the local CA-signed cert from Appendix B §B.8 to create the `signer-tls` Secret in namespace **C** (the cert from §B.8 already covers Decision **I**'s hostname). Run the `kubectl create secret tls` command from §8.1 above, pointing `--cert` and `--key` at `/etc/verify-test/certs/server.crt` and `server.key` respectively. ### 8.3 Verify ```bash kubectl get pods -n -l app.kubernetes.io/name=julia-signer kubectl logs -n -l app.kubernetes.io/name=julia-signer ``` The startup log shows DID assignment, OpenBao connection, database connection, domain credential delegation, and honest.bot™ credential acquisition. A failed step names itself. Common causes: - No available DIDs in the pool. The admin service mints to maintain the pool; if minting is failing, check that at least one Chia node is synced and OpenBao is unsealed. - OpenBao sealed or unreachable. Unseal, check NetworkPolicies. - Admin service unreachable from the signer namespace. Check service DNS and policies. - Cannot reach Julia Social. Check egress. In the admin interface, Signature DIDs → the DID this server picked up shows "Assigned" with a recent heartbeat timestamp. --- ## Phase 9: SDK integration The SDK runs in your application backend, not in the cluster. Languages: Rust, JavaScript (Express), Python (FastAPI), Java (Spring MVC), Dart (shelf). Repo: `https://github.com/julia-social/julia_web_sdk`. Set three environment variables on the host running your backend: ```bash SIGNATURE_HOSTNAME= SIGNATURE_PORT=443 SIGNATURE_API_KEY= ``` > `SIGNATURE_HOSTNAME` must be the signature server load balancer (Decision **I**), not the host running the SDK adapter. Pointing both at the same host loops the WebSocket proxy back on itself. Build the adapter for your framework following the SDK readme. Configure `request_claims`, `require_site_pass`, `message_generator`, `on_success`, `on_failure`, and `expire_time`. Mount the adapter's router into your web application. **Verify:** call `GET /signature/notbot` from your frontend. The adapter returns a request ID. Build a universal link from it, scan with the not.bot app, complete a verification. Your `on_success` callback fires with the verified response. --- ## Done Your deployment is complete. The Operations & Reference Guide covers monitoring, alerting, scaling, failure modes, and troubleshooting for each component. --- ## Appendix A: Rebuilding the OpenBao image from source The chart's default image (`harbor.juliasocial-dev.com/library/openbao-bls`, pinned by digest) ships with the Chiakeys plugin (`vault-plugin-secrets-bls`) baked in. The mainline deployment uses it directly. This appendix is for customers who need to rebuild the image from source — for example, to audit the plugin's provenance against a supply-chain review, or to mirror the image into an internal registry. ### A.1 Build environment You need: - Docker with buildx (`docker buildx version`) - Outbound access to `github.com` (to clone the plugin) and `docker.io` (to pull `openbao/openbao:2.5.2` and `golang:1.22-alpine`) You do **not** need Go or a C toolchain on your host. The Dockerfile below compiles the plugin inside an Alpine container so the resulting binary links against musl libc (matching the OpenBao runtime image) and uses a pinned Go version. Building on a glibc host (Ubuntu, Debian, RHEL) and copying the binary into the Alpine runtime image produces a binary that fails to load. ### A.2 Multi-stage Dockerfile Create a file named `Dockerfile`: ```dockerfile # Build stage — Alpine + pinned Go + C toolchain (cgo for blst) FROM golang:1.22-alpine AS build RUN apk add --no-cache git build-base WORKDIR /src RUN git clone https://github.com/mintgarden-io/vault-plugin-secrets-bls.git . WORKDIR /src/cmd/vault-plugin-secrets-bls ENV CGO_ENABLED=1 RUN go build -o /out/vault-plugin-secrets-bls # Runtime stage — OpenBao with the plugin baked in FROM openbao/openbao:2.5.2 COPY --from=build /out/vault-plugin-secrets-bls /openbao/plugins/ ``` Build and push to your registry: ```bash docker buildx build --platform linux/amd64 -t /openbao-bls: --push . ``` Compute the plugin SHA-256 from inside the image (the chart's standalone config validates against this value): ```bash docker run --rm --entrypoint sha256sum /openbao-bls: /openbao/plugins/vault-plugin-secrets-bls ``` ### A.3 Use your image in the chart Edit `helm/openBao/values.yaml` to point at your image and update the plugin SHA in the standalone config: ```yaml openbao: server: image: registry: repository: openbao-bls tag: "" standalone: enabled: true config: | ... plugin "secret" "bls" { command = "vault-plugin-secrets-bls" binary_name = "vault-plugin-secrets-bls" sha256sum = "" } ``` Verify with `helm template helm/openBao` before installing, then continue from §1.1. --- ## Appendix B: Single-VM evaluation deployment The mainline Preflight and Deployment Checklist assume you already operate a Kubernetes cluster with capacity, a managed PostgreSQL, a Keycloak you log into, a private container registry, real DNS, and a working TLS story. Most evaluators do not have that on day one — they want to spin up the whole stack on a single machine to see what they're buying. This appendix is the recipe for that scenario. This is not a production deployment. The whole point of running everything on one host is that it's cheap to throw away and rebuild. You'll lose the deployment if the host dies, you have no HA story, OpenBao reseals on every host reboot and nobody else can unseal it, and you're trusting a self-signed CA you generated yourself. None of those are appropriate for production, but all of them are fine for "does this thing work for my use case?". When you decide to go further, swap components one at a time — PostgreSQL is the easiest first move (point an ExternalName Service at managed Postgres instead of the local container), then Keycloak (your enterprise IAM), then DNS and TLS (real records and a real CA), then the cluster itself. ### B.1 Host sizing A single VM running every component plus its prereqs needs: - **8 vCPU.** Chia node wants 4 vCPU with headroom (it has to keep up with chain head; a node that falls behind takes the verification flow offline until it resyncs). The admin service is light (~250m). The signature server uses 500m–1 vCPU under MPC load. OpenBao, ingress-nginx, MetalLB, kubelet, containerd, Postgres, Keycloak fill the rest. 8 vCPU leaves headroom; 4 vCPU will run but get tight under load. - **32 GiB RAM.** Chia is the largest consumer and commonly needs several GiB during mainnet operation; leave headroom for sync, cache, and restarts. Keycloak likes 2 GiB. Postgres at this scale is 1 GiB. Admin, signer, OpenBao together are another 2–3 GiB. KIND control plane plus system overhead consumes the rest. A 16 GiB host can run a test rig, but 32 GiB leaves enough margin that one component's transient memory use does not destabilize the node. - **500 GiB SSD.** Dominated by the Chia chain database (~215 GiB after first sync, growing 5–10 GiB/month). Allow at least 500 GiB so peak disk pressure during checkpoint extraction (~310 GiB transient) fits and you have months of growth runway. **AWS reference:** `t3.2xlarge` (8 vCPU / 32 GiB) with a 500 GiB gp3 EBS volume. For better Chia walk-forward throughput, bump gp3 IOPS to 6000 and throughput to 500 MiB/s during the first sync, then drop back to defaults afterward. If you want to skip the Chia node entirely (and ship the deployment without on-chain operations — see Architecture & Privacy Guide for what that costs you), you can run on 4 vCPU / 16 GiB / 100 GiB. The other components are not the heavyweight ones. ### B.2 Operating system and base packages Ubuntu 22.04 LTS is the reference. Other Debian-derived distros work the same way; RHEL-family distros need the obvious package-manager substitutions. ```bash sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg jq unzip openssl postgresql-client ``` `postgresql-client` is for your convenience — `psql` from the host to talk to the Postgres container in §B.9. ### B.3 Docker Install Docker CE with buildx and the compose plugin: ```bash sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin sudo usermod -aG docker "$USER" # log out + back in to pick this up ``` ### B.4 Kubernetes tooling Install `kubectl`, `helm`, and the `helm-diff` plugin per Preflight items #1, #2, #3: ```bash # kubectl (latest stable in the v1.32 channel) curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /" \ | sudo tee /etc/apt/sources.list.d/kubernetes.list >/dev/null sudo apt-get update sudo apt-get install -y kubectl # Helm 3 curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # helm-diff plugin (chia-node deploy scripts need it) helm plugin install https://github.com/databus23/helm-diff ``` Install the OpenBao CLI (Preflight #9) by downloading the matching linux-amd64 binary from the latest [openbao/openbao GitHub release](https://github.com/openbao/openbao/releases) and putting it on `PATH` as `/usr/local/bin/bao`. ### B.5 KIND cluster KIND runs a Kubernetes cluster as a set of Docker containers on the host. For a single-VM deployment you want a single control-plane node with the host's port 80 and 443 mapped into the node — that's how ingress traffic from outside the VM reaches the cluster. ```bash # Install KIND curl -fsSL https://kind.sigs.k8s.io/dl/v0.30.0/kind-linux-amd64 -o /tmp/kind sudo install -m 0755 /tmp/kind /usr/local/bin/kind rm /tmp/kind # Cluster config with port mappings for ingress cat > /tmp/kind-config.yaml <<'EOF' kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 80 hostPort: 80 protocol: TCP - containerPort: 443 hostPort: 443 protocol: TCP EOF kind create cluster --name notbot-test --config /tmp/kind-config.yaml --wait 120s kubectl config use-context kind-notbot-test kubectl cluster-info ``` `extraPortMappings` is what makes the cluster reachable from outside the VM. The ingress controller you install in §B.7 will bind to ports 80/443 inside the control-plane node, and KIND forwards from the host's 80/443 to those. ### B.6 MetalLB for LoadBalancer Services KIND has no cloud LB integration. Services of type `LoadBalancer` stay in `Pending` forever unless you provide an LB controller. MetalLB is the standard in-cluster answer; it picks an IP from a pool you configure and announces it via L2 (ARP) to the cluster's network. For this deployment, MetalLB's role is narrower than you might expect — most external traffic enters through ingress-nginx (§B.7) on the host's port 80/443 mappings, not through a LoadBalancer IP. MetalLB is here so any chart that defaults to `LoadBalancer` (the admin service does, for one) gets a working IP instead of hanging in Pending. ```bash kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml kubectl -n metallb-system wait --for=condition=Available deployment/controller --timeout=300s kubectl -n metallb-system rollout status daemonset/speaker --timeout=300s # Derive an IP pool from KIND's docker network so MetalLB IPs are routable inside the host DOCKER_SUBNET=$(docker network inspect kind \ | python3 -c 'import sys,json; cfg=json.load(sys.stdin)[0]["IPAM"]["Config"]; print(next(c["Subnet"] for c in cfg if "." in c["Subnet"]))') PREFIX=$(echo "$DOCKER_SUBNET" | cut -d. -f1-2) cat </...` lands on the ingress controller. ```bash kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.3/deploy/static/provider/kind/deploy.yaml kubectl wait --namespace ingress-nginx \ --for=condition=ready pod \ --selector=app.kubernetes.io/component=controller \ --timeout=300s ``` Once ingress-nginx is up, any Service you expose via an `Ingress` resource with a `tls:` block gets HTTPS termination using the TLS Secret you reference in that Ingress. You'll create the TLS Secret in §B.8. **For production:** in a real cluster with a cloud LB, you don't need ingress-nginx unless your application requires its specific features. The admin-service and signer-service charts both work with a cloud LB doing TLS at L7 (or L4 with the pod doing TLS). Appendix B is the only place that talks about ingress-nginx. ### B.8 Local CA and TLS certificates For evaluation you generate a CA and use it to issue server certs for every hostname you want to reach over HTTPS. The CA's only job is to sign one cert (or a few). You install the CA's public cert in your OS trust store and in your browser's trust store so the cert chain validates. ```bash sudo mkdir -p /etc/verify-test/{ca,certs} sudo chmod 700 /etc/verify-test/ca # CA key + cert sudo openssl genrsa -out /etc/verify-test/ca/ca.key 4096 sudo openssl req -x509 -new -nodes -key /etc/verify-test/ca/ca.key -sha256 -days 3650 \ -out /etc/verify-test/ca/ca.crt \ -subj "/CN=Verify Eval CA" # Server key + multi-SAN cert SERVER_NAMES="DNS:admin.example.com,DNS:signer.example.com,DNS:keycloak.example.com,DNS:example.com" sudo openssl genrsa -out /etc/verify-test/certs/server.key 4096 sudo openssl req -new -key /etc/verify-test/certs/server.key \ -out /etc/verify-test/certs/server.csr \ -subj "/CN=example.com" \ -addext "subjectAltName=${SERVER_NAMES}" sudo openssl x509 -req -in /etc/verify-test/certs/server.csr \ -CA /etc/verify-test/ca/ca.crt -CAkey /etc/verify-test/ca/ca.key -CAcreateserial \ -out /etc/verify-test/certs/server.crt -days 365 -sha256 \ -extfile <(printf "subjectAltName=%s" "$SERVER_NAMES") ``` Replace `example.com` with whatever domain you control. The cert covers the apex and three subdomains — admin (Decision **H**), signer (Decision **I**), and Keycloak. All four DNS names resolve to the host's public IP. Install the CA in the host's trust store so `curl` works without `-k`: ```bash sudo cp /etc/verify-test/ca/ca.crt /usr/local/share/ca-certificates/verify-eval-ca.crt sudo update-ca-certificates ``` You also need to install the CA in your laptop's browser trust store. Each browser has its own trust store; consult your browser's documentation. Firefox and Chrome both let you import a CA cert as "trusted to identify websites." > **`.app` and other HSTS preload TLDs.** Domains under `.app`, `.dev`, `.bank`, and a handful of others are in the Chromium HSTS preload list, which means the browser refuses to bypass an invalid cert warning at all — even with the CA installed, you must present a cert that validates cleanly. For evaluation, prefer a domain on a non-preloaded TLD (`.com`, `.io`, `.test`) or accept that you must get the local-CA install right before the browser will load anything. ### B.9 PostgreSQL Run Postgres as a Docker container on the KIND network. This puts it in DNS reach of the cluster pods at the container's name, and exposes it on the host's `127.0.0.1:5432` for your own `psql` use. ```bash POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 24) echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> ~/.verify-test-secrets sudo mkdir -p /var/lib/postgresql-data sudo chown 999:999 /var/lib/postgresql-data # Postgres container's UID sudo chmod 700 /var/lib/postgresql-data docker run -d \ --name postgres-verify \ --network kind \ --restart unless-stopped \ -p 127.0.0.1:5432:5432 \ -v /var/lib/postgresql-data:/var/lib/postgresql/data \ -e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \ postgres:16 ``` Wait for it to be ready, then create the `keycloak` database: ```bash KEYCLOAK_DB_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 24) echo "KEYCLOAK_DB_PASSWORD=$KEYCLOAK_DB_PASSWORD" >> ~/.verify-test-secrets docker exec -i -e PGPASSWORD="$POSTGRES_PASSWORD" postgres-verify \ psql -U postgres -v ON_ERROR_STOP=1 -v kc="$KEYCLOAK_DB_PASSWORD" <<'SQL' CREATE DATABASE keycloak; CREATE ROLE keycloak LOGIN; SELECT format('ALTER ROLE keycloak WITH LOGIN PASSWORD %L', :'kc')\gexec GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak; \c keycloak GRANT ALL ON SCHEMA public TO keycloak; ALTER SCHEMA public OWNER TO keycloak; SQL ``` Expose Postgres into the cluster by DNS name with an ExternalName Service. Pods will resolve `postgres.default.svc.cluster.local` to the container: ```bash kubectl apply -f - <> /etc/containerd/config.toml < /etc/containerd/certs.d/registry-verify:5000/hosts.toml < keycloak.your-domain.example fallthrough } kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa ttl 30 } prometheus :9153 forward . /etc/resolv.conf { max_concurrent 1000 } cache 30 { disable success cluster.local disable denial cluster.local } loop reload loadbalance } ``` Then `kubectl -n kube-system rollout restart deployment/coredns`. Verify with `kubectl run dns-test --rm -it --image=alpine:3.19 -- sh -c 'apk add bind-tools >/dev/null && nslookup keycloak.your-domain.example'` — the answer should be the kind-network IP, not the EC2's public IP. If you skip the cluster-side fix, you'll get all the way through admin-service install and only discover the problem when an operator tries to log in (the admin pod hangs on JWKS fetch and the browser hangs on the OAuth redirect-back). Add both entries before you deploy the admin service. ### B.13 Continuing with the Deployment Checklist At this point your single-VM rig satisfies the entire Preflight Checklist: - Kubernetes cluster + kubectl context: KIND (§B.5) - Helm 3, helm-diff plugin: §B.4 - PostgreSQL 14+: §B.9 - Keycloak 22+: §B.10 - Container registry: skipped (using Harbor library) or §B.11 - LoadBalancer support: MetalLB (§B.6) - Workstation tools (openssl, bao CLI): §B.2 / §B.4 - DNS control: §B.12 - TLS certificate (Decision **J**): §B.8 Continue from the Deployment Checklist's Phase 1. Three phase-specific notes for single-VM deployments: - **§5.1 (admin-service trust store for Keycloak's local-CA cert).** Your Keycloak is served from a cert signed by the local CA you created in §B.8. The JVM inside the admin-service pod does not trust that CA by default, so JWKS validation will fail unless you tell the chart to add the CA to the pod's trust store. In your admin-service `values.yaml` (or values overlay), set: ```yaml extraCaCerts: verify-eval-ca: | ``` Run `cat /etc/verify-test/ca/ca.crt` on the EC2 host to retrieve the PEM block. The chart's init container will import it into the admin pod's JVM trust store at startup. - **§5.2 (Admin service LB).** The mainline checklist annotates the admin service Service for an internal cloud LB. On KIND, set `service.type: ClusterIP` and reach the admin service through ingress-nginx — define an Ingress similar to the Keycloak one in §B.10, pointing at the admin service in your chosen namespace. TLS Secrets are namespace-scoped, so the `verify-eval-tls` Secret created in `default` (§B.10) is not visible to an Ingress in namespace **B**; recreate it there from the same local CA-signed cert before defining the Ingress: ```bash kubectl create secret tls verify-eval-tls \ --cert=/etc/verify-test/certs/server.crt \ --key=/etc/verify-test/certs/server.key \ --namespace ``` then reference `verify-eval-tls` as the Ingress `secretName`. - **§8 (Signature server).** Same pattern — use an Ingress for Decision **I**, not a cloud LB. Back it with the `signer-tls` Secret you already created in namespace **C** in §8.1 (not `verify-eval-tls`, which exists only in `default`). --- > **not.bot Verify: Operations and Reference Guide** — https://not.bot/technology/verify-operations/ · Markdown: https://not.bot/technology/verify-operations.md · Updated 2026-06-14 # Operations & Reference Guide ## not.bot™ Verify: Operations & Reference Guide This document covers the architecture, configuration, scaling, and failure modes of a running not.bot Verify deployment. It is reference material, not a procedure. For the deploy-from-zero walkthrough, see the Deployment Checklist. For the trust model and privacy properties, see the Architecture & Privacy Guide. Each component section covers what the component does, the configuration that matters in production, the failure modes you will see, and the operational behavior that surprises new operators. Cross-references to Deployment Checklist phases use the form (DC §X) so you can jump back to the procedure when you need to change something. --- ## Contents 1. [Overview and architecture recap](#1-overview-and-architecture-recap) 2. [OpenBao](#2-openbao) 3. [Admin service](#3-admin-service) 4. [Signature server](#4-signature-server) 5. [Chia node](#5-chia-node) 6. [SDK](#6-sdk) 7. [PostgreSQL and Keycloak (prerequisites)](#7-postgresql-and-keycloak-prerequisites) 8. [Observability and alerting](#8-observability-and-alerting) 9. [Support](#9-support) --- ## 1. Overview and architecture recap You operate four components, all in your own Kubernetes cluster: - **OpenBao** holds every DID's private key. Sealed on every restart. - **Admin service** runs as a singleton, exposed on your internal network. Hosts the management UI, manages the DID pool, reports MAU counts. - **Signature servers** run behind an internal load balancer, reached by your SDK adapter rather than the public internet. Each one holds one signature DID and serves user verification requests. - **Chia nodes** follow the Chia blockchain. Used by the admin service for on-chain operations and by signature servers for chain state queries. You also rely on two services you provide: PostgreSQL (application data) and Keycloak (admin operator login). Neither is part of not.bot Verify; both are prerequisites. The Architecture & Privacy Guide covers the verification flow in detail. The short version: your application backend uses the SDK to start a signature request, the user opens a universal link to the not.bot app, the not.bot app talks to your signature servers through your SDK adapter, and your backend gets a callback when verification finishes. No traffic in this flow reaches Julia Social. Julia Social is a runtime dependency only at signature server startup, when the server acquires its honest.bot™ credential. After that, a running deployment operates with no Julia Social connectivity required. See Architecture & Privacy Guide §10 for the full breakdown. --- ## 2. OpenBao ### 2.1 What it does OpenBao stores the BLS12-381 private key for every DID in your deployment: your business DID and every signature DID in your pool. The admin service signs DID transactions through OpenBao. Each signature server signs every user verification response through OpenBao. No private key leaves the cluster. The Chiakeys plugin (`vault-plugin-secrets-bls`) extends OpenBao to support Chia's BLS12-381 signature scheme. OpenBao does not include this support out of the box, so the deployment uses a custom OpenBao image with the plugin baked in. The chart references this image by digest and the plugin is registered automatically at startup; see Deployment Checklist Appendix A if you need to rebuild it from source. ### 2.2 The reseal problem OpenBao seals itself on every pod restart: cluster upgrades, node failures, manual restarts, eviction. A sealed OpenBao cannot sign. A signature server cannot serve a single user request while OpenBao is sealed. Until an operator unseals it, the verification flow is offline. The unseal key from initialization is what unseals it (DC §1.2). Keep that key in whatever break-glass secret store your team uses for high-blast-radius credentials, and keep it accessible to whoever is on call. If you cannot tolerate the gap between a restart and a human running `bao operator unseal`, look at OpenBao auto-unseal. The upstream OpenBao docs cover the supported backends (cloud KMS services, HSMs, transit unseal). Auto-unseal moves the trust anchor from "an operator has the key" to "the cluster's KMS principal can fetch it," which is a different threat model. Pick the one that matches your security posture. ### 2.3 1-of-1 key shares The deployment uses a single key share with a threshold of one (`-key-shares=1 -key-threshold=1`). This is correct for not.bot Verify, including production. The unseal key and root token are operator credentials for an instance that holds only your own DID keys; the trust model does not benefit from Shamir-splitting them across multiple humans. If your security team requires multi-share unseal as policy, OpenBao supports it. Set `-key-shares=N -key-threshold=M` at init time. You will then need M holders present to unseal after every restart, which makes the reseal problem worse. ### 2.4 Namespacing and policies The admin service operates inside its own OpenBao namespace, with a scoped token that grants access to two paths inside that namespace: `chiakeys/*` for BLS keys, and `secret/data/*` / `secret/metadata/*` for non-DID secrets such as Chia node CA cert/key pairs (DC §1.3). The token is created with `-orphan` so it survives root revocation. The root token's only purpose is bootstrapping that policy. After Phase 1, the root token is revoked (DC §1.4). If you need administrative access later, generate a new root with the unseal key using `bao operator generate-root`, do the work, and revoke it again. Nothing in not.bot Verify uses the root token for normal operation. If you ever see the root token in an application configuration, that is a configuration error. ### 2.5 Common failures **OpenBao sealed.** Logs from the admin service and every signature server show connection failures. Run `bao operator unseal `. Investigate why the pod restarted. **Sealed during signature server startup.** The signature server cannot complete its startup sequence and exits. The DID it was assigned stays in "assigned" state until the heartbeat timeout releases it. See §4.4. **Plugin SHA mismatch.** Only applies if you rebuilt the OpenBao image per Deployment Checklist Appendix A. If the Chiakeys plugin SHA-256 in `values.yaml` does not match the binary in your custom image, OpenBao refuses to register the plugin and the chiakeys engine will not enable. Recompute the SHA against the binary in the image (`docker run --rm --entrypoint sha256sum /openbao/plugins/vault-plugin-secrets-bls`), update `values.yaml`, and reinstall the chart. The shipped chart's SHA matches its shipped image; no action is needed when using the default image. **Unseal key lost.** Unrecoverable. The data in OpenBao is gone. You will need to mint a new business DID, mint new signature DIDs, re-verify your domain, and replace every signature server. Plan accordingly: store the unseal key somewhere you will still have access to it after a personnel change or a disaster. --- ## 3. Admin service ### 3.1 Role The admin service is the management plane. It does four things: 1. Hosts the operator-facing UI for registering Chia nodes, creating the business DID, minting signature DIDs, and uploading `deployment-config.json` once at first login. 2. Issues DID assignments to signature servers when they start up, and tracks the pool's "available" / "assigned" state in PostgreSQL. 3. Delegates the domain credential from your business DID to each signature server's signature DID at assignment time. 4. Reports your monthly active user count to Julia Social once an hour. It is a singleton. Run one replica. The DID assignment flow assumes a single coordinator; running two replicas without coordination would race on assignments. ### 3.2 Internal-only exposure Operators reach the admin service from your internal network. There is no public access path. The chart exposes the service through a Kubernetes `Service` of type `LoadBalancer`, annotated for internal-only placement. Your cloud provider sees the annotation and provisions a private endpoint with a stable hostname. Per provider: - **AWS:** `service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"` provisions a private NLB or CLB. For TLS termination at the LB, add `service.beta.kubernetes.io/aws-load-balancer-ssl-cert: ""` and `service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"`. The cert must live in the same region as the LB. The LB type is controlled by `service.beta.kubernetes.io/aws-load-balancer-type` (NLB recommended). - **GCP / GKE:** `networking.gke.io/load-balancer-type: "Internal"` provisions an internal TCP/UDP load balancer by default. For TLS, GCP's preferred path is a `BackendConfig` plus `ManagedCertificate` resource; an internal HTTP(S) load balancer requires a different setup (Gateway API or an Ingress with ILB scheme). If you are doing TLS termination at the LB, expect to manage one or two extra Kubernetes resources beyond the Service annotation. - **Azure:** `service.beta.kubernetes.io/azure-load-balancer-internal: "true"` places the LB on the internal AKS network. TLS termination at the Azure LB requires you to upload the cert to a key vault and reference it through a listener configuration; for most teams the simpler path is terminating TLS in nginx-ingress or a similar in-cluster proxy and leaving the LB at L4. Across providers, the admin service inside the pod serves plain HTTP on port 8080. TLS terminates at the LB. The cert reference goes in Decision **J** of the Pre-flight Checklist. > Cloud provider TLS termination details change between releases. Use the annotations above as a starting point and verify against your provider's current documentation before going to production. GCP's internal HTTPS LB and Azure's LB cert support have both moved in recent releases. After the LB exists, point internal DNS for **H** at the LB's stable hostname. The hostname must match `app.baseUrl` in the admin service `values.yaml` and the redirect URIs in Keycloak. Pre-flight Decision H is the single source of truth; Phase 3 (Keycloak) and Phase 5 (admin service) both read from it. ### 3.3 Keycloak integration The admin service uses two Keycloak URLs, and they have different jobs. `issuerUri` is what the admin service backend uses to fetch Keycloak's public keys and validate the tokens it receives. This is server-to-server traffic inside the cluster. HTTP on a ClusterIP is fine here because the traffic never leaves the cluster network. `externalUrl` is what the operator's browser hits during login. The operator types a password and gets a bearer token back. Plaintext is not appropriate. Use HTTPS. The two URLs can resolve to the same Keycloak instance. They almost always do. The split exists because the URL the backend uses (in-cluster) and the URL the browser uses (external) are usually different addresses for the same service. The single most common admin service failure is an issuer mismatch. The flow looks like this: the operator clicks login, signs in at Keycloak, returns to the admin service with a token, and the backend rejects the token because its `iss` claim does not match `issuerUri`. The `iss` claim is whatever Keycloak sees as its own hostname when it issues the token, which depends on Keycloak's hostname configuration (`KC_HOSTNAME` or the equivalent). If the operator's browser reaches Keycloak at `https://keycloak.example.com` but Keycloak is configured to advertise itself as `http://keycloak.keycloak.svc.cluster.local:8080`, the token's issuer will be the in-cluster URL and the admin service has to accept that. Set `issuerUri` to whatever Keycloak puts in the `iss` claim, not what you wish it would put there. If logins fail, decode the JWT (`jwt.io` works offline) and read the `iss` claim. Whatever you find there is what `issuerUri` must equal. ### 3.4 Database schema The admin service owns the main application schema. It creates most tables on first startup as the admin user (Decision **F**, default `notbot_admin`). The signer user (Decision **G**, default `notbot_signer`) needs read/write access on those tables; the deployment grants this through `ALTER DEFAULT PRIVILEGES` (DC §2). The current signature server also runs its own migrations at startup, so the signer user temporarily needs `CREATE` on the `public` schema. DC §2 grants that explicitly. If the product later moves all schema creation into the admin service, remove that grant and return the signer user to runtime-only DML. Both users connect to the same database in the standard deployment. Running them against separate databases means setting up replication, which not.bot Verify does not provide. If schema migrations on startup fail, the pod logs name the migration. Most migration failures trace back to a permissions problem on the existing schema (someone changed grants out of band) or a database version mismatch (the chart expects PostgreSQL 14+). ### 3.5 Configuration surface The admin service `values.yaml` is the largest configuration block in the deployment. Most fields are documented inline. Two points worth flagging: - The chart reads production secrets through Kubernetes Secret references. Create the referenced Secret before install and keep only Secret names and keys in `values.yaml`. Do not check generated credentials or populated local overlays into version control. - The `juliaServer.host` field defaults to `identity.julia.social`. Beta deployments may be pointed at `identity.juliasocial-dev.com`. Verify with support which one applies to your subscription. ### 3.6 Pending chart changes The Deployment Checklist reflects the admin service chart after three pending changes the dev team has agreed to: 1. Remove the unused `ingress` block from `values.yaml`. The block exists today but no template consumes it. 2. Add `service.annotations` support to the service template, so the internal-LB annotations described in §3.2 render through. 3. Change the default `service.type` from `NodePort` to `ClusterIP` (or `LoadBalancer`), so a default install does not open port 30880 on every node. If the admin-service `values.yaml` still has an `ingress` block, or the service defaults to `NodePort`, you have an older chart and your behavior may differ from this guide. ### 3.7 Common failures **CrashLoopBackOff at first deploy.** Almost always an upstream problem: PostgreSQL unreachable, Keycloak realm or client secret wrong, OpenBao sealed or token invalid, in-cluster DNS not resolving one of the above. The pod logs name the failing dependency. **Login redirects to a working Keycloak page but returns a 401 or 403 to the admin service.** Issuer mismatch. See §3.3. **`deployment-config.json` upload fails.** The API key in the file is one-time-use, and any upload error consumes it upstream regardless of what the error message says. Common causes: cluster cannot reach `billingServerUrl` (egress firewall), `customerId` / `organizationName` does not match Julia Social's records, or transient-looking 5xx-shape errors like "Billing service is currently experiencing issues" — the last one is misleading because the failure persists on your side even after the upstream recovers. The fix path is the same in all cases: email `support@julia.social` for a re-issued welcome email containing a fresh API key, then retry §6.3 with the new file. Investigating the root cause of the original error (firewall, name mismatch) before re-issuing is fine — but do not retry the upload with the old key, it will always fail. **Vault login reports "No online Chia node available."** The admin service could not find a registered Chia node with online status for the Vault/JNI login path. Register a Chia node first, then confirm the node health check marks it online before retrying the domain or signature-DID operation. **Hourly MAU report quietly stops.** The admin service queues failed reports and retries. If you watch the logs and see retries stacking up, your egress to `billingServerUrl` is blocked. No data is lost; the queue drains once connectivity returns. This does not affect the verification flow. --- ## 4. Signature server ### 4.1 Role A signature server holds one signature DID for its lifetime, signs user verification responses with that DID's key (through OpenBao), and serves the request flow described in the Architecture & Privacy Guide §5. You run as many as your throughput requires, behind an nginx ingress. The deployment is stateless from the operator's perspective. Each replica picks up its DID from the pool at startup and releases it at shutdown. Replacing a replica is a normal operation. ### 4.2 The DID pool The pool is the list of pre-minted signature DIDs in the admin interface. Each DID is in one of two states: - **Available.** Minted, not held by any running server, ready to be assigned at the next server startup. - **Assigned.** Held by a running signature server, with the server's identifier and the timestamp of its most recent heartbeat. A DID stays Assigned until the signature server holding it shuts down cleanly (releasing the DID) or stops sending heartbeats long enough for the admin service to release it automatically. The pool auto-sizes. The admin service maintains at least two unallocated DIDs at all times. When a signature server starts up and takes a DID, the admin service mints another to keep the unallocated count at two. Each minting is an on-chain transaction (around two minutes), so the buffer of two covers the gap between a startup picking up a DID and the admin service producing a fresh one. You do not size the pool yourself; your replica count and HPA ceiling are the cap. You mint the first DID once during initial setup (DC §7). The admin service handles every DID after that. ### 4.3 Startup sequence When a signature server pod starts, it goes through these steps in order. A failure in any step exits the pod, and the logs name the step. 1. **DID assignment.** Contacts the admin service. The admin service picks an Available DID, marks it Assigned, and returns the DID along with a scoped OpenBao token, the signer database credentials, and the connection details (including TLS material) for every registered Chia node. 2. **OpenBao connection.** Connects to OpenBao with the scoped token and confirms the key is reachable. 3. **Database connection.** Connects to PostgreSQL with the signer credentials. 4. **Domain credential delegation.** The admin service delegates your business DID's domain credential to the assigned signature DID. This is what proves to the not.bot app that this server represents your domain. 5. **honest.bot credential acquisition.** Contacts Julia Social. Julia Social issues an honest.bot credential bound to this DID. No two running processes can hold the same credential at once. 6. **Ready.** The server begins serving verification requests on port 8080. Common failures by step: - **Step 1.** No Available DIDs. The admin service is failing to mint replacements. Check the admin service logs and the registered Chia node's sync state; minting requires a synced node. - **Step 2.** OpenBao sealed (unseal it) or unreachable from this namespace (NetworkPolicy issue). - **Step 3.** PostgreSQL credentials wrong, host unreachable, or the signer user (Decision **G**) lacks the read/write and schema `CREATE` grants from DC §2. The current signer runs migrations at startup; without `CREATE` it fails with `permission denied for schema public`. - **Step 4.** The admin service is unreachable or your business DID is missing the domain credential. Re-verify your domain (DC §6.5). - **Step 5.** Egress to Julia Social blocked. Check firewall rules for outbound HTTPS to `identity.julia.social` (or the dev hostname for beta deployments). ### 4.4 Heartbeats and DID release Each signature server sends a heartbeat to the admin service every minute. The heartbeat updates the DID's `last_heartbeat` timestamp in the admin interface and confirms the server is alive. On clean shutdown (SIGTERM, then graceful drain), the server releases its DID before exiting. The DID returns to Available immediately, and the admin service does not need to mint a replacement. On a crash or network partition, the server cannot release its DID. The admin service watches for missed heartbeats and releases the DID after a timeout. Until that timeout fires, the DID is stuck Assigned. The auto-sizing logic continues to maintain two unallocated DIDs in parallel, so a replacement server can start up against a freshly minted DID without waiting for the stuck one. ### 4.5 Scaling The signature server chart supports a Horizontal Pod Autoscaler. Each new replica goes through the startup sequence in §4.3 the same way the first one did. The ingress routes requests across all running replicas. Scale up: HPA adds replicas. Each new replica takes one of the two unallocated DIDs, and the admin service mints another to refill. The two-DID buffer absorbs normal scale-up rates. A burst that adds replicas faster than the admin service can mint will see the later replicas wait at startup until a fresh DID lands; the on-chain transaction is around two minutes. Scale down: HPA terminates replicas. Each terminating replica receives SIGTERM, drains in-flight requests, releases its DID, and exits. The DID returns to Available. Helm rolling updates work the same way: the old pod drains and releases, the new pod picks up an Available DID. The admin service tracks unallocated count across both flows and does not over-mint. ### 4.6 Network requirements The signature server pod needs egress to: - **Admin service** (in-cluster). DID assignment and heartbeats. - **OpenBao** (in-cluster). Every signature request signs through OpenBao, so this connection is hot path, not just startup. - **PostgreSQL** (in-cluster or external). Reading and writing signature state. - **Chia nodes** (in-cluster). Mutual TLS using the CA and cert the admin service provided at startup. - **Julia Social** (external HTTPS). Startup honest.bot credential acquisition, then once an hour for the diagnostic count. After startup, this is the only Julia Social traffic the signature server generates. If your cluster enforces NetworkPolicies, every path above needs an explicit allow rule. The admin-to-signer namespace boundary trips up new deployments more than any other network restriction. ### 4.7 Bootstrap configuration The signature server needs a small amount of static configuration to reach the admin service at all. Once that initial call lands, most runtime config (DID, OpenBao token, database credentials, Chia node host/port/TLS material) is supplied by the admin service in its `signatureServerSetup` response and never touches the chart. What's in the bootstrap: **Required to start (binary panics or fails to contact admin without these):** - `API_KEY` — inbound API key the signer requires from clients (SDK adapter, not.bot app). Set from the operator-created Secret referenced by `deployment.apiKeySecret`. Without this set the binary panics on startup with `API_KEY Is Required: NotPresent`. - `ADMIN_API_KEY` — outbound API key the signer presents to the admin service. Set from the same operator-created Secret referenced by `deployment.apiKeySecret`; it should be the same `businesses.api_key` value used for `API_KEY`. - `ADMIN_HOSTNAME` — admin service DNS name inside the cluster. Set via `deployment.adminService.hostname` in `values.yaml`. If unset, the binary defaults to `localhost`, which is wrong inside the signer pod. - `ADMIN_SECURE` — whether the signer uses HTTPS to reach admin. Set via `deployment.adminService.secure`; the standard in-cluster admin service is plain HTTP, so the chart renders `false`. **Recommended but optional, with safe defaults:** - `ADMIN_PORT` — admin service port. The chart renders `8080`. - `CHIA_NETWORK` — `Mainnet`. not.bot Verify operates on Chia mainnet only; do not change this value. - `RUST_LOG` — log level filter, default `info`. **Do NOT set** (the binary populates these from the admin response and overriding them either has no effect or actively breaks the deployment): - `CHIA_FULL_NODE`, `CHIA_FULL_NODE_PORT` — pulled from `chia_nodes[0].host/port` in the admin response. - `PRIVATE_CA_CRT`, `PRIVATE_CA_KEY` — pulled from `chia_nodes[0]` inline PEM in the admin response; consumed by the Chia RPC client at startup, then unset. - `CHIA_FULL_NODE_SSL` — when set, the binary switches from inline-PEM-from-admin mode to filesystem-paths mode, looking for `/full_node/private_full_node.{crt,key}` and `/ca/private_ca.crt`. If those files don't exist (the chart doesn't provision them), startup fails with `No such file or directory` from the SSL loader. **Inert in this binary** (referenced elsewhere in the workspace but never read here): - `SSL_ROOT_CERTS`, `SSL_CERTS`, `SSL_PRIVATE_KEY`. Optional signer listener values `HOSTNAME` / `PORT` default to `0.0.0.0:8080`; the chart's service already targets 8080, so leave them unset. Optional SMTP alert values named `SIGNATURE_*` are only needed if you configure email alerts. The signer chart renders non-secret bootstrap config into a ConfigMap and reads both API-key env vars from an operator-created Kubernetes Secret. Database credentials, OpenBao token, DID assignment, and Chia node host/port/TLS material arrive from the admin `signatureServerSetup` response, not from chart env. ### 4.8 Common failures **Pod stuck in CrashLoopBackOff.** Read the logs. The startup sequence (§4.3) names the failing step. **Pod runs but the admin interface shows the DID as Available, not Assigned.** The pod is not heartbeating. Either it is wedged after starting (rare; check the logs for repeated errors) or the heartbeat path to the admin service is broken (NetworkPolicy added recently?). **DID stuck in Assigned with stale heartbeat.** The server holding it died without releasing. Wait for the heartbeat timeout; the admin service will release it. New servers are not blocked while you wait, since the auto-sized buffer keeps unallocated DIDs available. **429 or 503 from the signature server.** Either OpenBao is sealed (every signature now fails) or you hit a Chia node connectivity problem (chain state queries fail). The pod logs name which. --- ## 5. Chia node ### 5.1 Role A Chia node follows the Chia blockchain on behalf of your deployment. The admin service uses one to register DIDs on-chain. Each signature server uses one (or more) to verify chain state when serving user requests. Run at least one; three is recommended. The Chia node is not part of the not.bot Verify Helm bundle. The charts and image build live in a public repository (`github.com/GalactechsLLC/helm-chia-nodes`). DC §4 covers the deployment. ### 5.2 Sync behavior The chart ships with DB checkpointing on. On first deploy, the node downloads a recent compressed chain snapshot from `torrents.chia.net` and starts from there, which cuts initial sync time dramatically compared to syncing from genesis. The node then walks forward from the checkpoint to the current chain head before it can answer queries about current state. **Expect 12–24 hours of wall time for first sync** on commodity cloud SSDs. On a t3.xlarge with gp3 SSD (mainnet), we observed: - Checkpoint tarball download: ~25 minutes (~121 GiB, single mainnet checkpoint, recent vintage). - Tarball extraction to SQLite: ~50 minutes. Peak disk pressure during this window is roughly the tarball size plus the partial SQLite — size your PVC for at least 500 GiB to avoid running out mid-extraction. - Walk-forward from checkpoint to chain head: 17+ hours, averaging ~8.5 blocks/second, with periodic stalls from the sync pipeline's back-pressure. Walk-forward dominates total time and scales with how stale the checkpoint is relative to chain head. Faster disks (NVMe-class IOPS, higher gp3 IOPS provisioning) help the checkpoint download and extraction phases. During our t3.xlarge/gp3 test run, the walk-forward phase averaged ~8.5 blocks/second and showed periodic sync pipeline back-pressure. Higher vCPU counts and faster disks may improve catch-up, but we have not benchmarked enough instance shapes to give a reliable scaling curve. Spinning disks are still not viable for steady-state operation because the chain workload is write-IOPS-heavy at the tail. You cannot create your business DID, mint signature DIDs, or perform any other on-chain operation until at least one Chia node has fully synced. The admin service runs fine without a synced node, so you can deploy through Phase 5 (admin service) and configure operators while you wait. The on-chain steps (Phase 6 onward) block on sync. Plan to span the deployment across at least two business days. Subsequent restarts reuse the existing database and come online in a minute or two. The long wait is on first deploy only. A node showing `Running` in `kubectl get pods` is not the same as a synced node. Check sync status in the admin interface after registering the node (DC §6.2). ### 5.3 The shared private CA Every Chia node uses mutual TLS on its RPC interface. The node and its caller both present certs signed by a private CA. The operator generates the CA and the cert pair (DC §4.1) and pastes them into each node's values file. Use one CA for every node in the deployment. The chart supports a different CA per node, but every CA and cert pair has to be uploaded individually when you register the node in the admin interface, and tracking multiple CAs across nodes is overhead with no security benefit. The CA is your trust anchor; sharing it across nodes is the design. The CA is valid for ten years (DC §4.1 generates with `-days 3650`). Mark your calendar for rotation. Rotation is a planned operation: generate a new CA and cert, update every node's values file, redeploy each node, and re-upload the CA and cert for each registered node in the admin interface. ### 5.4 The YAML indentation gotcha The CA cert and key go into the values file as YAML block scalars (`|`). Block scalars preserve newlines, but they require consistent indentation under the field name. Every line of the cert and every line of the key must sit at the same indentation level. ```yaml chia-blockchain: chia: ca: private_ca_crt: | -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- ``` If indentation drifts (one of the cert lines is indented one space less than its neighbors, for example), YAML parses the file but the cert content is garbled. The pod cannot parse the cert at runtime, fails readiness, and restarts. From the outside this looks like a CrashLoopBackOff with no obvious cause. Trust the YAML linter that ships with your editor. If a node restart-loops on first deploy and you cannot see a reason in the logs, paste the cert content into a YAML linter and check. ### 5.5 Redundancy A single Chia node is a single point of failure for your verification flow. A node falling out of sync, hitting a storage issue, or restarting takes the admin service and signature servers offline as far as on-chain queries are concerned. Running more than one node gives you the redundancy to absorb a failure; three is recommended. The admin service distributes registered nodes to signature servers at startup; each signature server can fall back across them. Bring up additional nodes by repeating the deploy with a separate values file and Helm release name. Use the same CA in every node. ### 5.6 Storage The Chia chain database grows continuously. New blocks land every roughly 18 seconds. You will not run out of space tomorrow, but you will eventually if you do not monitor. Pick a `StorageClass` that supports growth (most cloud-managed PV classes do, with a CSI driver that supports `VolumeExpansion`). Size the PVC generously up front, expand when usage hits 70%, and alert when usage hits 80%. A node whose PVC fills up takes itself out of service until you expand. SSD is required. The chain workload is IOPS-heavy on writes. Spinning disks fall behind chain head and stay behind. ### 5.7 Preservation and restore A first sync from the checkpoint takes 12–24 hours of wall time (§5.2). A redeploy that starts from an empty PVC re-incurs that wait. Two operations avoid it: backing up a synced node's DB, and pre-populating a fresh PVC with a known-good DB before the chart starts. #### Backing up the chain DB The chain DB lives inside the node's PVC at `${CHIA_ROOT}/db/`. Back up the whole `db/` directory, not just `blockchain_v2_mainnet.sqlite` — the directory also contains a SQLite WAL/shm, height-to-hash index, peers cache, and sub-epoch summaries. Restoring only the `.sqlite` file leaves the node in an inconsistent state on first start. The backup mechanism is operator's choice; different clusters have very different storage capabilities. Two common shapes: - **Cluster-native volume snapshot.** If your StorageClass supports CSI VolumeSnapshots, create a VolumeSnapshot resource pointing at the node's PVC. This is the fastest path on most managed-cloud Kubernetes. - **Filesystem copy via maintenance pod.** Spin up a temporary pod (e.g. `busybox` or `alpine`) that mounts the node's PVC and uploads `${CHIA_ROOT}/db/` to object storage with `tar`, `rclone`, `aws s3 cp`, or whatever your team already uses. For the most consistent backup, scale the chia-node workload to zero replicas before snapshotting or copying. SQLite tolerates running snapshots, but quiescing first removes edge cases. The DB grows by 5–10 GiB per month after first sync. Back up often enough that a restore doesn't require a long walk-forward; weekly is a sensible default. #### Restoring or pre-populating a node DB The container entrypoint checks the size of `${CHIA_ROOT}/db/blockchain_v2_mainnet.sqlite` at startup. If `du -k` reports the file as smaller than 1 GiB (< 1048576 KiB), the entrypoint downloads the latest checkpoint torrent and extracts it — the slow first-sync path. If the file is at or above that threshold, the entrypoint skips the checkpoint flow and walks forward from whatever state it finds. This gate is what lets a pre-populated PVC short-circuit the 12–24 hour wait. To restore from a backup, or to seed a new node from a synced one's DB: 1. Pre-create the PVC manually instead of letting `helm install` create an empty one. Match the chart's expected name and size. 2. Mount the PVC from a temporary maintenance pod (`busybox` or `alpine` with a `sleep` command), as the same UID/GID the chia-node container runs as. Wrong ownership leaves files the runtime user cannot read or write. 3. Copy the backup contents into `${CHIA_ROOT}/db/` on the mounted PVC. Preserve file ownership and permissions. Note that some files in the chia DB directory ship mode 0600 (notably `sub-epoch-summaries`) — your copy operation needs to either run as the file owner or use elevated privileges (sudo, root-side `docker cp`, etc.) to read them. A standard non-privileged `cp` will fail silently or copy zero-byte files for these. Verify by checking sizes after the copy. If `sub-epoch-summaries` ends up missing or zero-byte after restore, chia regenerates it from chain state at startup — slower than restoring it, but not fatal. 4. Delete the maintenance pod. 5. `helm install` (or `./upgrade.sh`) the chia-node chart. The entrypoint sees the SQLite > 1 GiB, skips the checkpoint download, and walks forward only the recent blocks — minutes to hours rather than 12–24 hours. The upstream `helm-chia-nodes` chart does not currently expose either backup or restore as a templated option. If you do this often, consider wrapping the steps above in a script that lives with your IaC. ### 5.8 Mining Chia nodes do not mine cryptocurrency in this deployment. They follow the chain and serve queries; that is all. If you want to enable mining for unrelated reasons, the upstream Chia charts support it and the GalactechsLLC repo documents the values. not.bot Verify does not benefit from your nodes mining. ### 5.9 Billing Julia Social does not bill based on the number of Chia nodes you run. Deploy as many as your reliability and load profile call for. ### 5.10 Common failures **Pod CrashLoopBackOff on first deploy.** Either the CA YAML indentation is wrong (§5.4) or the storage volume failed to mount. The pod logs distinguish. **Pod runs but admin interface shows it as not synced.** Wait. First sync is slow; the chart's checkpoint mechanism makes it tolerable but not instant. **Node falls behind chain head after running for weeks.** Storage filled up, IOPS contention with another workload, or network egress to Chia peers degraded. Check disk usage first, then network. **TLS handshake fails between admin service and node.** The CA or cert uploaded to the admin interface (DC §6.2) does not match what the node was deployed with. Re-upload from the original files used in DC §4. --- ## 6. SDK ### 6.1 Role The not.bot Verify SDK is a server-side library that runs in your application backend, not in the cluster. It connects your backend to your signature servers and handles the verification flow: starting requests, proxying the cryptographic exchange between the not.bot app and your signature servers, and delivering results through callbacks you define. Languages: Rust (reference), JavaScript (Express), Python (FastAPI), Java (Spring MVC), Dart (shelf). The API surface is the same across all of them. Repository: `github.com/julia-social/julia_web_sdk`. ### 6.2 Two integration paths **Server adapter** (recommended for most deployments). You configure the adapter with your verification requirements and callbacks, and it mounts a set of `/signature/*` routes into your web framework. The adapter handles session tracking, request-to-session mapping, and websocket proxying. **SignatureClient** (for custom flows). A lower-level HTTP client that calls the signature server endpoints directly. Use it when you need manual control, for automation scripts, or when your framework does not have a matching adapter. DC §9 covers the adapter-based integration. ### 6.3 Adapter configuration reference The adapter takes six configuration items: - `request_claims`: which credentials you want from the user. Defined in `shared/claim_properties.txt` in the SDK repo. Common ones: `Notbot0` (bot detection), `AgeOver18` / `AgeOver21` and the full age bracket range, `FirstName` / `FamilyName` / `Nationality` (PII), `SitePass`. Architecture & Privacy Guide §8 covers what each claim attests to. - `require_site_pass`: when true, the verification generates a per-user-per-site Site Pass that lets you recognize returning users without learning their identity. - `message_generator`: produces the text the user sees in the not.bot app when approving the verification. Make it specific to your site so the user knows what they are approving. - `on_success`: called when verification completes. The adapter passes the verified response (alias DID, requested claims, Site Pass if requested, cryptographic presentation) and the session. Store what you need. - `on_failure`: called when verification fails. Log it, alert on it, handle it. - `expire_time`: seconds a verification request stays valid. Default 3600. ### 6.4 Routes the adapter exposes Once mounted, the adapter serves these routes from your backend: - `GET /signature/notbot`: your frontend calls this to start a verification. Returns a request ID. Build the universal link or QR code from the ID. - `GET /signature/status`: your frontend polls this to detect when verification finishes. - `POST /signature/notbot/{request_id}`: the not.bot app calls this during the cryptographic exchange. The adapter proxies to your signature server. - `POST /signature/verify/{request_id}`: the not.bot app submits the signed presentation here. The adapter proxies to your signature server, then fires `on_success` or `on_failure`. - `WS /signature/honestbot` and `WS /calculate_site_pass`: WebSocket routes used during the verification protocol. Proxied to your signature servers. Your backend code calls the first two. The not.bot app drives the rest. ### 6.5 The WebSocket proxy loop trap Configure `SIGNATURE_HOSTNAME` to point at your signature server load balancer (Decision **I**), not at the host running the SDK adapter. If both point at the same host, the WebSocket proxy will loop back to itself on `/signature/honestbot` and the verification will hang. This is the most common SDK misconfiguration. The fix is one environment variable. The symptom is mysterious: the universal link opens the not.bot app, the user approves, and nothing happens. The browser shows a stalled WebSocket. Check `SIGNATURE_HOSTNAME` first. ### 6.6 Session mapping and sticky sessions The adapter maps each request ID to the session that started it. When verification completes, the adapter looks up the originating session and passes it to `on_success`, even though the verification response arrives on a different HTTP connection (it must, since the not.bot app is a separate client). The map lives in memory in the adapter process. If you run multiple instances of your backend behind a load balancer, the verification response can land on a different backend instance than the one that started the request. The instance that received it has no map entry and cannot route to the right session. Two fixes work: - **Sticky sessions** at your load balancer. The user's frontend session and the not.bot app's verification response both route to the same backend instance. Most load balancers support this with a session cookie or source-IP affinity. - **Shared session store.** Replace the adapter's in-memory map with a Redis or similar store. The SDK does not provide this out of the box; you have to wire it up by overriding the adapter's session callbacks. For most deployments, sticky sessions are the simpler fix. ### 6.7 Common failures **Verification hangs after the user approves in the not.bot app.** WebSocket loop trap. See §6.5. **`on_success` fires on a different user's session.** Sticky sessions are off and the request landed on the wrong instance. See §6.6. **`SIGNATURE_API_KEY` rejected.** The key was generated for a different deployment, or the value was rotated and the running adapter has a stale value. Get a fresh key from the admin interface and restart the adapter. **Universal link does not open the not.bot app.** The user does not have the app installed (the link should redirect them to the appropriate app store; if it does not, your link construction is wrong) or the link's deeplink association is broken (rare; usually a manifest or App Store linkage issue, not an SDK problem). --- ## 7. PostgreSQL and Keycloak (prerequisites) You provide both. Neither is part of the not.bot Verify Helm bundle. Versions: PostgreSQL 14+, Keycloak 22+. PostgreSQL hosts the admin service's application data: registered Chia nodes, the signature DID pool, MAU counters, and signature server state. The schema is created by the admin service on first startup as the admin user (Decision **F**, default `notbot_admin`). The signer credentials (Decision **G**, default `notbot_signer`) need read/write on tables created by the admin user. The schema lives in one database. Splitting it across two databases means setting up replication; the deployment does not provide that. Keycloak handles operator login to the admin service. End users on the not.bot app never touch Keycloak. Only your deployment operators do. The admin-service realm has one client (`admin-service`) with confidential authentication and a redirect URI matching `app.baseUrl`. The most useful operational property of both is that they are standard. Any monitoring, backup, or HA pattern your team already runs for either applies here. For PostgreSQL backup: nightly dumps are the minimum, point-in-time recovery (WAL archiving) is better. The admin service can recreate the DID pool by re-querying the chain through a registered node, but everything else (operator state, Chia node registrations, MAU counters) lives only in the database. For Keycloak: standard. Lose the realm and you lose admin login until you recreate it. The realm config is in version control if you exported it; otherwise back up Keycloak's own data. --- ## 8. Observability and alerting ### 8.1 Probes The Helm charts ship with liveness and readiness probes on both the admin service and the signature server. Kubernetes uses these to restart unhealthy pods and hold traffic from pods that are not ready. Defaults are in the charts; do not change them unless you have a reason. ### 8.2 Logging Both components log to stdout. `kubectl logs` works out of the box. Both use structured output, so an aggregator (ELK, Loki, Datadog) parses without custom config. The admin service log level is controlled by `springProfile`. `prod` logs at INFO. For deeper troubleshooting, set `springProfile: dev` and redeploy; switch back when you have what you need (the dev profile produces high-volume output and includes debug data you do not want in long-term storage). The signature server logs at INFO by default. The startup sequence (§4.3) logs each step, so a failed startup names the failing step without needing higher verbosity. ### 8.3 Metrics The signature server exposes `/metrics` on port 8080 with Prometheus scrape annotations. If you run Prometheus in your cluster, it picks up the endpoint with no extra setup. The annotations have no effect without a collector. The admin service does not expose a Prometheus endpoint in the current release. If you need admin service metrics, scrape Kubernetes-level metrics (pod uptime, restart count, resource usage) and pair them with the admin interface's own DID pool view. ### 8.4 Conditions to alert on Five failure conditions take the verification flow down or degrade it. Set alerts for each. **OpenBao sealed.** Every signature request requires OpenBao. A sealed OpenBao means zero signatures. The admin service and signature server logs both show connection failures. OpenBao reseals on every pod restart (§2.2). Alert on the bao seal status, or on a sustained pattern of OpenBao connection errors in the signature server logs. **Chia node out of sync.** A node behind chain head cannot verify current state. The admin interface shows sync status per node. Alert on any registered node leaving "synced" state. If your only synced node goes down, the admin service and signature servers lose chain visibility. §5.5 covers running multiple nodes. **Signature server heartbeat loss.** A stale heartbeat in the admin interface means the server holding that DID has stopped reporting. The admin service will release the DID after the timeout, but until it does, that DID is stuck. If the server crashed, the replacement blocks at startup waiting for an Available DID. Alert on heartbeat staleness exceeding the heartbeat interval by more than a small margin. **Signature DID pool not refilling.** The admin service maintains two unallocated DIDs and mints replacements as servers consume them. If the unallocated count drops to zero and stays there, the admin service is failing to mint, usually because no registered Chia node is synced or OpenBao is sealed. New signature servers will block at startup until the pool refills. Alert when the unallocated count stays at zero for more than a few minutes. **Julia Social connectivity loss.** Signature servers contact Julia Social once at startup (honest.bot credential) and once an hour (diagnostic count). Connectivity loss does not affect running servers or active verifications. It prevents new signature servers from starting and pauses diagnostic and MAU reporting. Alert on sustained egress failures, especially during scale-up windows. The Architecture & Privacy Guide §10 covers the operational consequences of each failure mode in more detail. --- ## 9. Support Email `support@julia.social` for deployment issues, configuration questions, or credential reissuance. When opening a ticket, include: - Your `customerId` and `organizationName` from `deployment-config.json`. - The component involved (admin service, signature server, OpenBao, Chia node, SDK). - Pod logs from the relevant component covering at least the last error. - The phase of the Deployment Checklist where the issue first showed up, if you are still in initial setup. Do not paste secrets, scoped tokens, or your unseal key into a support ticket. Support will never ask for them. --- > **not.bot Verify Web SDK Reference** — https://not.bot/technology/web-sdk/ · Markdown: https://not.bot/technology/web-sdk.md · Updated 2026-06-14 # not.bot™ Verify Web SDK Reference ## 1. Overview The not.bot Verify Web SDK (`julia_web_sdk`) is a server-side library that runs in an application backend. It connects the backend to the not.bot Verify signature servers and handles the verification flow: starting signature requests, proxying the cryptographic exchange between the not.bot app and the operator's signature servers, and delivering results back to the application through callbacks. The SDK is the final integration layer in the not.bot Verify stack. It sits between the operator's application backend and the signature servers deployed via the not.bot Verify Deployment Checklist. No user data or verification traffic ever reaches Julia Social. The entire exchange stays within the operator's infrastructure and the user's device. **Repository:** `https://github.com/julia-social/julia_web_sdk` **Version:** 1.0.0 (all languages) **Languages:** Rust (reference implementation), JavaScript (Express), Python (FastAPI), Java (Spring MVC), Dart (shelf) --- ## 2. Repository Layout ``` julia_web_sdk/ ├── rust/ # Rust crate, reference implementation │ ├── Cargo.toml │ └── src/ │ ├── lib.rs # ServiceBuilder + route handlers + WebSocket proxy │ ├── signature_client.rs │ ├── models.rs │ ├── claims.rs │ └── error.rs ├── javascript/ # JavaScript, Express adapter │ ├── package.json │ └── src/ │ ├── index.js # Re-exports all public API │ ├── models.js # ClaimProperties enum + Bytes32/ByteArray validators │ ├── client/ │ │ └── signatureClient.js # SignatureClient + QR code generation │ └── server/ │ └── expressAdapter.js # Express router + WebSocket proxy ├── python/ # Python, FastAPI adapter │ ├── pyproject.toml │ └── julia_web_sdk/ │ ├── __init__.py │ ├── claims.py # CLAIM_PROPERTIES dict │ ├── models.py # Pydantic models for all request/response types │ ├── client.py # SignatureClient + factory function │ └── server_fastapi.py # FastAPISignatureAdapter + WebSocket proxy ├── java/ # Java, Spring MVC adapter │ ├── pom.xml │ └── src/main/java/social/julia/sdk/ │ ├── ClaimProperties.java │ ├── JuliaWebSdkException.java │ ├── client/ │ │ └── SignatureClient.java │ ├── model/ │ │ └── SignatureModels.java │ └── server/ │ ├── SignatureAdapterConfig.java # Builder for adapter configuration │ ├── SpringSignatureController.java # REST controller │ ├── JuliaWebSocketConfig.java # WebSocket registration │ └── JuliaWebSocketProxyHandler.java # WS frame proxy ├── dart/ # Dart, shelf adapter │ ├── pubspec.yaml │ └── lib/ │ ├── julia_web_sdk.dart │ └── src/ │ ├── claims.dart │ ├── models.dart │ ├── signature_client.dart │ └── shelf_adapter.dart ├── examples/ # Runnable examples per language │ ├── javascript/ │ │ ├── express_server.mjs │ │ └── client_usage.mjs │ ├── python/ │ │ ├── fastapi_server.py │ │ └── client_usage.py │ ├── java/ │ │ ├── SpringSdkConfig.java │ │ └── SignatureClientExample.java │ ├── dart/ │ │ ├── shelf_server.dart │ │ └── client_usage.dart │ └── rust/ │ ├── server_integration.rs │ └── client_usage.rs └── shared/ ├── api_contract.md # Canonical endpoint contract (v1.0.0) └── claim_properties.txt # All claim property URIs ``` Each language directory also contains a `README.md` and its lock file. The repository root holds `README.md` and `LICENSE`. --- ## 3. Two Integration Paths ### 3.1 Server Adapter (recommended) Configure the adapter with verification requirements and callbacks; it mounts `/signature/*` routes into the web framework. The adapter handles session tracking, request-to-session mapping, and WebSocket proxying. The operator writes only the callbacks that decide what to do with verified results. ### 3.2 SignatureClient (lower-level) An HTTP client that calls signature server endpoints with no adapter layer. Use it for manual control over the flow, automation scripts, or when the framework has no matching adapter. --- ## 4. Environment Variables All languages read the same three environment variables: | Variable | Default | Purpose | |----------|---------|---------| | `SIGNATURE_HOSTNAME` | `localhost` | Hostname of the load balancer in front of signature servers | | `SIGNATURE_PORT` | `8080` | Port of the load balancer | | `SIGNATURE_API_KEY` | `CHANGE_ME` | API key that authenticates the backend to signature servers | The SDK uses HTTPS when `SIGNATURE_HOSTNAME` is anything other than `localhost`. --- ## 5. Adapter Configuration All language adapters accept the same six configuration options: | Option | Type | Default | Purpose | |--------|------|---------|---------| | `requestedClaims` | list of claim property URIs | `[]` | Credentials to request from the user (see Section 9) | | `requireSitePass` | boolean | `false` | When true, generates a per-user-per-site identifier | | `messageGenerator` | function → string | `() => ""` | Text the user sees in the not.bot app when approving | | `onSuccess` | callback(verifyResponse, session) | stores in session | Called when verification succeeds | | `onFailure` | callback(error) | no-op | Called when verification fails | | `expireTimeSeconds` | integer (seconds) | `3600` | How long a verification request stays valid | Option names appear here in JavaScript form. Python and Rust use snake_case equivalents: `requested_claims`, `require_site_pass`, `message_generator`, `on_success`, `on_failure`, and `expire_time_seconds` (Rust: `expire_time`). ### 5.1 onSuccess Callback The `onSuccess` callback receives two arguments: 1. **verifyResponse**: contains the user's alias DID, any requested claims, the Site Pass (if requested), a timestamp, and the cryptographic presentation. 2. **session**: the originating user's session, looked up via the request-to-session mapping. The adapter resolves this even when the verification response arrives on a different HTTP connection (the not.bot app is a separate client). ### 5.2 Session Behavior The adapter maps each `request_id` to the `session_id` that initiated it. This mapping lives in memory in the adapter process. If running multiple backend instances behind a load balancer, sticky sessions or a shared session store are required so the verification response routes back to the adapter instance holding the mapping. --- ## 6. SDK-Exposed Routes (Adapter Routes) Once mounted, the adapter serves these routes from the operator's backend: ### HTTP Routes | Route | Method | Called By | Purpose | |-------|--------|-----------|---------| | `/signature/notbot` | GET | Frontend | Starts a verification request. Returns a `request_id`. Frontend uses this to build the URL or QR code. | | `/signature/status` | GET | Frontend | Returns `true` if the current session has completed verification. Frontend polls this to update UI. | | `/signature/notbot/{request_id}` | POST | not.bot app | Accepts `{ "nonce": "" }`. Adapter proxies to upstream, returns `{ "compressed_presentation": [...] }`. | | `/signature/verify/{request_id}` | POST | not.bot app | Accepts `{ "presentation": [...] }`. Adapter proxies verification to upstream, fires `onSuccess` or `onFailure`. Returns `204` on success. | ### WebSocket Routes | Route | Header Forwarded | Purpose | |-------|-----------------|---------| | `/signature/honestbot` | `x-presentation-hash` | Proxied to upstream signature server for honest.bot™ credential verification | | `/calculate_site_pass` | `x-site-pass` | Proxied to upstream signature server for Site Pass computation | **WebSocket proxy safety:** The adapter's upstream base URL must target the external signature service, not the same host serving SDK adapter routes. Pointing both to the same `/signature/*` host creates proxy-to-self loops on `/signature/honestbot`. --- ## 7. Upstream Signature Server Endpoints (Called by SDK) These are the endpoints the SDK calls on the signature servers (via the load balancer): | Endpoint | Method | Request Body | Response | |----------|--------|-------------|----------| | `/signature/start` | POST | `StartSignatureRequest` (see 7.1) | `{ "request_id": "..." }` | | `/signature/presentation` | POST | `{ "request_id": "...", "nonce": "" }` | `{ "compressed_presentation": [...] }` | | `/signature/verify` | POST | `{ "request_id": "...", "presentation": [...] }` | `VerifySignatureResponse` (see 7.2) | | `/signature/honestbot` | WS | n/a | Binary/text frame proxy | | `/calculate_site_pass` | WS | n/a | Binary/text frame proxy | All upstream HTTP calls include the `api-key` header with the value from `SIGNATURE_API_KEY`. ### 7.1 StartSignatureRequest ```json { "requested_credentials": ["julia://./v1/pii/age_over_18"], "require_site_pass": true, "required_alias_launcher": null, "requested_message": [86, 101, 114, 105, 102, 121], "expires": 1730000000 } ``` Fields: - `requested_credentials`: list of claim property URI strings - `require_site_pass`: boolean - `required_alias_launcher`: optional Bytes32 (null for most flows) - `requested_message`: UTF-8 bytes of the message the user sees in the not.bot app - `expires`: Unix UTC timestamp for request expiry ### 7.2 VerifySignatureResponse ```json { "alias_did": { "launcher_id": [0, 1, 2, ...] }, "site_pass": "0x00112233...", "claims": [ { "property": "julia://./v1/pii/age_over_18", "value": [1] } ], "timestamp": 1730000000, "presentation": [1, 2, 3, ...] } ``` Fields: - `alias_did.launcher_id`: 32-byte array identifying the user's alias DID - `site_pass`: Bytes32 hex string, present when `require_site_pass` was true - `claims`: list of verified claims with property URI and byte-encoded value - `timestamp`: Unix UTC timestamp of verification - `presentation`: the full cryptographic presentation bytes --- ## 8. Data Encoding Conventions | Type | Encoding | Example | |------|----------|---------| | `Bytes32` | 0x-prefixed, 64-char lowercase hex | `"0x00112233..."` | | `Vec` / byte arrays | JSON array of integers 0–255 | `[86, 101, 114]` | | Timestamps | Unix UTC seconds | `1730000000` | The byte-array encoding matches Rust `serde` defaults and is consistent across all language implementations. --- ## 9. Claim Properties Claims are identified by URI strings. The full list is in `shared/claim_properties.txt`. Each claim property maps a short name to a URI. ### 9.1 Bot Detection | Name | URI | Category | |------|-----|----------| | `Notbot0` | `notbot://./v1/notbot0` | Basic bot detection | | `Notbot1` | `notbot://./v1/notbot1` | Enhanced bot detection | | `Notbot2` | `notbot://./v1/notbot2` | Highest bot detection | ### 9.2 Honest.bot & Licensing | Name | URI | Category | |------|-----|----------| | `Honestbot0` | `notbot://./v1/honestbot0` | Honest.bot credential | | `SignatureLicense` | `notbot://./v1/signature_license` | Signature license | ### 9.3 Site & Account | Name | URI | Category | |------|-----|----------| | `SitePass` | `julia://./v1/site_pass` | Per-user-per-site pseudonym | | `AccountName` | `sha2-256\|CBOR://./v1/account_name` | Account name (hashed) | | `DomainName` | `sha2-256\|CBOR://./v1/domain_name` | Domain name (hashed) | ### 9.4 PII (Personal Identifiable Information) | Name | URI | |------|-----| | `FirstName` | `julia://./v1/pii/first_name` | | `GivenNames` | `julia://./v1/pii/given_names` | | `FamilyName` | `julia://./v1/pii/family_name` | | `Gender` | `julia://./v1/pii/gender` | | `Nationality` | `julia://./v1/pii/nationality` | | `BirthDate` | `julia://./v1/pii/date_of_birth` | | `BirthDay` | `julia://./v1/pii/birth_day` | | `BirthMonth` | `julia://./v1/pii/birth_month` | | `BirthYear` | `julia://./v1/pii/birth_year` | ### 9.5 Age Verification **Threshold claims:** `AgeOver13` through `AgeOver25`, plus `AgeOver100`. Each proves the user is at or above the specified age without revealing the actual age. | Name | URI | |------|-----| | `Age` | `julia://./v1/pii/age` | | `AgeOver13` | `julia://./v1/pii/age_over_13` | | `AgeOver14` | `julia://./v1/pii/age_over_14` | | `AgeOver15` | `julia://./v1/pii/age_over_15` | | `AgeOver16` | `julia://./v1/pii/age_over_16` | | `AgeOver17` | `julia://./v1/pii/age_over_17` | | `AgeOver18` | `julia://./v1/pii/age_over_18` | | `AgeOver19` | `julia://./v1/pii/age_over_19` | | `AgeOver20` | `julia://./v1/pii/age_over_20` | | `AgeOver21` | `julia://./v1/pii/age_over_21` | | `AgeOver22` | `julia://./v1/pii/age_over_22` | | `AgeOver23` | `julia://./v1/pii/age_over_23` | | `AgeOver24` | `julia://./v1/pii/age_over_24` | | `AgeOver25` | `julia://./v1/pii/age_over_25` | | `AgeOver100` | `julia://./v1/pii/age_over_100` | **Range claims:** Five-year and ten-year age brackets. Five-year brackets: `AgeRange20To24`, `AgeRange25To29`, `AgeRange30To34`, `AgeRange35To39`, `AgeRange40To44`, `AgeRange45To49`, `AgeRange50To54`, `AgeRange55To59`, `AgeRange60To64`, `AgeRange65To69`, `AgeRange70To74`, `AgeRange75To79`, `AgeRange80To84`, `AgeRange85To89`, `AgeRange90To94`, `AgeRange95To99`. Ten-year brackets: `AgeRange20To29`, `AgeRange30To39`, `AgeRange40To49`, `AgeRange50To59`, `AgeRange60To69`, `AgeRange70To79`, `AgeRange80To89`, `AgeRange90To99`. All age range URIs follow the pattern `julia://./v1/pii/age_range_{low}_{high}`. --- ## 10. Verification Flow (Step by Step) This is the complete flow as implemented in the SDK adapter code: 1. **Frontend calls `GET /signature/notbot`** on the SDK adapter. 2. The adapter clears any existing verification from the session. 3. The adapter calls **`POST /signature/start`** on the upstream signature server (via load balancer) with the configured claims, Site Pass requirement, message bytes, and expiry timestamp. 4. The signature server returns a `request_id`. 5. The adapter stores a **`request_id → session_id` mapping** in memory and returns the `request_id` to the frontend. 6. The frontend builds an **App Link URL** from the request_id: `https://not.bot/s1/{request_id}/{hostname}/{port}` and presents it as a tappable link (mobile) or QR code (desktop). 7. The **not.bot app** opens, connects to the SDK adapter endpoints, and begins the cryptographic exchange: - `POST /signature/notbot/{request_id}` with a nonce → adapter proxies to `POST /signature/presentation` upstream → returns `compressed_presentation`. - `POST /signature/verify/{request_id}` with the signed presentation → adapter proxies to `POST /signature/verify` upstream. - WebSocket connections on `/signature/honestbot` and `/calculate_site_pass` are proxied to upstream. 8. If upstream verification succeeds, the adapter looks up the originating session via the `request_id → session_id` mapping and calls **`onSuccess(verifyResponse, session)`**. 9. The frontend polls **`GET /signature/status`** to detect completion and update the UI. ### Network Path During the verification exchange, traffic flows: user's phone → SDK adapter → signature servers. No packets reach Julia Social at any point. The entire exchange stays within the operator's infrastructure and the user's device. --- ## 11. Language-Specific Implementation Details ### 11.1 Rust **Framework:** portfu (custom framework from GalactechsLLC) **Key dependencies:** - `dg_xch_core`: Chia blockchain primitives (`Bytes32`, BLS types) - `portfu`: Web framework with macros, sessions, WebSocket support - `reqwest`: HTTP client with cookie store - `tokio`: Async runtime - `time`: Timestamp handling **Architecture:** The `ServiceBuilder` uses the builder pattern to configure claims, callbacks, and settings, then `.build()` converts it into a `ServiceGroup` (portfu's route group). Routes are defined with `#[get(...)]`, `#[post(...)]`, and `#[websocket(...)]` macros. Session state uses `Arc>` with portfu's `SessionManager`. **Notable implementation detail:** The Rust implementation uses `portfu::wrappers::sessions::Session` which stores typed data via `session.data.insert(response)` / `session.data.get::()`. The WebSocket proxy uses `tokio_tungstenite` and runs a polling loop that alternates reads between the client and upstream sockets. **Error handling:** Uses a custom `Error` type with `ErrorCode` enum covering client errors (4xx range), server errors (5xx range), and Chia-specific errors (6xx range: CLVM, Garbler, Evaluator, BLS signature/credential/proof). ### 11.2 JavaScript **Framework:** Express 5.x **Key dependencies:** - `express` ^5.1.0 - `express-session` ^1.18.2 - `qrcode` ^1.5.4 (QR code generation for `getSignatureRequestId()`) - `ws` ^8.18.3 (WebSocket) **Node.js requirement:** >=18 **Package type:** ES Module (`"type": "module"`) **Exports:** ```javascript import { ClaimProperties, // Frozen object of all claim URIs createSignatureClient, // Factory function → SignatureClient createExpressSignatureAdapter, // Factory → { router, attachWebsocketHandlers } SignatureClient, // Class for direct endpoint calls JuliaWebSdkError, // Custom error with status + body bytes32, // Validator for Bytes32 hex strings byteArray // Validator for byte arrays } from "julia_web_sdk"; ``` **Integration pattern:** ```javascript const signatureAdapter = createExpressSignatureAdapter({ signatureClient: createSignatureClient(), requestedClaims: [ClaimProperties.Notbot0, ClaimProperties.AgeOver18], requireSitePass: true, messageGenerator: () => "Verifying my identity with example.com", onSuccess: async (verifyResponse, session) => { session.juliaSignatureVerification = verifyResponse; }, onFailure: async (error) => { console.error("verification failure", error); }, }); app.use(signatureAdapter.router); signatureAdapter.attachWebsocketHandlers(httpServer); ``` **Session handling:** Uses `req.sessionID` and `req.sessionStore` for cross-connection session resolution. The adapter's `requestToSignatureSession` is an in-memory `Map`. **WebSocket proxy:** Uses the `ws` library's `WebSocketServer` with `noServer: true`. Upgrades are intercepted on the HTTP server's `upgrade` event. The proxy forwards `x-presentation-hash` and `x-site-pass` headers. **SignatureClient extras:** The JS client includes `getSignatureRequestId()` which calls `/signature/notbot`, builds the `https://not.bot/` App Link URL, generates a QR code via the `qrcode` library, and returns `{ request_id, qr_code, url }`. ### 11.3 Python **Framework:** FastAPI **Key dependencies:** - `fastapi` >=0.115.0 - `httpx` >=0.27.0 (async HTTP client) - `pydantic` >=2.8.0 (data models) - `websockets` >=13.1 (WebSocket client) **Python requirement:** >=3.10 **Exports:** ```python from julia_web_sdk import ( CLAIM_PROPERTIES, # Dict[str, str] of all claim URIs FastAPISignatureAdapter, # Adapter class create_fastapi_router, # Shorthand factory SignatureClient, # Direct HTTP client SignatureClientConfig, # Dataclass for client config create_signature_client_from_env, # Factory from env vars JuliaWebSdkError, # Custom exception ) ``` **Integration pattern:** ```python from julia_web_sdk import FastAPISignatureAdapter, create_signature_client_from_env, CLAIM_PROPERTIES adapter = FastAPISignatureAdapter( signature_client=create_signature_client_from_env(), requested_claims=[CLAIM_PROPERTIES["Notbot0"], CLAIM_PROPERTIES["AgeOver18"]], require_site_pass=True, message_generator=lambda: "Verifying my identity with example.com", ) app.include_router(adapter.router) ``` **Session handling:** The Python adapter uses `session_cookie_name` (default: `"session"`) to read the session cookie value. The session-to-request mapping (`session_signatures`) is an in-memory dict. An optional `resolve_session` callback allows custom session resolution for cross-connection flows. **Data models:** All request/response types are Pydantic v2 `BaseModel` subclasses: `StartSignatureRequest`, `StartSignatureResponse`, `GeneratePresentationRequest`, `GeneratePresentationResponse`, `VerifySignatureRequest`, `VerifySignatureResponse`, `Claim`, `DIDInfo`, `ServerPresentation`, `ClientPresentation`, `SignatureRequest`. **WebSocket proxy:** Uses the `websockets` library (`websockets.connect`). Runs two async tasks (`from_client` and `from_upstream`) in parallel via `asyncio.wait(FIRST_COMPLETED)`, canceling the other when one completes. ### 11.4 Java **Framework:** Spring MVC 6.x + Spring WebSocket **Key dependencies:** - `jackson-databind` 2.17.2 - `spring-webmvc` 6.1.12 - `spring-websocket` 6.1.12 - `jakarta.servlet-api` 6.0.0 **Java requirement:** 17+ **Architecture:** Four classes comprise the server adapter: - `SignatureAdapterConfig`: Builder pattern for adapter configuration with functional interfaces `OnSuccess`, `OnFailure`, and `SessionResolver`. - `SpringSignatureController`: `@RestController` with `@GetMapping`/`@PostMapping` handlers for the four HTTP routes. - `JuliaWebSocketConfig`: `WebSocketConfigurer` that registers the two WebSocket proxy handlers. - `JuliaWebSocketProxyHandler`: `AbstractWebSocketHandler` that proxies frames in both directions using `java.net.http.WebSocket`. **Session handling:** Uses `ConcurrentHashMap` for `request_id → session_id` mapping. The `SessionResolver` functional interface allows custom session lookup. **SignatureClient:** Uses `java.net.http.HttpClient` with async `sendAsync()` returning `CompletableFuture`. JSON serialization via Jackson `ObjectMapper` with `PropertyNamingStrategies.SNAKE_CASE`. **Integration pattern:** ```java @Bean public SignatureAdapterConfig signatureAdapterConfig() { return SignatureAdapterConfig.builder() .requestedClaims(List.of(ClaimProperties.NOTBOT0, ClaimProperties.AGE_OVER_18)) .requireSitePass(true) .messageGenerator(() -> "Verifying my identity with example.com") .onSuccess((response, session) -> { session.setAttribute("juliaSignatureVerification", response); }) .build(); } ``` ### 11.5 Dart **Framework:** shelf + shelf_router **Key dependencies:** - `http` ^1.2.2 - `shelf` ^1.4.1 - `shelf_router` ^1.1.4 - `shelf_web_socket` ^2.0.0 - `web_socket_channel` ^3.0.1 **Dart SDK requirement:** >=3.4.0 <4.0.0 **Architecture:** Follows the same pattern as other languages: `SignatureClient` for HTTP calls, `ShelfSignatureAdapter` for mounting routes. WebSocket proxying uses `web_socket_channel` for upstream connections and `shelf_web_socket` for incoming connections. --- ## 12. SignatureClient API (All Languages) The `SignatureClient` provides both upstream (signature server) and SDK adapter endpoint methods. ### 12.1 Upstream Methods (require API key) | Method | Calls | Returns | |--------|-------|---------| | `startSignature(request)` | `POST /signature/start` | `{ request_id }` | | `generatePresentation(request)` | `POST /signature/presentation` | `{ compressed_presentation }` | | `verifyPresentation(request)` | `POST /signature/verify` | `VerifySignatureResponse` | ### 12.2 SDK Adapter Methods (no API key, uses cookies/credentials) | Method | Calls | Returns | |--------|-------|---------| | `getSignatureRequestId()` | `GET /signature/notbot` | request_id string (JS also returns QR + URL) | | `getSignatureStatus()` | `GET /signature/status` | boolean | | `generateSignaturePresentation(requestId, nonce)` | `POST /signature/notbot/{id}` | `{ compressed_presentation }` | | `verifySignaturePresentation(requestId, presentation)` | `POST /signature/verify/{id}` | void (204) | ### 12.3 Constructor Options | Option | Default | Purpose | |--------|---------|---------| | `baseUrl` / `host` + `port` | from env vars | Signature server address | | `apiKey` | `SIGNATURE_API_KEY` env var | Authentication key | | `timeout` | 180 seconds | Request timeout | | `secure` | `true` unless localhost | Use HTTPS | --- ## 13. Error Handling All language implementations throw/raise a custom error type when API calls fail: | Language | Error Type | Properties | |----------|-----------|------------| | Rust | `error::Error` | `message: String`, `code: ErrorCode` | | JavaScript | `JuliaWebSdkError` | `message`, `status`, `body` | | Python | `JuliaWebSdkError` | `message`, `status_code`, `body` | | Java | `JuliaWebSdkException` | `message`, `statusCode`, `body` | | Dart | `JuliaWebSdkException` | `message`, `statusCode`, `body` | The Rust `ErrorCode` enum is the most detailed: a retry band (300-301), client errors (400-499), server errors (500-518), and Chia/MPC/BLS errors (600-605), plus a catch-all `Other` (999). ### 13.1 Adapter Error Responses | Scenario | HTTP Status | Handler | |----------|-------------|---------| | Upstream signature server unreachable | 502 | `onFailure` called | | Missing nonce or presentation in request body | 400 | Direct error response | | Upstream verification rejects the presentation | 422 | `onFailure` called | | `onSuccess` callback throws | 500 | `onFailure` called | --- ## 14. Quick Start Per Language ### JavaScript ```bash cd javascript && npm install # Set env vars: SIGNATURE_HOSTNAME, SIGNATURE_PORT, SIGNATURE_API_KEY node examples/javascript/express_server.mjs ``` ### Python ```bash cd python && pip install -e . # Set env vars uvicorn examples.python.fastapi_server:app ``` ### Java ```bash cd java && mvn -q package # Integrate SignatureAdapterConfig + SpringSignatureController into Spring Boot app ``` ### Dart ```bash cd dart && dart pub get dart run examples/dart/shelf_server.dart ``` ### Rust ```bash cd rust && cargo check # Integrate ServiceBuilder into portfu application ``` --- ## 15. Operational Considerations ### 15.1 Session Stickiness The `request_id → session_id` mapping lives in memory. When running multiple backend instances behind a load balancer, either use sticky sessions or a shared session store. Without this, the verification response may arrive at a different adapter instance than the one holding the mapping, and the `onSuccess` callback will not find the correct session. ### 15.2 WebSocket Proxy Loops Configure `SIGNATURE_HOSTNAME` to point at the signature server load balancer, not at the host running the SDK adapter. If both point at the same host, the WebSocket proxy will loop back to itself on `/signature/honestbot`. ### 15.3 Timeout All language clients default to a 180-second timeout on all HTTP requests to the signature server. This accommodates the time a user may take to approve the verification in the not.bot app. ### 15.4 not.bot App Link Format The JavaScript `SignatureClient` builds App Links in this format: ``` https://not.bot/s1/{request_id}/{hostname}/{port} ``` The `https://not.bot/` form is an App Link (iOS Universal Link / Android App Link). On mobile, it opens the not.bot app. On desktop, the URL renders as a QR code the user scans with a phone. --- ## 16. Relationship to Other Components The SDK is the final layer in the not.bot Verify deployment stack: ```mermaid flowchart TB frontend["Frontend (QR / Link, in user's browser)"] phone["User's phone: not.bot app
(talks only to the operator's backend)"] subgraph infra["Operator's Infrastructure"] backend["Backend + SDK Adapter
/signature/* routes
(runs outside the cluster)"] subgraph cluster["Kubernetes cluster (private, no public ingress)"] siglb["Signature-server LB (internal)"] sig["Signature servers (load balanced)"] admin["Admin service
(mints signature DID pool, issues the SDK API key)"] bao["OpenBao + Chiakeys (DID keys)"] chia["Chia nodes"] end end frontend <--> backend phone -->|"https://not.bot App Link"| backend backend -->|"proxies /signature/*"| siglb siglb --> sig sig <-->|"scoped token → DID keys"| bao sig <-->|"mTLS"| chia admin --> bao admin --> chia sig -.->|"registers, heartbeats, pulls config"| admin ``` For the full deployment topology, including PostgreSQL, Keycloak, the operator's edge, and the two hourly aggregate counts to Julia Social, see the Architecture and Privacy Guide §4. The SDK depends on: - **Signature servers** being deployed and healthy (Architecture and Privacy Guide §3, §6) - **Signature DID pool** being minted (Architecture and Privacy Guide §6, "Scaling") - **Admin service** running (Architecture and Privacy Guide §3) - **Load balancer / ingress** configured to route to signature servers (Architecture and Privacy Guide §4) - **API key** obtained from the admin interface (Deployment Checklist, Phase 9) The SDK does NOT communicate with Julia Social. All traffic stays within the operator's infrastructure.