{"slug": "we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works", "title": "We sign every export our AI app builder produces. Here's how it works", "summary": "A developer building SPOE, an AI app builder, has implemented cryptographic signing of every code export the tool produces, shipping a PROVENANCE.json manifest, an Ed25519 signature file, and a ~40-line dependency-free Node verifier with each project. The manifest records per-file SHA-256 hashes, a tree hash, the generator and reviewer models, and the signer's public key, while a pre-export lint blocks any export that references SPOE packages, environment variables, or APIs.", "body_md": "I'm building SPOE, an AI app builder. Every tool in this space says \"you own your code\". I wanted to be able to prove it, so every export SPOE produces is signed. This is how that works, in enough detail that you can poke holes in it.\n\nWhen an AI writes your app, two questions follow the code around. Is this exactly what I was shown? And does it quietly depend on the tool that made it? A ZIP answers neither.\n\nThree files ride along with every project: `PROVENANCE.json`, `PROVENANCE.sig` and `verify-provenance.mjs`.\n\n`PROVENANCE.json` lists every file with its SHA-256 and size, a hash over the whole tree, which models wrote and reviewed the changes (never the prompts), and the signer's public key:\n\n```\n{\n  \"spoe_provenance\": \"1\",\n  \"project\": { \"slug\": \"tint-booker\", \"stack\": { \"frontend\": \"nextjs\", \"backend\": \"node\", \"database\": \"postgres\" } },\n  \"version\": { \"number\": 2 },\n  \"files\": [{ \"path\": \"web/app/page.tsx\", \"sha256\": \"9f2c…\", \"bytes\": 1834 }],\n  \"tree_sha256\": \"41ad…\",\n  \"generations\": [\n    { \"role\": \"generator\", \"model\": \"…\" },\n    { \"role\": \"reviewer\", \"model\": \"…\" }\n  ],\n  \"signer\": { \"alg\": \"ed25519\", \"key_id\": \"c85280961cc26721\", \"public_key_pem\": \"-----BEGIN PUBLIC KEY-----…\" }\n}\n```\n\nThe signature in `PROVENANCE.sig` is Ed25519 over a canonical form of that JSON: keys sorted recursively, no whitespace. The tree hash is SHA-256 over the sorted lines `path\\0sha256\\n`, so the order files happen to be zipped in never matters. The key id is the first 16 hex characters of the SHA-256 of the public key's DER encoding.\n\nThe verifier is about 40 lines of plain Node 18+, with no packages and no network:\n\n``` bash\n$ node verify-provenance.mjs\nOK   signature valid (key_id c85280961cc26721)\nOK   30 files match manifest\nVERIFIED - exported 2026-10-09T01:24:13Z from project tint-booker v2\n```\n\nIt checks that the key id matches the embedded key, that the signature is valid, that every listed file is on disk with the right hash, and the tree hash. It exits 1 if anything is off.\n\nA valid signature only tells you the files match a key. To know who signed it, compare the key id with the keys spoe.ai publishes at [spoe.ai/api/signing-keys](https://spoe.ai/api/signing-keys). The page at [spoe.ai/verify](https://spoe.ai/verify?ref=devto) does all of this in your browser without uploading the ZIP, and also lists any file in the ZIP that the manifest doesn't know about. The offline script is getting that same check next.\n\nBefore an export is signed, a lint refuses it if anything ties it back to SPOE: an import of an SPOE package, a dependency on one, code reading `SPOE_*` environment variables, a call to SPOE's API, or one of our internal folders. No warnings, no override.\n\nAnd CI does the whole thing on every commit: export the scaffold, unzip it into an empty directory, verify the signature, `docker compose up`, hit the health check. If that fails, nothing ships.\n\nEvery change the builder makes is reviewed by a second model from a different model family before it lands. A critical finding blocks the change whatever the reviewer's own verdict says, and a review that times out or errors is never treated as a pass: it waits for a human.\n\nA signature proves integrity and origin, not quality. It can't tell you the code is free of bugs or safe to run; the review and your own eyes are for that. It also says nothing about the prompts, which are deliberately left out of the manifest.\n\nSPOE is at [spoe.ai](https://spoe.ai/?ref=devto). It's free to start (50 credits on sign-up and a daily top-up), runs on Venice's private models, and your first payment of any size unlocks export for good.\n\nI'd especially like critique of the manifest format and the verifier. What would you need to see before you trusted an export from a tool like this?", "url": "https://wpnews.pro/news/we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works", "canonical_source": "https://dev.to/slavripa/we-sign-every-export-our-ai-app-builder-produces-heres-how-it-works-33ae", "published_at": "2026-10-10 01:49:26+00:00", "updated_at": "2026-10-10 01:59:25.338039+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-agents", "ai-products"], "entities": ["SPOE", "Venice", "Node.js", "Ed25519"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works", "markdown": "https://wpnews.pro/news/we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works.md", "text": "https://wpnews.pro/news/we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works.txt", "jsonld": "https://wpnews.pro/news/we-sign-every-export-our-ai-app-builder-produces-here-s-how-it-works.jsonld"}}