Skip to content
SkyKeephelp

Demonstration installation

The PLAIN-TEXT corpus counts below describe the corpus that ships with SkyKeep, which is what this deployment installs — SKYKEEP_DEMO_CORPUS_URL is unset, so nothing has replaced it. If that changes, this note changes with it. The mixed-format corpus is separate configuration and ships with nothing, so it gets its own reading of this deployment below.

On this deployment admin001 signs in on the password alone, and needs no mail relay. Both acknowledgment phrases are present, so SKYKEEP_DEMO_ADMIN_MFA_OFF makes demo_setup enrol the administrator with the second factor off — the same state the six demonstration people are already in, and a state any account can reach from its own profile page. There is no separate sign-in path: the ordinary MFA policy resolves it. The same phrase admits demo_signin, which puts the demonstration's delegated administrator (clientadmin) in that state too — and creates it, since demo_setup makes no such account.

The mixed-format corpus on this deployment

This deployment is configured for demo_setup --mixed: all three settings it needs are set, so the flag loads the mixed-format corpus beside the ordinary one rather than refusing. That is 89 more documents through the same real pipeline and both scan gates, and the ingest-budget preflight counts them together with the ordinary corpus — so this is the run that may need a larger SKYKEEP_DEMO_INGEST_BUDGET_SECONDS. What the corpus contains is described in the mixed-format corpus note below.

A vault already built WITHOUT the flag does not hold it: the flag is read at build time, and a re-run empties the vault first.

This mode makes a vault deliberately weak. It exists so a complete, populated, immediately demonstrable vault costs one command instead of an afternoon — and the three properties that make it repeatable would be a serious vulnerability in any real deployment. It is therefore fenced by the engine rather than by this page: it refuses without an explicitly typed marker, refuses on a vault holding data it did not itself create, and is reachable only as an operator command — no HTTP route on any interface reaches it, for any caller, including an administrator. Both refusals leave the vault untouched.

