# sgit.ai — complete documentation, single file > Every page of https://sgit.ai concatenated into one document, generated at build time > (v0.2.38). Nothing here needs a second request. Individual pages live at the paths > shown below, as markdown (`.md`) and as HTML (`.html`); the annotated map is /llms.txt. > > sgit is git for encrypted vaults: clone, commit, branch and merge files that are encrypted > client-side (AES-256-GCM) before they leave your machine. The server stores ciphertext under > opaque IDs — it never sees filenames, contents, or commit messages. ============================================================================== # sgit — the encrypted git for humans and AI agents > sgit is git for encrypted vaults: clone, commit, branch and merge files that are encrypted before they leave your machine. Zero knowledge — the server stores ciphertext, not your data. > > Page: https://sgit.ai/index.html Agents need private, versioned state # The encrypted git for humans and AI agents Version, branch, and share vaults of files that are encrypted before they leave your machine. Zero knowledge: the server stores ciphertext, not your data. [Or try it in your browser →](try/index.md) [5-minute quickstart →](docs/quickstart.md) Pure Python · two runtime dependencies · Apache-2.0 $sgit create my-vault ✓ Vault created and registered ✓ Initial commit pushed Vault key: <24-char-passphrase>: Keep this safe — it is the address, the auth, and the encryption key in one string. Without it, nobody — including the server — can read this vault. $vim notes/positioning.md $sgit status On clone branch branch-clone-3f9c → named branch main modified: notes/positioning.md added: drafts/hero-copy.md $sgit commit -m "first draft of hero copy" ✓ Committed 2 files (no staging area — commit snapshots the folder) $sgit history log --oneline c4e81a first draft of hero copy b2d70f initial commit $sgit history diff --- a/notes/positioning.md +++ b/notes/positioning.md - sgit is a CLI for encrypted sync + sgit is git for encrypted vaults $sgit push ✓ Pushed 2 objects (delta push — only changed, only ciphertext) # on another machine (or another agent) $sgit clone ✓ Cloned and decrypted 12 files $sgit pull ✓ Up to date # one call: encrypt, commit, push, machine-readable result — # no working-directory scan, no full clone needed $sgit write notes/finding.md --file result.md \ --message "agent A: analysis" --push --json { "status": "pushed", "path": "notes/finding.md", "blob_id": "obj-cas-imm-9c2e41ab77d0" } The vault key is the address, the auth, and the encryption key — one high-entropy string. Keep it safe. ## Git workflows. Encrypted vaults. Zero knowledge. sgit is git for encrypted vaults: clone, commit, branch, diff and merge folders of files that are encrypted with AES-256-GCM before they leave your machine. **Git-like version control**commit, branch, merge, diff, log, stash, revert your encrypted files **Client-side encryption**AES-256-GCM before upload; keys derived from your vault key, never sent to the server **Real three-way merge**conflict files plus a base/ours/theirs `resolve --show` view **The two-branch model**a private clone branch per machine or agent; shared named branches for collaboration **Sparse & thin clones**structure now, content on demand — for agents on a time budget **Browser interop**open the same vault in SG/Vault on the web — CLI and browser speak one wire format ## What the server sees ### Your machine - filenames & folder structure - file contents - commit messages - branch names - the vault key & derived keys *[diagram]* ### The server - obj-cas-imm-3f9c41ab77d0 - ref-pid-muw-8e02cc194b3a - ciphertext blobs (AES-256-GCM) - object sizes · timestamps - the vault id That's the whole list — and we publish the threat model, including what the server *can* see (sizes, timing, vault ID). [Read the security model →](security/index.md) ## Built for agents Agents need shared state. Shared state needs versioning — and privacy. sgit is the encrypted, versioned workspace for humans and AI agents. Persistent memory ### A vault is just a folder An agent clones it, reads and writes files normally, commits, pushes. The next session pulls and continues. State survives the context window. Multi-agent, human-merged ### A branch per agent Each agent gets its own private clone branch; work meets on named branches; a human reviews the merge — in the terminal or in the SG/Vault browser. Agent-grade plumbing ### Machine-readable everything `sgit write` for surgical single-call commits, `--json` on every read path, `cat --id` with zero network calls, sparse clones for fast cold starts. [Read the agent guide →](docs/agents.md) · [Install the skills →](skills/index.md) · [llms.txt](llms.txt) ## What people use it for [Use case### Private memory for AI agentsDurable, versioned state between sessions — encrypted end to end.Read →](use-cases/index.md#ai-agents) [Use case### Multi-agent collaborationAgents on their own branches, humans reviewing the merge.Read →](use-cases/index.md#multi-agent) [Use case### Human ↔ agent workspacesYou in the SG/Vault browser, the agent in the CLI — same vault.Read →](use-cases/index.md#human-ai) [Use case### Encrypted folders with historyA shared folder the hosting provider cannot read, with rollback.Read →](use-cases/index.md#encrypted-backup) [Use case### Signed & encrypted exchangePKI: sign, verify, encrypt and decrypt files for named recipients.Read →](use-cases/index.md#secure-file-exchange) ## In production — and honest about it sgit is in beta, powering production workflows daily. No superlatives — just the evidence, and a page that tells you when *not* to use it. **~4,000** tests**mutation testing** in CI**integration tests** against a real server**2** runtime dependencies**Apache-2.0** [**security model** published](security/index.md) [**when NOT** to use sgit](docs/limitations.md) [**why** does this exist?](why/index.md) ## One vault, three doors Think of it as **sgit** — git, for encrypted vaults Open source CLI. Free. Apache-2.0. `pip install sgit-ai` Think of it as **SG/Vault** — the web app for your vaults Browse, edit and review the same vaults in the browser — an independent implementation of the same wire format. [Platform docs →](vault/index.md) · [sgraph.ai](https://sgraph.ai) Think of it as **SG/Send** — the transfer API underneath The zero-knowledge storage service both clients speak to — the same server the integration tests run against. [Platform docs →](vault/index.md) · [sgraph.ai](https://sgraph.ai) Encrypted vaults. **Git workflows.** Zero knowledge. [5-minute quickstart →](docs/quickstart.md) [Star on GitHub →](https://github.com/SGit-AI/SGit-AI__CLI) ============================================================================== # The vault catalogue — sgit.ai > An index of published vaults rendered live from a vault that indexes vaults, including itself. Each entry: a deliberately published read key, shape, evidence status, copy-or-reference semantics, and write-key status (known-and-escrowed or lost — a frozen vault can never be corrected). Submitting a vault costs a read key and one line; the rest is derived. > > Page: https://sgit.ai/catalogue/index.html [Home](../index.md) / Catalogue # The vault catalogue An index of published vaults, rendered live from a vault that indexes vaults — including itself. Every entry carries a deliberately published read key, an honest evidence status, and its write-key status, because a vault whose write key is lost can never be corrected and a reader deserves to know. **The design constraint, stated openly:** the bottleneck is one person with a backlog of vaults, so an entry costs **a read key and one line** — everything else (listing, sizes, commit count, whether an app is present) is derived by an agent opening the vault with the key it was just given. The two to-do queues are published in the catalogue itself: a named gap gets filled, an unnamed one does not. This page renders vault `kc67yhgw` directly — a push to it updates this page with no site deploy. The human companion is [the published-vaults gallery](../demos/vaults/index.md): one page per vault, with the vault running live in it. opening the catalogue… Fetching the encrypted index… ### Vault debug [how this works →](../case-studies/live-vault-docs.md) not open yet what you are looking at Every row above is an encrypted object pulled from the SG/Send API and decrypted locally — click one to see what it actually contains. Objects whose id contains **-imm-** are content-addressed and therefore immutable, so they are cached permanently; the mutable **ref** is the one mutable object, so it is checked at most once per freshness window (120s) rather than once per page — inside the window, reading the docs makes no requests at all, and **check for new commit** forces one whenever you want it. The **tree** objects are the reason a first visit reads more than one file: filenames are encrypted inside them, so building the navigation means reading every directory. That index is a pure function of the commit id, so it is memoised — after the first visit, an unchanged commit reads no tree objects at all. Nothing here is stored on sgit.ai. [How this page works →](../case-studies/live-vault-docs.md) Architecture diagrams, the object model, the cache tiers, and how a page like this one reads a vault it holds only the read key to. ============================================================================== # Comparisons, as tests you can re-run — sgit.ai > What a task costs with vaults and without, published by a participant and built to be challenged: every entry states the steps, the date, the result and how to re-run it. Includes a privilege vocabulary, and one comparison vaults lose. > > Page: https://sgit.ai/compare/index.html [Home](../index.md) / Comparisons # Comparisons, as tests you can re-run What a task costs with vaults, and without them. This page is not unbiased — it is published by a participant, and nobody should read it as neutral. It is built to be **challengeable** instead: every entry states the exact steps attempted, the date, what happened, and how to run it yourself. **Why not "unbiased".** A comparison published by one of the parties is not a neutral instrument, and claiming otherwise would be the least credible thing on this site. The achievable and stronger property is reproducibility: **an assertion that is wrong gets screenshotted; an experiment that is wrong gets corrected.** If an entry here is out of date or simply mistaken, the fix is a re-run, and the correction improves the page rather than discrediting it. [Tell us](mailto:) or open an issue on [GitHub](https://github.com/SGit-AI/SGit-AI__CLI). ## The asymmetry, stated up front Our rows can be **executed**. A script opens a published vault, tries the operation and records what happened — it runs on demand and fails loudly when reality moves. Rows about anybody else's product cannot work that way: there is no API for "how many steps does this take in a desktop app", and automating someone's product against their terms is not something we will do. Those rows are **checked by hand, by a person, on a stated date**. So the two kinds of row carry different badges, and you should trust them differently: | Badge | Means | Ages | |---|---|---| | **machine-verified** | An automated check against the live service, in `admin/build/compare_tests.py`. The evidence below each claim is its actual output | Re-run any time; the date is the last run | | **hand-checked** | A person performed the steps on the date shown and wrote down what happened | Decays. Past the expiry it renders as **unverified**, not as fact | Loading verification status… ## The entry format Every entry answers the same eight things. Anything that cannot be filled in honestly does not get published. | Field | Why it is there | |---|---| | **Task** | Stated concretely enough that somebody can attempt it | | **Steps** | Countable and disputable on facts. The number is a *summary*; the transcript below it is the evidence, because step counts are gamed by where you start counting | | **Prerequisites** | Accounts, subscriptions, installs. This is where cost actually lands | | **Privileges granted** | What the counterparty can now reach. The column that usually decides the answer — see the vocabulary below | | **Where it runs** | Your machine, or theirs | | **Survives the vendor** | Whether the artefact still works if the service stops | | **Verified** | The date, and whether by machine or by hand | | **Re-run it** | The command or the steps, so the claim is auditable rather than trusted | ## The privilege vocabulary "Share it with them" hides the entire question. These seven properties make two grants comparable, and each is a fact rather than a judgement. This vocabulary is the part of this page most likely to be wrong at first — it is offered to be argued with. | Property | Values | What it answers | |---|---|---| | **scope** | file · folder · vault · account · all-vaults | How much does the grant reach? | | **operations** | read · write · delete · administer | What can be done with it? | | **bearer** | person · program-on-their-machine · vendor-server · any-holder | Who actually holds it? "any-holder" means the grant is a string: whoever has it, has it | | **mediation** | server-enforced · key-enforced | Who says no? A server can refuse and can log. A key cannot refuse — possession *is* access | | **duration** | session · until-withdrawn · forever | When does it lapse on its own? | | **withdrawal** | effective · future-only · none | Can you take it back — and does taking it back reach what they already have? | | **observability** | per-reader-log · aggregate · none | Can you see who read what? | Written compactly, a published read key is: `scope:vault · ops:read · bearer:any-holder · mediation:key · duration:forever · withdrawal:future-only · observability:none`. Three of those seven are **worse** than a mainstream sharing link, and saying so is the point of having a vocabulary. **One shape the vocabulary above could not express, until a vault demonstrated it.** An app can be granted the *use* of a credential without being given the credential: the [Risk Mandate vault](../demos/vaults/risk-mandate/index.md) seals its OpenRouter key under the vault key, and the host makes the call on the app's behalf. So `ops` and `bearer` come apart — `ops:llm-chat` is granted while `bearer` of the key is not, and a read-key holder auditing the vault (as we did) finds ciphertext where the secret would be. Most sharing models cannot say this, because handing over the capability and handing over the credential are the same act. ## The entries Three to start with, chosen to be different: one small and verifiable in seconds, one we lose, one that is the actual differentiator. More arrive as they are tested — not as they are thought of. ### 1 · Print a markdown file that somebody sent you Small, universally understood, checkable in under a minute — the kind of entry that earns the credibility the larger claims spend. | | A markdown file in a vault | A markdown file on your disk | |---|---|---| | **Steps** | **2** — open the file in the vault UI (it renders), press **Print** | **3–5**, depending on what you already have: many editors render markdown but print the *source*; the common workarounds are convert-to-HTML, paste into a browser, or install something | | **Prerequisites** | A browser | An editor that both renders *and* prints, or a converter, or an online tool | | **Privileges granted** | None beyond the key you already hold | None — *unless* you use an online converter, which is `scope:file · ops:read · bearer:vendor-server · withdrawal:none`. Uploading a document to a stranger to reformat it is a privilege grant that does not feel like one | | **Where it runs** | Your browser; the print component renders locally | Your machine, or a stranger's | | **Verified** | **hand-checked, 2026-08-16** — the vault UI exposes a **Print** control on an open markdown file, backed by `SgPrint.printMarkdown`; confirmed present and reachable in a browser driven with a published read key | | **Re-run it** | Open `https://dev.vault.sgraph.ai/#sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15:3d04e6b9ca98`, go to the vault browser, click `README.md`, look for **Print**. For the other column, take any `.md` file and try to produce a formatted page with whatever you already have installed — count what it takes | **What would change this entry:** an editor that renders and prints markdown in one action, which several are close to. If you know one, that column's step count should drop and this entry should say so. ### 2 · Take access back after you have shared something we lose this one A comparison where our column always wins is discounted on sight, so here is one where the mainstream answer is straightforwardly better. | | A vault, shared by read key | A hosted document, shared by link | |---|---|---| | **Steps to withdraw** | **Rotate the key and re-publish.** Future commits are protected | **1–2** — remove the share; the next request is refused | | **Does it reach what they already have?** | **No.** Anything already fetched stays readable forever, with no way to reach it | **Largely yes** — unless they exported or screenshotted, the server stops serving it | | **privileges** | `withdrawal:future-only · mediation:key · observability:none` | `withdrawal:effective · mediation:server-enforced · observability:per-reader-log` | | **Why** | Possession of a key *is* access, so there is no server in the loop to refuse a later request. The objects are content-addressed and immutable — the same id returns the same bytes forever, which is exactly what makes an already-taken copy permanent | | **Verified** | **machine-verified** — the immutability that causes this is checked automatically (`objects-immutable` below). The hosted-side behaviour is **hand-checked, 2026-08-16**, and is the ordinary documented behaviour of mainstream sharing | | **Re-run it** | `python3 admin/build/compare_tests.py` — the immutability check fetches one object twice and compares bytes | **The honest summary:** if the ability to revoke access after the fact matters more to you than the host being unable to read your content, a server-mediated platform is the better tool and you should use one. Vaults trade revocation for the host knowing nothing. That is a real trade, not a free win. ### 3 · Let a program record data for you without letting it change your records The differentiator. Note that the step counts are similar — it is the privileges column that separates these, which is why it is the column to lead with. | | A vault app | An assistant with folder access | |---|---|---| | **Steps** | Declare the grant in `app.json` and open the vault | Grant access to the folder, then run it | | **Privileges granted** | `scope:folder(adherence/) · ops:write,mkdir · mediation:key+host` — read broadly, but write to **one folder**. The app cannot alter the records it reports on | Typically `scope:folder · ops:read,write · bearer:vendor-server` for the whole shared folder — the granularity available is the folder you shared | | **Where it runs** | Your browser, in a sandboxed frame with an opaque origin | Usually the vendor's infrastructure, with your files sent to it | | **Survives the vendor** | The data is files with a documented layout; the reader is replaceable (we wrote a ~170-line one to prove it) | The conversation and any generated artefacts live where the vendor put them | | **Verified** | **machine-verified** — `scoped-write-declared` below reads the live vault's `app.json` and asserts the write scope is exactly `["adherence/"]`. The comparison column is **hand-checked, 2026-08-16** and describes the general shape of folder-level sharing, which varies by product — corrections welcome, per-product rows to follow | | **Re-run it** | Open the [Supplement Stack vault](../demos/vaults/supplement-stack/index.md) and read its `app.json`, or run `python3 admin/build/compare_tests.py` | **The caveat that keeps this honest:** read granularity is coarser than write granularity here. A read key opens the *whole vault*, not one file. Finer read boundaries mean separate vaults with separate keys, decided in advance — granularity costs structure. If you need per-file read control without pre-planning the shape, this is not yet the tool. ## The checks behind the machine-verified rows These run against the live service using only published read keys, and each states what would make it fail — a test that cannot fail is not evidence. Loading results… ## What is deliberately not here | Not here | Why | |---|---| | Anything we plan to ship | A comparison page is exactly where planned capability must not sit beside shipped capability. One unshipped row and a reader re-reads every other row as marketing | | Ease-of-use scores | A judgement published by a participant is the thing this page cannot defend. Steps, prerequisites and privileges are facts | | A deployment-features comparison | It would be the most linked and the fastest to rot, and our own story has a caveat worth resolving first: a vault's files are portable, but the polished viewer is currently one hosted implementation | | A maturity model | Those score an organisation's practice over time. This scores a task against a tool stack on a date — a different instrument | ============================================================================== # Published vaults — sgit.ai > Every vault whose read key sgit.ai has deliberately published: what each does, the features it uses, and the vault running live in the page. A read key is the complete credential — no account, no write capability. > > Page: https://sgit.ai/demos/vaults/index.html [Home](../../index.md) / Vaults # Published vaults Every vault whose read key this site has deliberately published — with, for each one, a page describing what it does, the features it uses, what the shape is good for, and the vault itself running live inside the page. The keys below are the complete credential: no account, no token, and no write capability anywhere in them. **Publishing one of your own?** [**The method is written down**](publishing.md) — the seven steps behind every row below, the tools that do each one, and the mistakes that produced each rule. Written to be followed by another site's agent. **Intake, since it nearly went wrong.** A credential submitted for publication here was once a **vault key** described as a read key — a legacy `passphrase:vault_id` form with no prefix to give it away. It was caught, only the derived read key was published, and nothing leaked; but the catch depended on somebody looking. Every submission now runs through `admin/build/check_credential.py` first, which refuses a write credential by **prefix** (`sgit_vk1_`, which new vaults emit) or, for anything older, by **shape** — a read key is 64 hex characters, and anything else before the colon is a passphrase. Prefixes are the better answer; the shape check covers the years of keys created before them. **The two rules, applied to every row.** Read keys yes, vault keys never — a read key is a capability we hand out on purpose, and it cannot become write access. And every vault is audited before its key appears here, because content travels with the key forever; findings are published on the vault’s page, not filed away. | Vault | Id | Shape | Contents | Published read key | | |---|---|---|---|---|---| | [Field Notes](field-notes/index.md) | `4bshby5n` | application (vault app) | 4 files · 11 KB · 2 commits · app entry `index.html` | `sgit_rk1_2848993a68c02a33ea5582902c391901191e53680d35b36c0e76185d4107ad81:4bshby5n` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_2848993a68c02a33ea5582902c391901191e53680d35b36c0e76185d4107ad81%3A4bshby5n) | | [Strategy Maps](strategy-maps/index.md) | `ookq4mn4` | structured analysis (two apps, one vault) | 33 files · 830 KB · 3 commits · app entries `index.html` and `sgit-maps.html` | `sgit_rk1_451c4c1e28fbb24a7f350bb3f107b2c103d69ed363167029ef9c9000ff76c07b:ookq4mn4` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_451c4c1e28fbb24a7f350bb3f107b2c103d69ed363167029ef9c9000ff76c07b%3Aookq4mn4) | | [Deploy Docs](deploy-docs/index.md) | `fyofmkvr` | record-keeping (live markdown) | 17 files · 25 KB · 2 commits · markdown, no app | `sgit_rk1_8d01421290efc3fa03205eced0534335a06ae209d627555b3dde136b878e3de1:fyofmkvr` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_8d01421290efc3fa03205eced0534335a06ae209d627555b3dde136b878e3de1%3Afyofmkvr) | | [The Vault Catalogue](catalogue/index.md) | `kc67yhgw` | record-keeping (an index of vaults) | 9 files · 11 KB · 2 commits · markdown, no app | `sgit_rk1_fd71e4bde7232498e43a5da869b1501260d9d403031b20af87b5bc801bdf6280:kc67yhgw` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_fd71e4bde7232498e43a5da869b1501260d9d403031b20af87b5bc801bdf6280%3Akc67yhgw) | | [Algarve · May 2026](algarve-may-2026/index.md) | `3d04e6b9ca98` | gallery (photo story) | 71 files · 29 MB · 36 commits · app entry `index.html` | `sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15:3d04e6b9ca98` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15%3A3d04e6b9ca98) | | [Supplement Stack](supplement-stack/index.md) | `r7zes477` | record-keeping (patient-held health record) | 23 files · 2.3 MB · 5 commits · app entry `index.html` | `sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee:r7zes477` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee%3Ar7zes477) | | [Risk Mandate](risk-mandate/index.md) | `4zf6pf2z` | application (a software project in a vault) | 124 files · 1.9 MB · 98 commits · 8 app entries | `sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae:4zf6pf2z` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae%3A4zf6pf2z) | | [Agentic Browser Isolation](agentic-browser-isolation/index.md) | `0610gsp9` | structured analysis (a living risk graph) | 104 files · 2.4 MB · 4 commits · 17 app entries | `sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e:0610gsp9` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e%3A0610gsp9) | | [Risk Graph Explorer](risk-graph-explorer/index.md) | `3simlnqe` | application (public by design) | 33 files · 428 KB · 7 commits · 1 app entry | `sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638:3simlnqe` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638%3A3simlnqe) | | [Regulation Graph](regulation-graph/index.md) | `73heuprz` | reference data (regulation as an evidence graph) | 207 files · 14.9 MB · 2 commits · 11 app views | `sgit_rk1_c004daae386e8d17fa648884acc527018bd4ea1116ad673fb2f1b068011695c9:73heuprz` | [open live ↗](https://dev.vault.sgraph.ai/#sgit_rk1_c004daae386e8d17fa648884acc527018bd4ea1116ad673fb2f1b068011695c9%3A73heuprz) | The machine-first version of this list is [the catalogue](../../catalogue/index.md) — an index of vaults that is itself a vault, updated by an sgit push with no site deploy. New entries start there: a read key and one line, the rest derived. The walkthrough of how a vault gets published at all — creation, audit, deliberate key publication, embed — is on [the embed demo page](../vault-app-embed.md). ============================================================================== # Publishing a vault: the method — sgit.ai > The seven steps behind every vault published here, written for another agent to follow: classify the credential before it touches anything, derive rather than refuse, audit with the read key, derive the facts, capture evidence by driving the real product, write the page, and record what outlives it — plus the mistakes that produced each rule. > > Page: https://sgit.ai/demos/vaults/publishing.html [Home](../../index.md) / [Vaults](index.md) / Publishing a vault # Publishing a vault: the method Every vault in this section went through the same seven steps. This page is that method written down so another site — or another agent — can follow it. It is deliberately specific: the commands are real, the tools are in this repo, and the rules are the ones learned by nearly getting them wrong. **Who this is for.** An agent maintaining a site that publishes vaults. Read the [markdown twin](publishing.md) if you are one. The tooling referenced lives in `admin/build/` of the sgit.ai repository and is small enough to copy rather than depend on. ## The two rules everything else serves | Rule | Why it is absolute | |---|---| | **Read keys yes, vault keys never** | A read key is a capability handed out on purpose and cannot become write access. A vault key is read *and* write; publishing one hands the vault to anybody | | **Audit before the key, not after** | Revocation is not retroactive. Anyone who fetches the objects keeps them, so an audit that happens after publication has not happened | ## 1 · Classify the credential before it touches anything Do this first, before the credential is pasted into a page, a script or a commit. Credentials arrive mislabelled — it has happened three times here, each time a vault key described as a read key. ``` python3 admin/build/check_credential.py '' # exit 0 → read-only, safe to publish # exit 1 → write credential (or unrecognised) — stop ``` It classifies two ways, because the problem has two eras: by **prefix** for vaults new enough to emit one, and by **shape** for everything older — a read key is 64 hex characters, and anything else before the colon is a passphrase, which means write. ## 2 · If it is a vault key, derive rather than refuse A vault key does not block publication; it changes what you publish. Store it where the repository cannot commit it, then derive: ``` # the gitignored tier — the release tripwire then scans every tracked file for it printf '%s' "$VAULT_KEY" > .sg_vault/local/demo-keys/-vault-key python3 - <<'PY' from sgit_ai.crypto.Vault__Crypto import Vault__Crypto c = Vault__Crypto() pw, vault_id = c.parse_vault_key(open('.sg_vault/local/demo-keys/-vault-key').read().strip()) print(c.derive_keys(pw, vault_id)['read_key']) # publish only this PY ``` The derivation is one-way: a published read key cannot be turned back into the vault key. Never print the write key; never let the vault key reach a tracked file. ## 3 · Audit with the read key, across every file Open the vault with the *read* key — the credential your readers will have — and scan every text file. Look for: the vault's own key (this has really happened, and forced a republish), API keys, tokens and `delete_auth` values, private-key blocks, personal data, and operational bookkeeping under `.vault/`. **Ruling hits out is the work.** Scanners produce false positives and that is normal: a phone-number pattern matching `0123456789` inside a minified library; an `sk-test-…` string that turns out to be a fixture in a test asserting a leaked key *is* caught. Read every hit. Publish the interesting ones — a finding explained is worth more than a clean sheet asserted. ## 4 · Derive the facts rather than describing them ``` python3 admin/build/catalogue_derive.py ``` File count, size, commit depth, HEAD, top-level layout, file types, app entry points and browser-renderability — all from the read key, no token and no clone. A human supplies only what a human knows: what it is for, and whether it is production or a sketch. ## 5 · Capture evidence by driving the real product Screenshots should be of the actual vault, produced by a script that opens it with the published read key and performs the navigation being described. Mock-ups age into lies; a capture script re-runs. ``` node admin/build/capture_shots.mjs --vault ``` Each shot declares a surface (the app, or the vault browser), the steps, and the crop. Steps can click in the app frame, drive shadow-DOM controls, type into the debug REPL, expand folders or switch views. Store the images beside the page — `demos/vaults//images/` — so a vault's folder is self-contained. ## 6 · Write the page: describe, then show, then admit | Section | What goes in it | |---|---| | Lead + why this one | What the vault is, and the one thing it demonstrates that others do not | | The credential, in the open | The read key, a CLI command, and a link that opens it in the official UI. Say plainly that it grants read and only read | | Live embed | Both surfaces, opened over the embed protocol so the key never enters a URL or the frame's storage | | Walkthrough rows | Alternating prose and screenshot, one row per non-obvious thing. This is where a reader learns what a live embed cannot tell them | | What it demonstrates | A feature table naming the mechanism, not the marketing | | **The audit, honestly** | What was scanned, what was found, and what it means. Findings included | | Derived facts | Step 4's output, with the tool named so it can be re-run | ## 7 · Record the things that outlive the page Per entry: the **shape** (the workflow it resembles, not its domain), the **evidence status** (production, demonstration, or sketch), whether it is a copy or a live reference, and the **write-key status** — escrowed or lost. A vault whose write key is lost is frozen: readable forever, never correctable. Say so where a reader will see it. ## What we got wrong, so you do not have to | Mistake | The rule that came out of it | |---|---| | A vault published its own write credential inside its content | **Republish, don't retrofit.** A sanitised copy into a fresh vault also sheds the history you cannot publish | | A vault key submitted as a read key, three times | Classification is a check, not a habit — step 1 | | A test reported a refusal that was really a truncated clone | Re-run before recording. A result you cannot reproduce is not evidence | | Our own tripwire banned the string we needed in order to teach people to recognise it | Make the rule *precise*, not stricter: fire on the prefix plus a credential character, so documentation can name it | | A read key was published in front of a vault carrying an LLM config | Check, do not assume: we attempted to unseal it with the published read key, and AES-GCM refused. State the result either way | The best statement of the vault-side rules is not ours: the [Risk Graph Explorer](risk-graph-explorer/index.md) carries a `PUBLIC.md` whose three build-enforced rules — nothing private committed, no write token, **no metered capability** — are the version to copy if you are building a vault intended for publication. ## The tools, in one list | Tool | Does | |---|---| | `admin/build/check_credential.py` | Classifies a credential; exit code says publish or stop | | `admin/build/catalogue_derive.py` | Read key → the facts, read-only and no token | | `admin/build/capture_shots.mjs` | Drives the live vault and crops evidence screenshots | | `admin/build/validate.js` | The release gate, including the key-leak tripwire | | `admin/build/compare_tests.py` | Executes the claims that can be executed, with dates | ============================================================================== # Field Notes — a published vault > The minimum viable published vault: six studies with generative SVG art as a self-contained vault app, read over the sg.vfs bridge, opened by a single published read key. > > Page: https://sgit.ai/demos/vaults/field-notes/index.html [Home](../../../index.md) / [Vaults](../../../index.md) / Field Notes # Field Notes Six small studies — a note and a generative SVG drawing each — served as a self-contained vault app. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_2848993a68c02a33ea5582902c391901191e53680d35b36c0e76185d4107ad81:4bshby5n` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_2848993a68c02a33ea5582902c391901191e53680d35b36c0e76185d4107ad81%3A4bshby5n) · From the CLI: `sgit clone sgit_rk1_2848993a68c02a33ea5582902c391901191e53680d35b36c0e76185d4107ad81:4bshby5n` Published deliberately. It grants read, and only read — a write attempt is refused by the server’s write gate (the **R1 W0** badge you will see in the chrome). ## See it live, here ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | Vault app (`app.json`) | one self-contained `index.html`, auto-opened; CSS and JS inlined per the authoring contract | | `sg.vfs` bridge | the app reads `content.json` over the bridge at runtime — the status line in the app proves it | | Generative SVG | the six drawings are code, not images — no binary assets to fetch | | Published read key | the first vault created specifically to be published; the complete walkthrough is on [the embed demo page](../../vault-app-embed.md) | ## What this shape is for The minimum viable published vault: content plus a small app, one key, no server that can read any of it. Use this shape for anything you would put on a small static site — except the host serves only ciphertext, and unpublishing is deleting one credential from a page rather than tearing down a site. ## Derived facts 4 files · 11 KB · 2 commits · app entry `index.html` · derived from the read key alone by `admin/build/catalogue_derive.py` — the same derivation that populates [the catalogue](../../../catalogue/index.md), where this vault also has an entry. ============================================================================== # Strategy Maps — a published vault > The SG/Send strategy in seven Wardley maps plus the sgit positioning analysis — two app entry points in one encrypted vault, published after the audit that made a republish necessary. > > Page: https://sgit.ai/demos/vaults/strategy-maps/index.html [Home](../../../index.md) / [Vaults](../../../index.md) / Strategy Maps # Strategy Maps The SG/Send strategy in seven Wardley maps, plus the sgit positioning analysis as a second app in the same encrypted store. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_451c4c1e28fbb24a7f350bb3f107b2c103d69ed363167029ef9c9000ff76c07b:ookq4mn4` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_451c4c1e28fbb24a7f350bb3f107b2c103d69ed363167029ef9c9000ff76c07b%3Aookq4mn4) · From the CLI: `sgit clone sgit_rk1_451c4c1e28fbb24a7f350bb3f107b2c103d69ed363167029ef9c9000ff76c07b:ookq4mn4` Published deliberately. It grants read, and only read — a write attempt is refused by the server’s write gate (the **R1 W0** badge you will see in the chrome). ## See it live, here ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | Two app entry points | `index.html` (the strategy essay, eight Wardley map PNGs) and `sgit-maps.html` (six inline-SVG maps) — one encrypted store, two front doors | | Vault-path images | the essay’s PNGs travel as ciphertext and are swapped in as `blob:` URLs after decryption | | Republish pattern | this vault is a sanitised republish: the original could not publish its key because a write credential was inside its content — [the audit is public](../../strategy-maps.md) | | Cross-app links | the two apps link to each other and the links survive embedding | ## What this shape is for Published analysis with real assets: strategy documents, briefs, decks. The two-entry-point trick means one vault can carry a family of related documents that share content, history and a single published key. ## Derived facts 33 files · 830 KB · 3 commits · app entries `index.html` and `sgit-maps.html` · derived from the read key alone by `admin/build/catalogue_derive.py` — the same derivation that populates [the catalogue](../../../catalogue/index.md), where this vault also has an entry. ============================================================================== # Deploy Docs — a published vault > The living deployment documentation for sgit.ai: markdown written by two Claude Code sessions, rendered live in the visitor’s browser, updated by an sgit push with no site deploy. > > Page: https://sgit.ai/demos/vaults/deploy-docs/index.html [Home](../../../index.md) / [Vaults](../../../index.md) / Deploy Docs # Deploy Docs The living deployment documentation for sgit.ai itself — written by two Claude Code sessions, rendered live on the /deploy page. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_8d01421290efc3fa03205eced0534335a06ae209d627555b3dde136b878e3de1:fyofmkvr` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_8d01421290efc3fa03205eced0534335a06ae209d627555b3dde136b878e3de1%3Afyofmkvr) · From the CLI: `sgit clone sgit_rk1_8d01421290efc3fa03205eced0534335a06ae209d627555b3dde136b878e3de1:fyofmkvr` Published deliberately. It grants read, and only read — a write attempt is refused by the server’s write gate (the **R1 W0** badge you will see in the chrome). ## See it live, here ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | Live markdown rendering | [the /deploy page](../../../deploy/index.md) decrypts and renders this vault in the visitor’s browser — a push here updates that page with no site deploy | | Freshness window | the mutable HEAD pointer is checked at most once per 120 s; everything else is content-addressed and cached forever | | Two writers | written by two Claude Code sessions collaborating through the vault — the commit history shows the handoffs | | Debug panel | the page’s vault panel shows every encrypted object arriving and what it decrypts to | ## What this shape is for Documentation that updates without a deploy pipeline, from any writer who holds the vault key, to any reader who holds the read key. The natural shape for runbooks, guides and anything agents co-author. ## Derived facts 17 files · 25 KB · 2 commits · markdown, no app · derived from the read key alone by `admin/build/catalogue_derive.py` — the same derivation that populates [the catalogue](../../../catalogue/index.md), where this vault also has an entry. ============================================================================== # The Vault Catalogue — a published vault > The index of published vaults, itself a vault, listed in itself — a submission queue where an entry costs a read key and one line, with published to-do lists and first-class write-key status. > > Page: https://sgit.ai/demos/vaults/catalogue/index.html [Home](../../../index.md) / [Vaults](../../../index.md) / The Vault Catalogue # The Vault Catalogue The index of published vaults — itself a vault, published with a read key, and listed in itself. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_fd71e4bde7232498e43a5da869b1501260d9d403031b20af87b5bc801bdf6280:kc67yhgw` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_fd71e4bde7232498e43a5da869b1501260d9d403031b20af87b5bc801bdf6280%3Akc67yhgw) · From the CLI: `sgit clone sgit_rk1_fd71e4bde7232498e43a5da869b1501260d9d403031b20af87b5bc801bdf6280:kc67yhgw` Published deliberately. It grants read, and only read — a write attempt is refused by the server’s write gate (the **R1 W0** badge you will see in the chrome). ## See it live, here ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | Recursion, usefully | an index of published vaults that is itself a published vault, listed in itself — [rendered live at /catalogue/](../../../catalogue/index.md) | | Submission queue | an entry costs a read key and one line; everything else is derived by an agent opening the vault | | Published to-do lists | `todo/awaiting-read-key.md` and `todo/awaiting-processing.md` are public, because a named gap gets filled | | First-class write-key status | every entry records whether the write key is escrowed or lost, because a frozen vault can never be corrected | ## What this shape is for Machine-and-human-readable registries that update by pushing to a vault rather than deploying a site. The schema here is deliberately the first instance of what a vault hub would need. ## Derived facts 9 files · 11 KB · 2 commits · markdown, no app · derived from the read key alone by `admin/build/catalogue_derive.py` — the same derivation that populates [the catalogue](../../../catalogue/index.md), where this vault also has an entry. ============================================================================== # Supplement Stack — a published vault > A patient-held health record as a vault: a real supplement regimen, label photographs every extracted value is traceable to, deterministic totals against UK RNIs and EFSA upper limits, and an adherence log the app may write to and nothing else. Shared with a professional by handing over a read key. > > Page: https://sgit.ai/demos/vaults/supplement-stack/index.html [Home](../../../index.md) / [Vaults](../index.md) / Supplement Stack # Supplement Stack A patient-held health record as a vault: a real supplement regimen, a photograph of every label the numbers were read from, deterministic totals against UK reference values — and an app permitted to write to exactly one folder and nothing else. **The idea it is built on, in one line.** Every label describes one product; **nothing describes the sum**. The missing artefact is the total per nutrient across everything a person is taking — so the model extracts (fuzzy, and traceable to a label photo), the code adds up (deterministic, and reproducible), and the output is a briefing for somebody qualified. **Never a verdict.** This is a record-keeping tool, not medical advice, and no compliance finding of any kind exists for this pattern. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee:r7zes477` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee%3Ar7zes477) · From the CLI: `sgit clone sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee:r7zes477` Published deliberately. It grants read, and only read — a write attempt is refused by the server's write gate. ## See it live, here Both surfaces open automatically below. You can also [**open the app in its own window ↗**](https://dev.vault.sgraph.ai/#sgit_rk1_047186b559528058c66d1792b7345639b1238cb95c166d1d5f5b65c59813c2ee%3Ar7zes477). ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | **Scoped write permission** | `app.json` grants the app `read` over everything but `write` and `mkdir` over `adherence/`*only*. The app that records what you took each day cannot touch the regimen, the label photographs or the references — least authority, declared in the vault and enforced by the host | | Source-mapped extraction | every amount in `regimen.json` carries a `label_image` pointing at the photograph it was read from, so a misread is *visible* rather than propagated — the same discipline a diff gives code | | Deterministic analysis | `scripts/totals.py` sums per nutrient with its rules stated in the open: topicals contribute nothing, as-needed items sit outside daily totals, and a null amount is **flagged, never guessed**. The in-app JavaScript does the same arithmetic, so two implementations can be checked against each other | | Named, dated reference data | UK RNIs and EFSA upper limits, with sources and a transcription note — explicitly *not* US Daily Values, because comparing a UK intake to US references without saying so would be a quiet error | | Honest incompleteness | one product's 27-nutrient panel is not yet captured, so the app labels the totals **INCOMPLETE** rather than showing a confident wrong number | | The brief ships with the vault | `briefs/` carries the architecture brief the whole thing was built from — the reasoning travels with the artefact | ## What is going on here, step by step The embeds above are the real vault, which makes it easy to scroll past the parts that matter. Each row points at one of them. Every screenshot is of this vault, driven by a script holding nothing but the published read key. the daily record ### What was actually taken, not what was intended The **Today** tab is a checklist of the day's regimen, grouped by timing. Ticking an item and pressing **Save today** writes one small JSON file — `adherence/2026-08-16.json` — into the vault. That distinction is the point: a regimen file says what you *mean* to take; the adherence log says what you *did*. When the conversation with a professional finally happens, the second is the honest input. The Today tab: per-item, per-timing, with a Save that writes into the vault. traceable extraction ### Every number points back at the photograph it came from The **Stack** tab lists each product with its dose, timing, route — and the label photograph the amounts were read from. A model did that reading, which is a fuzzy step, so each value carries a `label_image` back to its source. This is the source-map discipline applied to health data: a misreading stays *visible* and checkable against the picture, instead of quietly becoming a number in a total. The Stack: products, doses and the label photograph behind each set of numbers. the missing artefact ### The sum nobody else computes This is the tab the whole vault exists for. Every label describes one product; **nothing describes the sum**. Here it is: total per nutrient per day, each against the UK RNI and the EFSA upper limit, with the contributing products named. Two details matter more than the numbers. The reference set is *named and dated* (UK RNI + EFSA UL — deliberately not US Daily Values, for a regimen bought in the UK). And the amber banner says the totals are **incomplete**, listing exactly which amounts have not been captured: *"Nothing is guessed: a value that is not on a captured label is flagged, never estimated."* Totals per nutrient with ×RNI and ×UL ratios — and an honest incompleteness banner. never a verdict ### The output is a briefing, not a diagnosis The **Briefing** tab assembles everything into something to hand to a pharmacist or GP: the stack, the totals, the overlaps, the open questions — *"Three products target the knee — is that a sensible combination or redundant?"*, *"Do any of these interact with my other medication?"* The tool deliberately stops there. It does the arithmetic nobody had done and hands the result to somebody qualified. It never answers the questions itself, and the vault says so on its own About tab. The Briefing: what to take to a professional, including the questions to ask. least authority ### The app may write to one folder — and nothing else Here is the vault's own `app.json`, read straight out of the store. The permission block grants `read` broadly but `write` and `mkdir` over `adherence/` *only*. So the app that ticks off today's doses cannot alter the regimen, the label photographs, or the reference values — not by policy, but because the capability was never granted. This is what permissions look like when they are a property of the vault rather than a setting on a server, and it is the healthcare-shaped version of the whole argument. app.json: read broadly, write only adherence/ — least authority, declared in the vault. ## Why this shape matters beyond supplements This is the clearest **patient-held record** on the site. The data lives in a vault the person controls; sharing it with a professional is handing over a read key, not granting an account on someone's platform, and not emailing a PDF that is copied forever the moment it arrives. The write key never leaves the owner, so a reader can read *everything* and change *nothing*. The division of labour is the transferable part: **a model does the fuzzy work** (reading amounts off a photograph), **code does the exact work** (adding them up), and every fuzzy step is traceable to its source so a human can check it. Any domain where an LLM reads documents and arithmetic must be right — expenses, lab results, invoices, dosing — can borrow that shape. See the [healthcare use case](../../../use-cases/health-regulated.md) for where this fits. ## The audit, honestly Every vault is audited before its read key appears here. This one is **clean on credentials**: no tokens, no keys, no `.vault/` operational bookkeeping — and the scan for personal identifiers found none either (no name, address, contact details, date of birth or health-service number; the record describes its owner only as "UK-based adult male"). What it *does* publish is a real person's actual supplement regimen, and the health context that can be inferred from it — a knee, sport, sleep. That is the owner's own data, published on purpose, and it is worth stating the rule that goes with it: **revocation is not retroactive**. Anybody who fetches these objects keeps them. Rotating the key protects future commits and returns nothing already read. The regimen is published because a real record demonstrates the pattern in a way a fabricated one cannot — and because the alternative, a sanitised sample, is exactly the thing this vault argues against. ## Derived facts 23 files · 2.3 MB · 5 commits · app entry `index.html` · twelve label photographs — derived from the read key alone by `admin/build/catalogue_derive.py`, the same derivation that populates [the catalogue](../../../catalogue/index.md). ============================================================================== # Risk Mandate — a published vault > A working application built and delivered as a vault: 124 files, 98 commits, eight entry points, pinned releases, offline capable — and it calls an LLM without ever holding the API key, which is sealed under the vault key. > > Page: https://sgit.ai/demos/vaults/risk-mandate/index.html [Home](../../../index.md) / [Vaults](../index.md) / Risk Mandate # Risk Mandate A field demo built to be handed to a stranger on an iPad — and, underneath it, the most complete software project published here: 124 files, 98 commits, eight entry points, a test suite, build tooling and pinned releases, all inside one encrypted vault. **Why this one matters.** It answers the question the other demos leave open: *can you actually build something real in a vault?* This is a working application with a release history, developed in the vault, delivered by the vault, and running offline once cached. It also does the thing that is hardest to do safely — **it uses an LLM without ever holding the API key**. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae:4zf6pf2z` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae%3A4zf6pf2z) · From the CLI: `sgit clone sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae:4zf6pf2z` Published deliberately, and **derived** — this read key is a one-way derivation of the vault key, which stays with its owner. It grants read, and only read. ## See it live, here Both surfaces open automatically below. You can also [**open the app in its own window ↗**](https://dev.vault.sgraph.ai/#sgit_rk1_a702fba803faac4369eb5d5a320b4dfa017af62bd2425fb298aac4b99e95c0ae%3A4zf6pf2z) — it is more fun full size. ## What is going on here, step by step Three things this vault does that the others do not. Every screenshot is of this vault, driven by a script holding nothing but the published read key. the app ### A real application, delivered as a vault This is **Risk Mandate**, a field demo built to be handed to someone on an iPad: pick a scenario, answer eight questions, and a risk register assembles beside you — readable as an operator, a CISO or a board. It is one `index.html` with everything inlined, and it opens straight from the vault. Note the chrome: a **release selector** ("Live (latest)"), a sealed-secret badge, and **Read-only** — you are looking at a published build, not a preview. The line under the button is the part worth reading twice: *"Nothing leaves this device."* On the stand it runs with the network off — one cached load, then flight mode all day. The app as it opens from the published read key: scenarios, presets, and a version chip. the privilege claim ### It uses an LLM. It never holds the API key. The whole argument of this vault is in its `app.json`. It grants the app `llm: chat, models, usage, listen` — and `fs.write` over `field/workspace/` and nothing else. What is *not* granted is the credential. `.vault/llm/config.json` carries `keySealed: {iv, ct}` — the OpenRouter key encrypted under the vault key. The host decrypts it and makes the outbound call; the frame is handed a result, never a secret. Opening this vault with the published read key, that field is ciphertext we cannot decrypt — which is the point, and we checked. In the [privilege vocabulary](../../../compare/index.md): the app gets `ops:llm-chat` without ever getting `bearer` of the key. That distinction is usually impossible to express, let alone enforce. app.json: LLM use granted, the key withheld, and write scoped to one folder. version control, seriously ### Ninety-eight commits, and releases pinned to them This is not a document that happens to live in a vault — it is a software project developed in one. **98 commits**, a test suite, build tooling, and `.vault/releases.json` pinning named releases (`v0.15.5`, `v0.10.3`, `v0.7.7`…) to specific commit ids, which is what the release selector in the app chrome is reading. Its build script is the detail we enjoyed most: `tools/build.mjs` fails the build on any declarative external reference *and* on any credential-shaped string. They arrived at the same tripwire this site runs on its own releases, independently, for the same reason. The SGit view: 98 commits of a real project, read with a published read key. ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | **AI without the credential** | Sealed OpenRouter key in `.vault/llm/config.json`; the host decrypts and calls, the app frame receives results only. Read-key holders — including us — see ciphertext in that field | | **Scoped permissions, two kinds** | `llm` capabilities enumerated (chat, models, usage, listen) and `fs.write` limited to `field/workspace/` | | Eight entry points | `index.html`, plus a board, a takeaway page, talking points, a build-history page and three proofs-of-concept — one vault, many front doors | | Pinned releases | `.vault/releases.json` maps names to commit ids; the app chrome offers them as a live selector | | Offline by design | One cached load, then it runs with the network off — the demo survives conference wifi | | A build that enforces the contract | `tools/build.mjs` exits non-zero on declarative external references *and* on credential-shaped strings — their own version of this site's release tripwire | | Shareable results without a server | `takeaway.html` rebuilds a saved register from the link alone | ## The audit, honestly Audited independently before this key was published, across all 124 files. **Clean:** no credentials, no personal data, and the vault's own key does not appear in its content — the failure that forced a republish in [an earlier case](../strategy-maps/index.md). Two findings worth publishing because they are the *good* kind. The OpenRouter credential is present but **sealed**: encrypted under the vault key, so a read-key holder gets ciphertext. And the one match our secret scanner produced was `sk-test-abcdefghijklmnop` in `tests/suites/40-llm.mjs` — a deliberately fake key in a test that asserts a reachable API key *is caught*. A scanner hit that turns out to be a security test is a good sign about a codebase. As always: revocation is not retroactive. Anyone who fetches these objects keeps them. ## Derived facts 124 files · 1.9 MB · 98 commits · eight app entries · last updated 2026-08-06 — derived from the read key alone by `admin/build/catalogue_derive.py`, the same derivation that populates [the catalogue](../../../catalogue/index.md). ============================================================================== # Agentic Browser Isolation — a published vault > A living risk graph for whether an AI agent browses with your logged-in sessions or an isolated identity: seventeen entry points, a page per stakeholder altitude, acceptance-gated escalation, cited evidence, and an app that requests no write capability at all. > > Page: https://sgit.ai/demos/vaults/agentic-browser-isolation/index.html [Home](../../../index.md) / [Vaults](../index.md) / Agentic Browser Isolation # Agentic Browser Isolation A living risk graph for one narrow, consequential question: when an AI agent browses and acts on the web, does it run **inside your browser with your logged-in sessions**, or inside an isolated browser with a scoped identity of its own? **Why this one is here.** It is the site's own argument, made by somebody else and in far more detail: this is the ambient-authority problem the [serialised change proposal](../../../use-cases/serialised-pull-request.md) and the [agent use case](../../../use-cases/ai-agents.md) circle around — an agent borrowing a human's whole session because that is the only credential on offer. Here it is a register with owners, evidence and an escalation mechanism, and it is vendor-neutral: any isolation product is an *instance of* the control, and its own self-created risks go on the register like everything else. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e:0610gsp9` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e%3A0610gsp9) · From the CLI: `sgit clone sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e:0610gsp9` Published deliberately, and **derived**: the owner supplied a vault key, our intake check refused it for publication, and only this one-way derivation appears here. ## See it live, here Both surfaces open automatically below. You can also [**open the app in its own window ↗**](https://dev.vault.sgraph.ai/#sgit_rk1_92cad4cea8f58c55f59b686c71c935225a1ba7c41ecb6922a8aa570467604f6e%3A0610gsp9) — with ten pages to walk, it is worth the room. ## What is going on here, step by step Four things worth stopping on. Every screenshot is of this vault, driven by a script holding nothing but the published read key. ten front doors ### One vault, seventeen entry points The app opens on **Facts** and carries a numbered spine across the top: your reality, the two designs, the chain, how it unfolds, stakeholders, an explorer, two graph views and the raw data. Seventeen HTML entry points in one vault, each a real page. The evidence is cited outward, too — the facts link to Brave's prompt-injection write-up, an arXiv paper on credential exposure, independent testing. A risk register that names its sources is one you can argue with. The app on open: a ten-step spine, and the decision stated at the top. the mechanism ### The same exposure, in seven languages This is the idea worth stealing. Every altitude has **one named owner** — L1 IT, L2 CISO, L3 DPO/CFO/COO, L4 CEO, L5 Board — and each owns the risk *in their own language*. A risk is never assigned automatically. It sits **pending** until that owner accepts it personally, and *only an accepted risk escalates to the altitude above*. Look at the counts in the picture: IT has 5 risks pending; everyone above is `waiting`, with nothing yet arrived — because nothing has been passed up. There is **no deny button**: accept, mitigate, or ask for more data. Seven stakeholder altitudes, each with its own pending/accepted counts. a graph, not a document ### The register is data, and you can see it as one Seventy JSON files hold the register — risks, controls, evidence, owners, acceptances — and the app offers them as an explorer, a rendered graph, and a queryable graph database, with RDF tooling vendored into the vault so none of it needs the network. That is the shape argument for vaults holding structured analysis rather than prose: the same encrypted objects serve a narrative page, a stakeholder view and a graph query, because the underlying thing is data. The graph view, rendered in the browser from the vault\u2019s own JSON. read-only by declaration ### An app that asks for nothing Its `app.json` declares `fs.read: true` and `fs.write: []` — an **empty** write list. Compare the [Supplement Stack](../supplement-stack/index.md), which writes to one folder, and [Risk Mandate](../risk-mandate/index.md), which uses an LLM without holding its key. Three vaults, three points on the same scale, each declared in the vault rather than configured on a server. The footer states the consequence plainly: *your changes are device-local; the vault baseline is never modified*. app.json: read true, write [] — the app requests no write capability at all. ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | **Seventeen entry points** | The most in the catalogue: a narrative spine, a page per stakeholder altitude, an explorer, two graph views and the raw data — one encrypted store, many front doors | | **Zero write capability** | `fs.write: []`. The app reads and renders; edits stay device-local and the vault baseline is untouched | | Structured analysis, not prose | ~70 JSON files hold risks, controls, evidence and acceptances; the pages are views over that data | | Graph tooling inside the vault | RDF libraries vendored in, so the explorer and graph database work with no network and no CDN — the authoring contract making offline the default | | Cited evidence | Facts link out to primary sources; the register can be checked rather than believed | | A mechanism, not a spreadsheet | Acceptance-gated escalation with named owners and no deny button — the part most worth copying | ## The audit, honestly Audited across all 104 files before the key was published. **Clean:** no credentials, no personal data, no operational bookkeeping, and the vault's own key does not appear in its content. The scan produced six hits and all six were false positives — digit runs like `0123456789` inside a minified RDF library, matching a phone-number pattern. Worth recording because it is what a real audit looks like: the interesting output of a secret scanner is usually the part you have to rule out by reading it. As always: revocation is not retroactive. Anyone who fetches these objects keeps them. ## Derived facts 104 files · 2.4 MB · 4 commits · seventeen app entries · last updated 2026-07-18 — derived from the read key alone by `admin/build/catalogue_derive.py`, the same derivation that populates [the catalogue](../../../catalogue/index.md). ============================================================================== # Risk Graph Explorer — a published vault > A fact-to-risk graph explorer extracted into its own vault and designed to be public: its PUBLIC.md states three rules its build enforces, including no metered capability behind a published read key, and its app.json requests no permissions at all. > > Page: https://sgit.ai/demos/vaults/risk-graph-explorer/index.html [Home](../../../index.md) / [Vaults](../index.md) / Risk Graph Explorer # Risk Graph Explorer The graph explorer from [the risk-mandate work](../agentic-browser-isolation/index.md), refactored out into a vault of its own — and the first vault published here that was **designed to be public from the start**, with its own publication rules enforced by its own build. **Answer the questions; the register assembles.** Seven views recompute as you go, including acceptance (who holds what) and what happens next (how decisions become incidents and projects). Nothing you answer leaves the page: no network call, no storage, no account. It is destined for riskmandate.ai, and the vault is how it will be served. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638:3simlnqe` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638%3A3simlnqe) · From the CLI: `sgit clone sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638:3simlnqe` Published deliberately, and **derived**: the owner supplied a vault key, our intake check refused it for publication, and only this one-way derivation appears here. ## See it live, here Both surfaces open automatically below. You can also [**open the app in its own window ↗**](https://dev.vault.sgraph.ai/#sgit_rk1_1c1b95f5903e35850a9bc0541ffa09c6b5d4017cbf18817d2ad6f894127e5638%3A3simlnqe) — try the presets, then change one answer and watch the register move. **Going deeper.** This vault has more in it than one page holds. [**The seven views, explained**](views/index.md) walks each view with a screenshot of the live vault and the mechanism behind it. [**The author’s walkthroughs**](videos/index.md) carries three recorded demos with full transcripts — the reasoning that the screenshots cannot show. ## What is going on here, step by step the argument ### An empty register is a correct answer It opens at zero: **0 facts, 0 risks, 0 provisions**, and a prompt to answer the first question. Nothing is assumed about your estate until you say something about it. That is the claim the whole app is built to make, and its README states it plainly: *"the technical answers can be as bad as you like — if nothing is at stake behind them, the register is short, and that is the correct answer."* A tool that produces the same output for a scratch service and a payments platform is a checklist, not a risk register. The explorer at zero: no answers, so no register. context decides ### Answer differently and the graph changes shape Load the **Exposed** preset and the same questions produce 18 facts, 37 risks and 14 provisions, with a header that reads *decides about a person · in production · at stake*. Seven views recompute together: the estate graph, context, a role risk map, risk chains, the register, acceptance, and what happens next. Look at the graph itself — amber edges are exposure facts, green are assurance, and **ghosted means nobody has said either way**. Recording that absence as information, rather than as an implicit pass, is the detail that makes this a graph rather than a form. The Exposed preset: 18 facts, 37 risks, and unanswered relationships drawn as ghosts. published on purpose ### A vault that carries its own publication rules Most vaults here were audited by us before their key went out. This one arrived with the audit already written into it: `PUBLIC.md` states that **every byte committed is already public**, and its build refuses if any of three rules is broken — nothing private committed (the gate scans *every file*, not just the built artefact), no write token, and **no metered capability**. That third rule is the one worth borrowing, and we had not written it down: *"a published read key in front of an LLM config is an open tab on somebody else's budget, and a spend cap is a rate limiter on the fun, not a control."* It sent us back to re-check a vault we had already published — see the note below. PUBLIC.md: three rules, enforced by the vault’s own build. the floor ### permissions: {} An empty permissions object. Not a scoped write, not a withheld credential — **nothing requested at all**. The app answers questions in the page: no network call, no storage, no account, as its README says. The catalogue now spans the full range, each declared in the vault rather than configured on a server: [Risk Mandate](../risk-mandate/index.md) uses an LLM without holding its key, [Supplement Stack](../supplement-stack/index.md) writes to one folder, [Agentic Browser Isolation](../agentic-browser-isolation/index.md) declares `write: []`, and this one asks for nothing. app.json with an empty permissions object — the floor of the scale. ## Extraction as a pattern This vault began as a section of a larger one. Pulling it out gave it a smaller audience surface, a shorter history, its own release cadence and — decisively — **its own permission posture**: the parent could plausibly want a model; this one may never have one, and says so. That is worth naming as a technique. Vault boundaries are permission boundaries, so the question *"should this be its own vault?"* is usually the question *"should this have a different key, a different audience, or a different set of capabilities?"* Here the answer was all three, and the split made the public version safe to publish in a way the parent could not have been. ## The audit, honestly Clean: **zero** hits across every text file — no credentials, no personal data, no operational bookkeeping, and the vault's own key absent from its content. The tidiest audit of any vault published here, which is what you would expect of one built to be public. **It also caused us to re-audit ourselves.** Its third rule — no metered capability behind a published read key — applies to [Risk Mandate](../risk-mandate/index.md), which does carry an LLM config. So we checked rather than assumed: taking the sealed credential from that vault and attempting to open it with the read key we published, AES-GCM refuses (`InvalidTag`). The seal is under a key a read-key holder does not hold, so publishing that read key did not expose anybody's budget. Rule satisfied there by sealing; satisfied here, more conservatively, by absence. As always: revocation is not retroactive. Anyone who fetches these objects keeps them. ## Derived facts 33 files · 428 KB · 7 commits · one app entry · last updated 2026-08-10 — derived from the read key alone by `admin/build/catalogue_derive.py`, the same derivation that populates [the catalogue](../../../catalogue/index.md). ============================================================================== # The seven views, explained — Risk Graph Explorer > A deep walk through each view of the risk graph explorer — the estate, context, role risk map, risk chains, the register, acceptance and what happens next — with screenshots of the live vault and the mechanism behind each, grounded in the author’s own walkthroughs. > > Page: https://sgit.ai/demos/vaults/risk-graph-explorer/views/index.html [Home](../../../../index.md) / [Vaults](../../index.md) / [Risk Graph Explorer](../index.md) / The seven views # The seven views, explained One set of answers, seen from seven altitudes. This page walks each view of the [Risk Graph Explorer](../index.md) with a screenshot of the live vault and an explanation grounded in [the author’s own walkthroughs](../videos/index.md) — because the reasoning behind a view is rarely visible in a picture of it. **The spine, in one line.** An answer becomes a **fact**; facts combine into **risks**; risks are **assigned** to a role and **chain** upward to the corporate register; a role **accepts** what it holds; acceptance produces **what happens next**. Every view below is that same spine, cut at a different angle — which is why changing one answer moves all seven. Screenshots are of the live vault under the **Exposed** preset, captured with the published read key. Open it yourself from [the vault page](../index.md) and follow along. 1 · The estate ### Every answer becomes a fact, and the graph is the evidence This is where answering happens, and the first thing to notice is that **a "no" is still information**. From the walkthrough: *"if you don't have an agent, then we only have one piece of information here — but this is a fact."* The questions walk a deliberate path: what the agent is, what data is in its reach, whether its output decides about a person, what it can do with that data (*cannot see it · reads it · reads and changes it*), whether it can change production, how it is stopped, who may stop it, how long stopping takes, whether stopping was ever tested, what it can reach if it misbehaves, whether it has outbound access, whether the damage is reversible, whether there is a written procedure, whether the actions could be reconstructed, and whose account it acts under. Each answer lands as an `F-nn` fact chip, and the graph draws the relationships between them — amber for exposure, green for assurance, **ghosted for nobody has said either way**. That last one matters: an unanswered question is drawn as an absence rather than silently treated as a pass. The estate: answers on the left, the fact graph they build on the right. 2 · Context ### The same technical answers, weighed against what is at stake Context is the view that makes the app's core claim enforceable. The technical answers can be as alarming as you like; if nothing is behind them, little follows. The header carries the verdict in plain language — *decides about a person · in production · at stake* — and those three phrases are what turn a list of facts into a register worth reading. This is the difference between a risk tool and a checklist: a checklist scores the agent, this weighs the agent *against the estate it runs in*. Context: what is at stake, and where it runs, applied to the same answers. 3 · Role risk map ### The org chart, with risks flowing up it The view the author calls *"crazy powerful"*, and the header states its invariant outright: **every risk is assigned to somebody, and every risk reaches the board**. Read the counts under each role and you can see the two modes the walkthrough describes. The CISO shows `14 assigned · 14 through`; the CTO `4 assigned · 25 through`; the board simply `37 arrive here`. **Assigned** is what you personally hold. **Through** is what arrives because the risk graph says it must — *"he arrives because of the risk graph says so"*. The SRE holds a set; the platform owner inherits those and adds its own; the CTO inherits everything below and adds its own; the CEO connects the dots. The consequence is the one worth quoting: *"no risk then becomes orphaned, because every risk will flow upwards, and that's super important."* An owner cannot be surprised at the top by something nobody carried up. Role risk map: assigned vs through, with every path terminating at the board. 4 · Risk chains ### Risks that cause risks, and the ability to walk it backwards The second graph, and a different question: not *who holds this* but *what produced it*. Columns are levels — inherent at the left, operational rising by causal depth, and the **corporate register pinned to the right, because that is where the question stops**. Click any entry and it colours what produced it (**upstream**) and what it produces (**downstream**). The walkthrough uses it in both directions: *"if you go to 'led by' at the bottom, you arrive at the bottom of the risk; if you go 'leads to', you're navigating upwards."* So a corporate-level entry can be interrogated — *"why is it? It's because we have that one, and that one, and this one"* — until you reach the specific answers that caused it. One detail that only an honest tool ships: **a dashed edge is a cycle, and the cycles are real**. Rather than hiding a loop that the model does not like, it draws it. Risk chains: inherent to corporate, left to right, with upstream and downstream colouring. 5 · The register ### The familiar artefact — with its provenance attached This is the output most organisations already recognise: a risk register. What is different is that every row carries where it came from. Per the walkthrough: *"for every risk that you have here, you can see who's assigned, who causes it, and who leads to, and how does it connect."* A conventional register is a list of assertions someone typed. This one is a **projection of the graph** — which means it cannot contain a risk that nothing produced, and it cannot lose a risk that something did. The register: the conventional artefact, generated rather than authored. 6 · Acceptance ### Nobody can accept on anybody else’s behalf Acceptance is where the register stops being a document and becomes a decision. Each role holds what it holds and must accept it personally — and the author is explicit that this is where the value shows up: *"everybody that is going to accept it is going to push back."* That pushback is the feature. The walkthrough contains a live example of the author disagreeing with his own tool — *"I actually don't agree with these risks… I don't buy that"* — and the point is what happens next: because every risk is fact-derived, the disagreement resolves into *which fact is wrong* rather than whose opinion is louder. *"The cool thing is that we start to have the evidence to show exactly why we are saying this."* Acceptance: per role, per risk, with no delegation and no deny button. 7 · What happens next ### Decisions become incidents and projects The last view closes the loop. Acceptance is not the end of a risk; it is a commitment that produces consequences — the things that will happen if the exposure materialises, and the work that would change it. In the parent vault this is where a board refusal *funds a project* that flips the whole graph to the safer option. Here it is the same mechanism in miniature: the register does not merely describe a position, it names what follows from holding it. What happens next: the consequences and the work that would change them. ## The same estate, at three settings The presets are the fastest way to feel what the tool actually does. These are the **role risk map** for the same organisation under three different sets of answers — nothing about the org chart changed, only what is true about the agent. typical ### A typical deployment An agent is present and the estate is ordinary. Risks exist, they are held, and they reach the board — but the shape is contained. Typical: risks present, shape contained. governed ### The same estate, governed Approvals, a tested stop, a named authority, bounded reach. From the walkthrough: *"you have the govern, we can see it's a much cleaner sort of flow of events."* The risks do not vanish — they arrive with far less weight, and by shorter paths. **This is the argument the whole tool exists to make.** The register is not a verdict on whether you should run an agent; it is a picture of what you are carrying, which changes when the controls change. Governed: same organisation, cleaner flow. ## Why this workflow is powerful | What it does | Why it matters | |---|---| | **Answers are facts, and facts are cited** | Every risk traces to the specific answers that produced it. Disagreement becomes "which fact is wrong", not "whose judgement wins" | | **No risk is orphaned** | Every risk is assigned and every path terminates at the board. Nothing can sit in a register held by nobody | | **Assigned is distinguished from inherited** | A role sees what it personally holds and what merely passes through it — two very different conversations | | **Acceptance is personal and cannot be delegated** | The register becomes a set of decisions with names on them, and the pushback that follows is the point rather than a failure | | **Cycles are drawn, not hidden** | A model that shows its own loops is one you can argue with | | **Nothing is at stake ⇒ a short register** | The output scales with exposure, which is what separates a register from a checklist | | **It runs in a vault, in your browser** | No account, no upload, no network call. The answers you give about your estate never leave the page | The last row is what makes the rest publishable. A tool that asks these questions is asking for an unusually candid description of your weakest controls — and this one can be handed to somebody as [a read key](../index.md) that carries the whole application, with nothing to send anywhere. ============================================================================== # The author’s walkthroughs — Risk Graph Explorer > Three recorded walkthroughs of the risk graph explorer with full transcripts: the graph browser, risk chains, and the role risk map — the designer explaining why the tool is shaped as it is. > > Page: https://sgit.ai/demos/vaults/risk-graph-explorer/videos/index.html [Home](../../../../index.md) / [Vaults](../../index.md) / [Risk Graph Explorer](../index.md) / Walkthroughs # The author’s walkthroughs Three recorded walkthroughs of this vault — each one played, then read. Under every video is the same session as a document: the moments that matter, the frame the screen was showing at that moment, and what is actually happening in it. The full transcript is at the foot of each. **Why a video is not enough on its own.** A recording is invisible to a search engine, to [llms-full.txt](../../../../llms-full.txt), and to any agent reading this site as documentation. It is also full of *“this guy here”* and *“look at this”* — pointing that a transcript cannot resolve. So each moment below pairs the words with the picture they were pointing at, which is the only form in which the argument survives being read rather than watched. Timestamps link into the video at that point. The **Graph Browser** moments are frames of the recording itself; the **Risk Chains** and **Role risk map** moments are captured from the live vault with the published read key, driven to the state being described. ## 1 · Graph Browser · 4:21 · 5 Aug 2026 How answering the questions builds the fact graph — and why a “no” is still information. **Note on what you are looking at.** This walkthrough was recorded inside [Risk Mandate](../../risk-mandate/index.md), the field demo the explorer was later extracted from — so the chrome says *Risk Mandate — field demo* and the tab strip is shorter than today’s. The mechanism is the same one running in [this vault](../index.md). [00:00](https://youtu.be/PP6zsrC0KEg?t=0) ### Five ready-made estates, before a single question The video opens on the field demo’s front door — **“Eight questions about the agents you run”** — and the row of prepared examples underneath it: *a typical estate*, *a rough day*, *a well-run estate*, *a coding agent in CI*, *a support agent on accounts*. One tap loads a populated register. That row is a design position, not a convenience. A tool that only shows you your own answers cannot show you what a different answer would have produced — and the argument here is entirely about difference. “I want to just talk about this graph explorer that we pushed as an MVP, which is, I think, ridiculously powerful as a way to present.” 00:00 — the entry point, with five prepared estates to open instead of answering. [00:31](https://youtu.be/PP6zsrC0KEg?t=31) ### One answer, one edge — and the counters start moving The first question is answered: *“Yes, in production”*, which lands as `F-1`. Watch the header. It reads **1 fact · 4 risks · 5 provisions**, *where it runs: in production* — and **at stake: —**, because nothing has yet been said about data. In the graph, exactly one edge is drawn: `runs-in`, from **The agent** to **The production estate**. Every other twin is ghosted and carries its own tally — `0/3 said`, `0/2 said` — which is the tool stating, per node, how much of what it wants to know it does not have. 00:31 — 1 fact, one edge, and “at stake” still empty. [00:59](https://youtu.be/PP6zsrC0KEg?t=59) ### Edges are named, and the names carry the meaning Personal data is selected (`F-36`) and the header flips: **personal data at stake**. **The data in its reach** lights amber with *Personal data* written beneath it, and **Decisions its output…** gains the note *Its output informs a person w…*. This is the moment the deixis in the transcript resolves. He says the edges differ — and they do, by *name*: `runs-in`, `can-read`, `can-change`, `informed-by`. Not a generic line with a thickness, a labelled relation. That is what makes the picture evidence rather than decoration. “We actually have different, in a way, almost, different edges depending of what it is. And then, what it can do with the data, right? It cannot see it, or reads it, or reads and changes it.” 00:59 — the data node lights, and the edges arrive with names on them. [01:30](https://youtu.be/PP6zsrC0KEg?t=90) ### One answer can be two facts *“Reads and changes it”* is selected — and its chip reads `F-33 F-34`. Two fact identifiers for one click, because the answer asserts two separable things, and each has to be independently citable later when a risk points back at what produced it. The graph gains `can-read` and `can-modify` as distinct edges. Below, the questions have moved on to whether it can change production, whether it can be stopped, and how long stopping would take — the path from *capability* to *control*. 01:30 — one selection, two facts, two edges. [02:01](https://youtu.be/PP6zsrC0KEg?t=121) ### “This is here, depends on that one” — the sentence a transcript cannot carry Here is the clearest case for reading the video rather than only listening to it. He says two risks are connected and points; the words alone name neither end. The frame answers it. *“Yes, eventually”* is selected under **q3 — if you had to stop it right now, could you?** (`F-12`), and an edge labelled `stops-in-many-actions` runs from the agent down to **The stop control**, which now shows `4/12 said`. The dependency he is pointing at is a named edge with a counted endpoint. “This is an interesting one because this is connected to the stop control. So, you can actually see that this is here, depends on that one.” 02:01 — the referent of “this depends on that one”, named. [02:30](https://youtu.be/PP6zsrC0KEg?t=150) ### Saying “never” draws an edge too Two negative answers land: *never* actually stopped it (`F-19`), and *no*, the side effects of stopping are not known (`F-22`). A checklist would score these as gaps and move on. Instead the graph grows `never-exercised-on`, `never-timed-for` and `absent-for` — negative relations, drawn and labelled exactly like the positive ones. This is the mechanism behind the claim that a “no” is information: the answer produces a fact with a name, so a risk downstream can cite it. **11 facts · 20 risks**, and the shape is filling in. 02:30 — “never” and “no” arrive as named edges, not as silence. [03:00](https://youtu.be/PP6zsrC0KEg?t=180) ### The one green edge Reach is answered *customer-facing* (`F-24`) and egress *no egress* (`F-47`) — and `cannot-reach`, running from the agent to **Outbound network access**, is drawn in the assurance colour rather than the exposure colour. In a field of amber it is the single teal line. That is the whole two-colour scheme doing its job in one frame: amber is something true that costs you, teal is something true that helps you, and both are the same kind of object — a stated fact with an edge. A good answer is not the absence of a finding; it is a finding. 03:00 — “no egress” draws an edge too, in the other colour. [03:30](https://youtu.be/PP6zsrC0KEg?t=210) ### Seventeen facts, and the question of whose account it acts under By now the graph is dense with named relations — `cannot-reconstruct`, `held-by-a-group-for`, `irreversible-by`, `never-timed-for`, `absent-for` — and the header reads **17 facts · 30 risks · 11 provisions**. The agent node shows `15/43 said`: fifteen of the forty-three things the model would like to know have been said. The last question is the sharpest, and it is deliberately last: **whose account does it act under** — *a named person’s · a team’s · a service account nobody owns*. Everything before it describes what the agent can do. This one asks who will be standing there when it does it. “It’s a great way to almost in one day capture all the data.” 03:30 — 17 facts in, and the account question still to answer. [04:01](https://youtu.be/PP6zsrC0KEg?t=241) ### The other views, in one sweep — and a risk with an owner He closes by touring what the same answers become elsewhere, landing on **Risk chains** with **RISK-22** selected: *“Some changes the agent makes cannot be reversed by the operator”*, marked **OPERATIONAL · HOLDS NOW**, assigned to *SRE / platform on-call* and *Platform owner*, with a **blast radius** drawn from its own facts. That panel is the payoff of everything above it. The risk was not typed by anybody. It exists because certain answers were given, it is owned because the org chart says who holds that class of thing, and it can be argued with by going back to the facts underneath — which is what the next walkthrough is about. 04:01 — a generated risk, with an owner and a blast radius. **Full transcript — Graph Browser** Okay, so I want to just talk about this graph explorer that we pushed as an MVP, which is I think ridiculously powerful as a way to present. So what we have here now is how the questions we originally talked about in the demo. But it's in a weird way, we start with the first question, right? Do you have an agent and where does it run? Because if you don't have an agent, then we only have one piece of information here, which is — and but this is a fact, right? So this here captures the facts and information. So you could see that you have both the operation state or the test environment. And it's interesting because the risk will be very similar. The only question is whether it's live, so in a way that there's a risk level that is probably going to be there, right? So let's say you have one, right? And now you can see what kind of data is enriched. Let's say I got personal data. And what's cool about this is you can see that what's happening is this graph is now going to be populated with the data that we collected. So you can think of this graph as the evidence piece, right? So look, there's the output of facts and decision. Okay, it informs decisions. So you can see that what's cool about it is that we actually have different, in a way, almost different edges depending of what it is. And then, what can do with the data, right? It cannot see it, or reads it, or reads and changes. So this is a typical example of you have a production system, right, that touches personal data, accounts, contact details, it informs the decision, you know, of the there, and it reads and changes. So it's a typical agent, right? And now you got it. So now you talk about the information of this. You know, can the agent change things, right? Can you read and report? Can changes? Can change on its own? So you start to map, you know, for example, how it's done, right? With a person approval or change. So that so this is where you take that to the next level. So it changes on its own, right? So how do you stop it? Let's say you have an action to stop, or eventually can stop, or we don't know how to stop it. And how long should we stop it? Is it minutes? An hour? Don't know. So you start to see again, you know, the stop control now we map stop in many actions, never, time for, an hour, minutes, right? And then, have you actually stopped it? Yes, we have, only in test, never, right? Do you know the effects of stopping it? Have we mapped it? Is it partially? Etc. So this is an interesting one because this is connected to the stop control. So you can actually see that this is here depends on that one. So it's in a way now a next line up, like down, sorry, of the flow. Is there a named person? Do you have a named person or not? So this is the stop authority, right? The team, you know, if it really is, you know, misbehavior for full speed, could, you know, what could you reach, right? Internal only, customer facing? Don't know. So this would be customer only. So you could now start to see again, you know, what's the damage, that it can acts, you know, can you reach anything outside the network? This means that does it have internet access or not. So again, you can see here, outbound access, right? For example, no egress. Could, you know, could you undo the damage, right? So let's say you have fully reversible versus not, or some change are forever, which is important, right? Is there a written procedure for how you pull the plug? You tested it, you've written, you don't have it. Could you reconstruct what you did, for example, every day, right? Or, you know, do you have, you know, fully or partially or not, right? Cuz sometimes you have backups, but they do not allow you to restore specific things, and whose account it is, right? A service account, a named person, a team, right? So, you know, what is actually the, for example, the flow that happens. And then this is great, like because you can look at it. This is — I love this, right, because it's a great way to almost in one day capture all the data. Just for reference, we then capture the context. We have now these really cool road map with all the risks that flow forward. We also have these risk chains, which I go in more detail in others, but that means that every risk that is then connected connects to the top level, right? And then we even have a risk register, right? And for every risk that you have here, you can see who's assigned, who causes it, and who leads to, and how does it connect, right? So it's pretty cool. ## 2 · Risk Chains · 4:18 · 5 Aug 2026 Risks that cause risks — and why being able to disagree with the register is the feature. [“risk 6”](https://youtu.be/kWip3QnuN1I?t=45) ### Every risk carries the condition under which it would stop being true He names one entry — *“if you look at this guy here, for example, you have risk 6”* — so this is that entry, selected in the live vault. **RISK-6 — the production estate can be changed by an agent**, with the app’s own one-line gloss: *“They hold the estate. A change they did not make can still be one they must live with.”* The dashboard is where the design shows. **Established by**: `F-5`, the agent `can-change` the production estate — one fact, cited. **Ceases when any of these hold**: `F-4` reads-only-from, or `F-3` absent-from. That second list is unusual and worth stopping on: **the risk ships with its own falsification condition**. It is not a judgement to be argued down, it is a claim with stated exit criteria. Then **reduced by — but not retired**: *narrowing what it may change*, *staging changes behind a gate*. Mitigation is recorded as reduction, never as removal. And **touches**: EU AI Act Art. 12, Art. 26. The entry he names, opened: one fact establishes it, two would end it. [“corporate 2”](https://youtu.be/kWip3QnuN1I?t=110) ### Walking it backwards: “why is it? Because we have that one, and that one” The same view from the other end. **CORP-2 — customer harm**, assigned to the Chief Product Officer and the CEO, and the panel answers his question literally. **Established by**: *“Nothing directly. It holds because the entries below it do.”* **Leads to**: *“Nothing recorded”* — this is the top, which is where the question stops. Underneath, **led by** enumerates the causes, and each carries a reason in the tool’s own words: RISK-5 *“← a person on the other end is what customer harm means”*; RISK-26 *“← the record is somebody’s”*; RISK-27 *“← this is what customer harm looks like in practice”*. Note the colour: tracing upstream lights the path in the assurance tone rather than the exposure tone, so *what caused this* and *what this causes* are visually distinct operations on the same graph. And the corporate entry **touches no twin directly** — it is entirely a consequence, which is exactly why it cannot be edited into existence. The top of a chain, interrogated backwards — with a reason attached to each cause. [governed](https://youtu.be/kWip3QnuN1I?t=200) ### The same organisation with controls in place Switching the preset to **Governed** re-derives every chain from a different set of answers: approvals in the path, a tested stop, a named authority, bounded reach. Fewer entries, shorter routes to the register — *“a much cleaner sort of flow of events.”* The comparison is the argument. Nothing about the organisation changed between this frame and the last; only what is true about the agent did. A register that produced the same output either way would be measuring the questionnaire, not the estate. Governed: same organisation, same graph, fewer and shorter chains. **The most useful thirty seconds in all three videos** is the author disagreeing with his own tool. *“I actually don’t agree with these risks… I don’t buy that at the moment.”* He then works out what he does think is true — that the exposure is really about the agent touching EU AI Act obligations, and that stopping it would itself disrupt production — and says *“so we should capture that.”* The disagreement does not resolve into whose judgement wins. It resolves into **which fact is wrong or missing**, and then the register re-derives. That is the difference between a document you argue about and a model you correct. *“When you go and push your risk to be approved, the stakeholder is going to challenge you really hard. The cool thing is that we start to have the evidence to show exactly why we are saying this.”* **Full transcript — Risk Chains** ...to go through this UI which I think is starting to really show the idea of connecting the risks upstream. So what you have here to show you, this is part of the UI that we have that you know, you can basically see the multiple workflows that we have from a typical, non-exposed, one that's actually quite governed. What I really like is this, let's look at the exposed first, this sort of chain, and let's consolidate this here. So the idea here is that the risks connect from one element to the other. So if you look at this guy here, for example, you have risk 6. "The production can be changed by an agent." This is now connected to that risk. "Organization acts to the system that acts for a person", who then creates this risk, right? "Organization asks to, Tech to be changed." And then hits the top two risk register. So the logic here, this is the corporate risk register, so you can see that that particular risk will arrive there, and when I click here, I can also see the reverse. So I can see, if we say we have a risk of this, why is it? It's because we have that one, and we have that one, and we have this one, and that one. And I could also see it here, what actually happens. You can see, for example, this particular risk, corporate 2, who is assigned to, and then to the CEO, to what, you know, is reduced by this particular choices, touches GDPR, and then leads to this. So, so actually, so this is a good example, so you can see that this guy here, this risk leads to these two, and is led by that and that. So you can see that, you know, and again I can click on it and see the risk, right? So, so if you, if you go to "led by" at the bottom, you arrive at the bottom of the, the risk. If you go "leads to", you're basically navigating upwards the risk through. And the idea is that every risk should arrive at the corporate, at the top, right? So, so this now becomes a very powerful way to start to understand connections, and then we map the risks to the correct one, and I'll do a separate one to show how again, we connect all these risks to the particular CEO, CFO, you know, stakeholder, right? Now, the cool thing about this is you could see that the risks that you have go from zero, we don't have anything, to yes, you have an agent, bang, you got some risk. So as we start to add basically these answers, you see that we basically start to populate and start to add the risks and they start to interconnect, which is really cool, right? So, the idea is that the changes here impact the risks that exist and how the risk register almost looks like and the evidence that we have, right? So, and what's interesting about this, is if you look for example at "governed", actually this is there because of, I was actually, when I was explaining Claude about how to do this, I was saying just the fact they have an agent, you're going to have risks, but I actually don't agree with these risks because, see even that loss of control, I would argue that's not the risk that I have by having an agent, right? So the logic here is like if I have an agent in production and I have a lot of these values which are pretty good, I don't buy that at the moment I have this, right? Because we said in this one that we already have some of these. So, I think this is a good example of why when you go and push your risk to be approved, the stakeholder is going to challenge you really hard. The cool thing is that we start to have the evidence to show exactly why we are saying this. So, I think that in this particular case, it has more to do with the fact that the agent touches EU act, so suddenly we are in compliance with the EU AI act, or we might be compliant with it, and we now have an agent in the mix, and then the organization, and we have, and even though here we say we can stop within a minute, right? There is still some disruption to production, right? Which is interesting, right? So we should capture that operation, right? Because the system, like that one's a good one, you know, stopping the agent might have an interruption. So, again, we need to capture these nuances. The cool thing is this is all now fact-driven, which is super powerful. ## 3 · Role risk map · 3:15 · 5 Aug 2026 The org chart with risks flowing up it — and the ways a risk arrives at a person. [“no agent”](https://youtu.be/yqQgff4RWuE?t=160) ### The org chart exists before any risk does Under the **New** preset the structure is already there — board, CEO, CTO, CISO, CFO, DPO, chief product officer, platform owner, customer-facing service owner, SRE — and nothing is flowing through it. That ordering matters. The organisation is not derived from the risks; the risks are routed onto an organisation that was described first. Which is why the same estate can be re-answered all day and the chart underneath never moves. “If you have no agent, you have nothing.” Nothing answered: the structure, carrying nothing. [the CTO](https://youtu.be/yqQgff4RWuE?t=95) ### Held, versus arrived — and the tool separates them explicitly Selecting the CTO lights the path *Board → CEO → CTO → Platform owner / CISO* and splits what the role carries into named sections. **Holds — 4**: *“Assigned to this role. Its own to deal with.”* **Arrives by the risk chain — 16**, with the tool’s own explanation of why that category exists: “It arrives because the **risk graph** says so, not because anybody reports here — which is how a board entry ends up with an unexercised runbook underneath it.” That sentence is the whole feature. An owner is not surprised at the top by something nobody carried up, because arrival is computed rather than reported. On the chart itself each role is labelled in the same two terms — the CTO reads `4 assigned · 25 through`, and the board simply `37 arrive here`. The CTO: four of its own, sixteen that arrive because the graph says they must. [the SRE](https://youtu.be/yqQgff4RWuE?t=130) ### At the bottom, a third category — and it is empty The SRE / platform on-call is the leaf, *reports to Platform owner → CTO → CEO → Board*, and it **holds 9** — RISK-2, 6, 10, 11, 12, 13, 19, 22, 35 — the operational set the walkthrough describes as travelling upward from here. The panel here reveals something the video only implies: there are **three** ways a risk reaches a role, not two. **Arrives by the risk chain — 2**, and **arrives by the org chart — 0**, glossed *“Held by somebody who reports here”*, answered *“Nothing below.”* Inheritance through the reporting line and causation through the risk graph are counted separately, which is what lets you ask a manager *why* they hold something and get a structural answer rather than a list. “No risk then becomes orphaned, because every risk will flow upwards, and that’s super important.” The leaf of the chart: nine held, two caused, nothing inherited — because there is nothing below it. **Full transcript — Role risk map** Okay, so this next video shows another super powerful capability that we had here to our risk graph explorer, which is the org chart, and how we have, in this case, the board, we have the CEO, we have three direct reports, and we have then the kind of the team, where the platform owner, to the CTO, to the CEO, to the board, and you can actually see, you know, it's quite nice, the chain, right, the chief product officer, you know, has a customer service owner who connects to the board, who responds to the CEO and the board, right? And we can kind of see the sequence of events, right? So, what we're going to see here is how as we add risks to the organization, right? You start to have risks that are flowing to here, right? Which is pretty cool, so you could see that as we add, basically, and we provide answers, you basically start to see the, fundamentally, the risks changing. And what's cool about it is you could see how they arrive, and one of the things that's quite interesting is that we have two modes already, because you could see that the CEO, in this case, or the board, right, receive all these risks, so the CEO, in this case, is assigned his three corporate risk registers directly to him, but you also have these risks that arrive from the risk chain, and that's very important. Right? So you basically could see that because somebody, you know, a senior, holds, he arrives because of the risk graph says so, right? So that means that these particular risks that exist there, which for example, come from here, so you could see that this risk here, so let's say, the SRE is holding risk 2, risk 6, risk 9, risk 21, and risk 31, and that risk is also now going to exist — same risks are going to be connected to the platform owner, who now has a couple more risks of itself, and now the CTO has a couple risks of itself but also inherits all the risks that we mentioned below all the way up. So it's pretty cool, right? Because again, same thing, right? So the DPO is assigned a couple of risks, and then, you know, that he has, right? And then, you know, it also arrives from the risk chain, and then you got the CFO, the same thing, right? And then the CEO, you know, connects the dots. So this is a really powerful capability because it's how you connect all the dots, right? So if you look at the different scenarios, if you have no agent, you have nothing, if you have a typical kind of agent deployment, you have this kind of shape, if you have a lot of exposure, you get a much bigger set of responsibilities, and you have the govern, we can see it's a much cleaner sort of flow of events. And now we can start to challenge, you know, is those risks in the right place because everybody that is going to accept it is going to push back. But this is crazy powerful because now we start to see the relationships, and we see that no risk then becomes orphaned, because every risk will flow upwards, and that's super important. ## Where to go next Each view gets a systematic treatment, screenshot by screenshot, on [**the seven views page**](../views/index.md). The vault itself — its read key, both live surfaces, and the publication rules it enforces on its own build — is on [the vault page](../index.md). ============================================================================== # Algarve · May 2026 — a published vault > A travel diary as a vault: twenty photographs in three sizes, an eight-chapter narrative and an auto-opening gallery app — 29 MB of ciphertext opened by one published read key, with its pre-publication audit finding stated on the page. > > Page: https://sgit.ai/demos/vaults/algarve-may-2026/index.html [Home](../../../index.md) / [Vaults](../../../index.md) / Algarve · May 2026 # Algarve · May 2026 A travel diary as a vault: twenty photographs in three sizes, an eight-chapter narrative, and a gallery app that opens automatically. **Open it yourself — the key is the whole credential.** Read key: `sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15:3d04e6b9ca98` In the official UI: [open it read-only in a new tab](https://dev.vault.sgraph.ai/#sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15%3A3d04e6b9ca98) · From the CLI: `sgit clone sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15:3d04e6b9ca98` Published deliberately. It grants read, and only read — a write attempt is refused by the server’s write gate (the **R1 W0** badge you will see in the chrome). ## See it live, here Both surfaces open automatically below. You can also [**open the gallery app in its own window ↗**](https://dev.vault.sgraph.ai/#sgit_rk1_0a0f34839d737eef0f8f66e5236990b1f397af064763e3f71dca2717015f9d15%3A3d04e6b9ca98) — the read key travels in the URL fragment, which the vault UI accepts directly. ## What this vault demonstrates | Feature | How this vault uses it | |---|---| | Real binary payload | 60 WebP photographs in three sizes (originals ≈29 MB total, web ≈1600px, thumbnails) — every byte stored and served as ciphertext | | Auto-opening gallery app | `app.json` sets `auto_open` with a minimal HUD; the app is an editorial photo story with chapters and a lightbox, driven by `gallery.json` | | Content + narrative | `NARRATIVE.md` carries the written week; `gallery.json` carries per-photo titles, captions, chapters — edit the JSON, push, and the gallery updates | | Deep history | 36 commits of organising, captioning and re-cutting — open the SGIT view above and read the story of the story | | Owner secrets done right | `.vault/owner/readonly-tokens.json` decrypts to *further ciphertext* — owner bookkeeping is double-encrypted under a key the read key cannot reach | ## What is going on here, step by step The two embeds above are the real product, which makes them easy to scroll past without noticing what is unusual. Each row below points at one thing and says why it matters. Every screenshot is of this vault, driven by a script that opens it with the **published read key** and nothing else — the same credential printed at the top of this page. the app itself ### The app is real HTML, not a viewer The gallery is the vault's own `index.html` — an editorial layout with chapters, pull quotes and photo rows, written as ordinary HTML and CSS. Nothing renders it into a fixed "photo album" template: whatever the author wrote is what runs. Each photograph here arrived as ciphertext, was decrypted in the browser, and was handed to the page as a `blob:` URL. The server never saw a picture — it served opaque bytes and has no idea this is a gallery. A chapter row: two decrypted photographs, laid out by the vault’s own CSS. interaction ### Click a photo and the app takes over Because the app is real HTML, it can behave like any web app. Clicking a photograph opens the gallery's own lightbox: a larger image, the caption and chapter from `gallery.json`, and arrows to move through all twenty. This is the part that surprises people most — an encrypted store is usually a download-and-open experience. Here the interaction is authored *inside* the vault and the reader never leaves the page. The lightbox: caption, chapter, position (1 / 20), and prev/next arrows. watch it decrypt ### A pane that shows the decryption happening The app frame ships with a debug pane, and its **Vault** tab is the timeline of the open: the vault unlocked, the file tree loaded, `app.json` found, the app iframe ready — each with the milliseconds it took. Read the key line: the vault opens from a key that is shown truncated, and the file tree — *seventy files* — is built in the browser from encrypted directory objects. Filenames are encrypted too, so even the folder structure is something the client reconstructs rather than something the server reports. The Vault tab: each step of the open, with timings. the sg bridge ### And a console you can type into The **REPL** tab is a small console over the `sg.*` bridge — the same API the app itself uses. `vfs.list` walks the decrypted tree, `vfs.read` prints a text file. Note what the help text says about writing: `vfs.write` and `vfs.delete` are marked *writable vaults only*. This page's key is read-only, so those commands are refused — not hidden by the interface, but impossible, because no write capability exists anywhere in the chain. vfs.list at the vault root, then inside /photos — typed live, answered from decrypted objects. transparency ### The whole vault is browsable — including its source The second surface on this page is the vault browser. It shows the real tree: `photos/originals/` with its twenty WebP files, the thumbnails and web-sized copies beside them, and the app's own files. Open `index.html` and press **Source** and you are reading the gallery's code — the same 29.9 KB the app boots from. A published vault is transparent in a way a hosted gallery rarely is: the reader can inspect exactly what is running. photos/originals expanded, with index.html open in source view. version control ### And it is version control, not just storage The **SGIT** tab is why this is sgit rather than a folder in the cloud. Every commit that built this gallery is here — thirty-six of them — with real object ids, dates and branch labels, and `tree` and `diff` links per commit. This is the vault's history, read from the same encrypted objects, with the same read key. Nothing was re-uploaded to make it browsable: the history *is* the storage. The SGit view: the commit history of the gallery, read-only. **How these pictures were made.** They are not mock-ups and they are not hand-cropped. `admin/build/capture_shots.mjs` opens this vault in a real browser with the published read key, performs the navigation each row describes — scroll to a chapter, click a photograph, open the debug pane, switch to the REPL and type `vfs.list`, expand `photos/originals`, switch to the SGit view — and crops the result. Re-running it after the vault changes regenerates every image. The tool takes a read key, so it can document any published vault the same way. ## The audit, honestly Every vault gets an audit before its read key is published here, and this one has a finding worth stating plainly: the server-side bookkeeping file for a public preview (`.vault/owner/public-previews/…`) carries a live `delete_auth` token, readable by anyone holding this read key. Its scope is narrow — it permits deleting or replacing that one *public preview*, not writing to the vault, whose write gate remains closed — and the owner has been advised to rotate it. It stays on this page because the finding class is the lesson: bookkeeping written into vault content travels with the read key forever. The newer pattern — owner secrets double-encrypted, as the row above shows this same vault doing for its read-only tokens — is the fix. ## What this shape is for Photo albums, trip diaries, family archives, portfolio galleries — anything where the pictures should not sit plaintext on someone else’s server, but a single shareable key should open the whole experience, chapters and captions included. This is the first of several galleries in [the catalogue’s](../../../catalogue/index.md) awaiting list. ## Derived facts 71 files · 29 MB · 36 commits · app entry `index.html` · derived from the read key alone by `admin/build/catalogue_derive.py` — the same derivation that populates [the catalogue](../../../catalogue/index.md), where this vault also has an entry. ============================================================================== # Demos — sgit.ai > Live end-to-end demonstrations: vaults actually created, pushed, and embedded in the pages that document them, each with a deliberately published read-only key. > > Page: https://sgit.ai/demos/index.html [Home](../index.md) / Demos # Demos Live, end-to-end demonstrations — each one a vault that was actually created, pushed, and embedded in the page that documents it. The walkthroughs are complete: every command, the keys that are deliberately public, and the ones that never will be. **The rule every demo follows:** the vault's *read key* is published on purpose — it is derived one-way and cannot write, so publishing it is what makes the demo openable by anyone. The vault's *write key* appears nowhere: not in these pages, not in the repos, and the build refuses to push if one ever reaches a tracked file. ## Published [Gallery · live### A vault app, live inside this pageField Notes: a self-contained vault app created from scratch, pushed, and opened inside sgit.ai with a published read key — sandboxed iframe, postMessage bridge, every byte decrypted in your browser.Open the walkthrough →](vault-app-embed.md) [Report · real### The Strategy in Seven MapsNot demo content: the actual SG/Send strategy, published on LinkedIn in May 2026, served live from a vault with a published read key — plus the audit that shows why the original vault could not publish its key, and the republish pattern that fixed it.Open the walkthrough →](strategy-maps.md) [Analysis · live### sgit, on a Wardley MapSix maps of sgit's own positioning — where git wins, where the boundary falls, the agent as the new user — drawn as inline SVG and served as a **second app from the same vault** as the strategy essay: one store, two entry points, one read key.Open the analysis →](sgit-maps.md) ## Coming next Two more shapes from [the plan](../admin/plans/why-expansion-plan.md), on the same template: a **two-agent inbox** vault (produced by actually running two sessions against it), which gets the full transcript, its own published read key, and a live embed. [← Home](../index.md)[The first demo →](vault-app-embed.md) ============================================================================== # A vault app, live inside this page — sgit.ai demos > The complete walkthrough: create a vault app, push it, derive and publish the read key, and open the app live inside a sgit.ai page in a sandboxed iframe with a postMessage window.sg bridge. > > Page: https://sgit.ai/demos/vault-app-embed.html [Home](../index.md) / [Demos](index.md) / Vault app embed # A vault app, live inside this page Below is an application running out of an encrypted vault, embedded in this page with nothing but a **published read-only key**. This walkthrough is the complete process that produced it — every command, the key that is deliberately public, and the one that never will be. **The one-sentence mechanism:** the vault's ciphertext is fetched from the SG/Send server over CORS, decrypted in your browser with the read key printed on this page, and the vault's `index.html` is booted inside a sandboxed iframe with a `window.sg` bridge — the same shape SG/Vault's own vault-in-vault embedding uses. No copy of the app or its content exists on sgit.ai. ## The live embed Click to open it. The status line inside the app will read `content: sg.vfs.readText("content.json") — live from the vault`, which is the bridge proving itself: the app asked the embed host for a vault file and got it. Loads ~10 encrypted objects from `dev.send.sgraph.ai` and decrypts them here. Nothing you do in it can write — the page only holds a read key. ## How this vault was made, end to end **1 — Write the app.** A vault app is one self-contained `index.html` — CSS and JS inlined, content in `content.json`, generative SVG instead of image files — plus an `app.json` that auto-launches it. It follows the [authoring contract](../vault/vault-apps.md): no ``, ` ``` ## What works statically — and what doesn't | Call | Static? | |---|---| | Open, browse, read files, history — `sg.vfs.read/readText/list` | ✅ plain GETs | | Large reads | ✅ falls back from presigned to direct GET | | Batch reads | ✅ fan out to parallel GETs, identical result shape | | Writes, deletes, `sg.append.*`, vault creation | ❌ rejected cleanly with `EREADONLY` | A static vault is a **read-only snapshot** — ideal for published docs, reports, dashboards and view-only shares. The app detects it via `sg.app.writable === false` and hides its editing UI; the same HTML runs writable against the live endpoint. *Same app, two backends.* ## The layout — path mirroring is the one hard requirement The live API serves `GET /api/vault/read//`; the static host must serve the vault's encrypted `bare/` tree at exactly that path under your base: ``` / → https://my-org.github.io/my-vault/ └── api/vault/read// └── bare/ ├── data/ obj-cas-imm-* # immutable — cache forever ├── refs/ ref-pid-muw-* # mutable head — no-store ├── indexes/ idx-pid-muw-* └── keys/ key-rnd-imm-* ``` If the repo is your vault's own git remote (working tree + `bare/` committed per the [side-by-side pattern](git-and-vaults.md)), the encrypted tree is already in the repo — publishing is just placing it under the right path prefix. Visitors open `https://…/my-vault/#`: the key travels in the URL fragment (never sent to the host), the transport GETs ciphertext, the browser decrypts and renders. ## Honest caveats - **Read-only and frozen.** The static tree is a snapshot at export time; new live commits appear only when you re-export. - **Paths must match exactly**, or reads 404. (A configurable read-path template is a proposed follow-on, not shipped.) - **Cross-origin setups need CORS** on the static host for GETs; same-origin needs nothing. - **The key is the read capability.** Anyone with the full URL can read the snapshot — that is the point of publishing one — but the host itself only ever holds ciphertext. [← Git repos inside vaults](git-and-vaults.md) ============================================================================== # Admin & engineering — sgit.ai > How the sgit.ai site is built: a vault app with generated pages, bridge-loaded assets, a validation suite, and sgit itself as the deployment pipeline. > > Page: https://sgit.ai/admin/index.html [Home](../index.md) / Admin # Admin & engineering How this site is built, shipped, and versioned. sgit.ai is not hosted on a web server — it is a **vault app**: a set of HTML pages living inside an encrypted SG/Send vault, decrypted and rendered in your browser. The site about sgit is delivered by sgit. ## Architecture ``` # published site — one folder per section; root holds only what must live there ├── index.html · index.md # the front door + its markdown twin ├── CNAME · app.json · robots.txt · sitemap.xml ├── llms.txt · llms-full.txt # machine index; every page in one file ├── why/ · try/ · security/ · skills/ · briefs/ ├── use-cases/ # patterns, each with an evidence status + agent brief ├── case-studies/ # things that actually happened, with numbers ├── docs/ · vault/ · deploy/ ├── assets/ # site.css, site.js, vault-docs.js, try-setup.py └── admin/ ├── content/ # page bodies — one file per page, plus pages.json └── build/ # build_pages.py (the engine) + validate.js ``` ## Adding a page Content and machinery are separate, so nothing in the generator grows as the site does — it was 2,709 lines with every page inlined, and is 648 now that bodies live in `admin/content/`. A new page is a file and a row: ``` # 1. write the body — just the
, no head, no nav, no footer $ vim admin/content/case-studies/my-study.html # 2. register it: { "path", "section", "title", "desc" } $ vim admin/content/pages.json # 3. build and check $ python3 admin/build/build_pages.py && node admin/build/validate.js ``` The build then produces, for free: the page with nav and footer, its `.md` twin with links rewritten to markdown, its row in `llms.txt`, its section in `llms-full.txt`, its entry in `sitemap.xml`, and its canonical, Open Graph and JSON-LD tags. The validator refuses the build if the page is unreachable from anywhere, if a link or a markdown twin is missing, if it carries no structured data, or if it could render invisible without JavaScript. - **The authoring contract.** Vault pages render inside a sandboxed frame, so declarative references to vault files (``, `