Built it already and want to know what to click? Presenting the demonstration is the ordered script, with sample questions that need more than one document to answer.

  1. What it makes

    Two compartments, hr and sales, and six accounts — a writing one and a read-only one for each grant: user_hr and user_hr_ro on hr, user_sales and user_sales_ro on sales, user_both and user_both_ro on both. The three unsuffixed accounts hold WRITE level and the three _ro accounts hold READ level; a write grant implies the read grant, so the difference is uploading and nothing else. A read-only account signs in, searches, asks, Thinks, reads summaries and follows citations exactly as far as its writing twin — it simply has no upload control on its page. Then the demonstration corpus: 269 documents that ship INSIDE the product as a committed archive — twelve kinds in eleven different file formats: user manuals as PDF, Python Enhancement Proposals as plain text, open-access biochemistry papers as PDF, HR policies as .docx, spreadsheets as .xlsx, sales figures as .csv, essays on Voltaire's Candide as .odt and again as .rtf, product decks as .pptx, photovoltaic price graphs as .png, ten photographed pages of real handwriting as .jpg, and five college-level essays in FRENCH on Greek myth as .docx and .odt — the corpus's only non-English documents. Every document carries its own provenance row — where it came from, under what licence, and whether it was downloaded from the public web or generated for this demonstration. The corpus is split by CATEGORY, one category per kind: sorted alphabetically, the first third of the categories lands in hr, the middle third in sales, and the last third in BOTH — twelve categories, four in each slice. Each portion is uploaded BY the account that owns it, through the ordinary ingest pipeline — user_both places the shared categories because it is the only account holding both write grants. Twenty-four of the 269 arrive HELD, two of every kind: uploaded through the same pipeline and both scan gates, then deliberately left unprocessed in the review queue, so the demonstration has pending work of every format to show. Nothing is written behind the vault's back, so the demo vault proves the same rules a real one does. Afterwards user_hr reaches 184 documents, user_sales 167, user_both all 269, and the administrator none. Each _ro account reaches exactly what its twin does — the reach numbers are about grants, not about level.

    scripts/skykeep.sh demo_setup
  2. What it deliberately weakens

    Three things, and each one would be a serious vulnerability in a real deployment. All six accounts share ONE email address, so one inbox stands behind six identities that a real engagement would keep apart. All six share ONE weak password. And none of them is under forced first-login rotation — this mode is the single documented exception to the rule (ADR-0012) that every provisioned account must replace its admin-known password before the vault will do anything else for it. NEVER point this mode at a deployment holding real data.

  3. The second factor, and why these accounts skip it

    All six demonstration accounts are created ALREADY ENROLLED with MFA off (ADR-0025), so they sign in on the password alone and a demonstration needs no mailbox at all. This is the ordinary policy, not a waiver: enrolled-with-MFA-off is a state any account can be put into from its own profile page, and the vault treats these six exactly as it would treat anybody in it. A read-only account signs in exactly like its writing twin, on the same shared password: access level is a grant, never an authentication difference. The administrator and the demonstration's clientadmin are not among the six, so whether THEY are asked for a code depends on this deployment: with SKYKEEP_DEMO_ADMIN_MFA_OFF set they are put in the same enrolled-with-MFA-off state and sign in on the password alone, and without it the ordinary policy asks them for a code. The paragraph further down reads this deployment's configuration and says which it is, rather than asserting one here. ADR-0012's forced first-login rotation still outranks all of it. The phrase-fenced sign-in waiver this replaced (SKYKEEP_DEMO_SIGN_IN_WITHOUT_CODE, ADR-0023) has been removed: the bespoke branch in the authentication path was the part of that arrangement carrying real risk.

  4. What is NOT weakened

    The vault's answers. No demonstration setting touches the compartment predicates, the row-level-security backstop, the two ingest scan gates, or the completeness of the audit trail. Every waiver widens who may sign in with what, or who may read the record — never what the vault will hand over, and never what it will record. A wrong password is still refused, forced rotation still outranks every MFA policy, and every sign-in is audited with the rule that decided whether a code was demanded — including when it was not.

  5. What it refuses without

    Three prerequisites, each refused by name and each refusal leaving the vault untouched. (1) The marker: SKYKEEP_DEMO_INSTALLATION must carry its exact acknowledgment phrase — unset, empty, or a plausible boolean like true or 1 all refuse. Since ADR-0027 this is the ONLY fence: behind it the command EMPTIES the vault and rebuilds the demonstration from nothing, so that it lands in the same state every time however much anybody clicked around first. It never touches the audit trail, the schema, or the console settings. Never set the marker on a deployment holding real data. (2) Its own configuration: the shared address and password, and the bootstrap administrator's identifier and secret, have no built-in defaults. (3) A configured corpus directory (SKYKEEP_DEMO_CORPUS_DIR) to expand the corpus into. The corpus itself ships inside the product as a committed archive, so building the vault needs NO network reach at all — unless SKYKEEP_DEMO_CORPUS_URL is deliberately set to load an alternative corpus zip, in which case that source must be reachable (an http(s) URL) or readable (a local path). It needs NO mail relay, to build the vault or to sign in to it: since ADR-0025 the six demonstration accounts are enrolled with MFA off and sign in on the password alone. What that leaves for the ADMINISTRATOR depends on this deployment, so the paragraph below reads it rather than telling you here.

  6. How long it takes

    The corpus load is the slow part, because every document goes through the real pipeline: parse, both scan gates, classify, chunk, embed, encrypt, write — 245 of the 269 all the way, while the twenty-four held documents stop before the model-facing steps. Measured on the reference development stack ON 2026-08-25, against the RETIRED 85-document plain-text corpus this mode used to load: 44 to 50 seconds with the default four workers, against 136 seconds with SKYKEEP_DEMO_INGEST_WORKERS=1 (strictly sequential). TREAT THAT FIGURE AS A FLOOR, NOT A FORECAST: the shipped corpus is now 269 documents in eleven formats, most of them far longer and far heavier to parse than the old papers — PDFs, spreadsheets, slide decks and photographs, none of which were in the measured run. The measurement also predates content-type detection, a second stored artifact per version, and ingestion asking a model to read each document for its summary — one generation call per admitted document. So on a CPU-only host expect materially longer, and treat the old claim that embedding is the dominant cost as unproven rather than as guidance. It has not been re-measured. SKYKEEP_DEMO_INGEST_SECONDS_PER_DOC and SKYKEEP_DEMO_INGEST_BUDGET_SECONDS are the deployment's own estimate of that cost and the ceiling it refuses above; the shipped values allow for a corpus of this weight rather than for the plain text that preceded it. The corpus needs no download at all: it expands from the committed archive in under a second.

    SKYKEEP_DEMO_INGEST_WORKERS=4 # the default
  7. The mixed-format corpus (--mixed)

    A SECOND corpus, installed only when you ask for it, and installed BESIDE the one above rather than instead of it: one document per format the vault can read — txt, md, html, htm, docx, pdf, pptx, eml, mbox, epub and rtf — plus a small generated records layer of three custody registers (csv and tsv) and a custodian directory (xlsx): 89 documents in 14 formats. It is where the evidence for the presenter runbook's questions about references, matter codes and custodians lives, so without it those questions have nothing in the vault to answer from. It is off by default because it is roughly ninety more documents through the same real pipeline. Three prerequisites, refused BY NAME and changing nothing: SKYKEEP_DEMO_MIXED_CORPUS_URL (an http(s) source; no built-in default), SKYKEEP_DEMO_MIXED_CORPUS_DIR (where it is prepared) and a positive SKYKEEP_DEMO_MIXED_CORPUS_MAX_BYTES. The first two have no default, so leaving either unset is what makes it missing; the third defaults to 16 MB and is missing only when set to something non-positive. In any of those cases the command REFUSES — it never loads the ordinary corpus alone and tells you it succeeded. The ingest-budget preflight counts BOTH corpora together, so a large ordinary corpus plus this one may need a larger SKYKEEP_DEMO_INGEST_BUDGET_SECONDS, set deliberately. --mixed and --accounts-only contradict each other and are refused together.

    scripts/skykeep.sh demo_setup --mixed
  8. Demonstrating with your OWN documents, or an imported wiki

    The corpus above is a default, not a fixture. SKYKEEP_DEMO_CORPUS_URL points this same command at a different corpus zip — an http(s) URL or a local path — and everything else is unchanged: the same manifest rules, verified exactly as fail-closed, the same accounts, the same real ingest pipeline, the same two scan gates, the same audit trail. A zip whose MANIFEST.csv disagrees with what the archive holds is refused before a single document is written. To point a container at a LOCAL zip, put it in the directory SKYKEEP_DEMO_CORPUS_SOURCE_DIR names (it is mounted read-only at /app/demo-corpus-source) and set SKYKEEP_DEMO_CORPUS_URL to /app/demo-corpus-source/<that file>. Mount the DIRECTORY, never the file. Note that a corpus is prepared ONCE into SKYKEEP_DEMO_CORPUS_DIR: to switch corpora, point that at a fresh or emptied directory, or the finished expansion already there short-circuits the change. To BUILD such a zip from a wiki, the product ships an importer (ADR-0054). It reads either a set of Wikipedia pages through the MediaWiki API or a Confluence HTML space export — the zip a space administrator downloads from Space tools, Content Tools, Export, HTML, which needs no API access and no token. It writes a corpus zip in exactly the shape above, every row carrying the source URL and the licence. A Wikipedia import needs SKYKEEP_IMPORT_USER_AGENT set to something naming you and a contact address; unset, it refuses rather than calling anonymously. Group the pages so the corpus has more than one category: the demonstration splits compartments BY category, and a single-category corpus lands entirely in one compartment, which cannot show what this product is for. Nothing the importer writes is sanitised — the vault's own parser is what strips scripts and refuses unsafe links, and every imported document goes through it like any other upload.

    python -m skykeep.importers --wikipedia --group "Cells=Solar cell,Perovskite solar cell" --group "Policy=Net metering,Feed-in tariff" --out ./src/skykeep/demo/data/my-corpus.zip
    python -m skykeep.importers --confluence-export ./MySpace-export.zip --out ./src/skykeep/demo/data/my-corpus.zip
    SKYKEEP_DEMO_CORPUS_URL=/app/demo-corpus-source/my-corpus.zip SKYKEEP_ENV_FILE=.env.demo scripts/skykeep.sh demo_setup
  9. Running it again

    IT EMPTIES THE VAULT FIRST. A second run is not incremental and does not converge onto what is already there: emptying is the FIRST write it makes after the demonstration fence passes (ADR-0027), and everything after it is built on an empty vault. That is precisely what makes a re-run land in the identical state rather than merely not failing — but it means ANY DOCUMENT UPLOADED SINCE THE LAST RUN IS DESTROYED, including anything an audience uploaded during a demonstration. Look before you run it. The whole 269-document corpus is then re-ingested from scratch, so a re-run costs the full load, not a second. The audit trail is NOT erased — it lives in a physically separate database and the emptying deliberately does not touch it — but note that the emptying itself writes no audit entry either. What the trail will show is the rebuild: every compartment, account and upload the re-run creates goes through the ordinary audited console path under a real administrator, so the rebuild audits exactly as an operator's would. The disappearance does not.