Trust model

Plainly. After each session, the hooks copy your ai's own session transcript into ~/alexandria/files/vault/ on this computer. That is the point, not a side effect: the loop learns you from your past sessions. Nothing is sent anywhere unless you separately turn on a connection. Setup adds Alexandria's hooks to your ai app's settings and preserves everything else there; the uninstaller removes those hooks and keeps your files. The signing key below is also published by GitHub, independently of Alexandria's server, so you can check it without trusting us.

Alexandria is not an agent and not a service — it is a method your own ai runs: plain Author files at ~/alexandria/, plus a small automatic runtime at ~/.local/share/alexandria/ that points your ai to those files and archives session transcripts locally. The AI is granted write access to the Author folder, not the runtime; a prompt that changes personal files cannot replace the next automatic hook or its verification marker, cannot grant the consent an automatic connection needs, and cannot make a hook run code or git settings from that folder. Your ai does the reading, writing, and learning; these files tell it how. The core is one local loop: passive ordinary sessions use the approved mirror and preserve clear signal; each new ordinary foreground task receives a first-reply instruction for the visible consent question; /a develops what accumulated; a. preserves the shift; local capture and Git keep the history. Native terminal chrome may remain as ambient status, but it does not replace the assistant sentence. Setup, security review, background work, compaction, subagents, and explicit Alexandria start/close tasks stay silent. A hook systemMessage, warning field, valid JSON result, hidden instruction, tool output, daily claim, or matching transcript string is never treated as proof that the Author saw the question; only the completed assistant reply is. The question does not repeat later in the task, and touch ~/alexandria/system/hooks/visible-cue.off turns off the whole automatic return path immediately. After the private loop works, onboarding checks the saved account-instruction field and a brand-new chat's accurate account-preference summary against the final block. Only a verified matching version records the instruction hash in its separate completion marker. This proves loading, not shared record access: retrieval, writing and retrieval in another chat require their own checks. Unsupported or deferred chat coverage stays unverified without blocking verified local readiness. It remains core because without the link the loop depends on the Author remembering, not because the Author is forced to keep it. Five starting method files are installed on top but remain removable or replaceable; moving one into ~/alexandria/system/canon/disabled/ turns it off, and both setup and update notices respect that choice. Shared skill and rule names remain user space. Setup first checks an exact path-and-hash ownership receipt or exact prior signed bytes. Its legacy recovery also recognizes start/close skills by their registered name plus the signed source description, allowlisted Cursor hook filenames by a matching Cursor hook: header, and Cursor rules by the signed source description. These narrow identity checks can adopt and replace an older or locally edited matching file; they are compatibility heuristics, not cryptographic proof of ownership, and a foreign file copying that identity can collide. Other files are preserved and the integration reports incomplete. Review local changes before an update. Additions wait for a direct local need. Connections to updates, an account, Library, marketplace, cloud, outbound messages, or twin services stay off until separately approved. Public Library reading stays in the browser or a genuinely isolated reader instead of flowing into the private loop. Every session, the shim runs only the engine payload pinned in the protected runtime after that exact file has passed signature verification against a manifest signed with a key that cannot leave the maintainer's Mac. Nothing self-updates or checks for updates by default. This document explains the mechanism and what it does and does not defend against.

The visible route uses the current host's real skill invocation: a slash command in slash-command hosts, a dollar-sign command in Codex, and the plain request start an Alexandria session as the portable floor. Typing the bare word alexandria is not treated as a universal skill trigger.

TL;DR for the auditor

  • The structural claim — none of this document asks you to trust the maintainer: we can't receive your private data (no protocol endpoint takes your private files, and the hook has no code path that reads them into any request — the session sync reads only your explicit publish outbox), can't change your machine after install (code pinned + hardware-signed; anything new applies only by your explicit action), and can't hide (every invited person's ai can read the full source, the surface is small, and the adversarial audit prompt factory/redteam.md ships inside it). Every leg is verifiable below.
  • What runs: plain bash, Python, and markdown. Your editable files live at ~/alexandria/; automatic hook programs, their verification markers, and the grants that allow any automatic outward work live separately at ~/.local/share/alexandria/, outside the writable root granted to the AI. The core loop is described above.
  • What the install does NOT do: no cloud connection, push to any remote, repo creation, key upload, or scheduled job. Capture shortcuts and other local additions wait until you ask for them. Git backup, iCloud capture/current-file recovery, the Google Drive chat pocket copy, Airlock, Library publication, marketplace signal, scheduled outbound messages, and twin services are connections — each needs its own explicit yes after install (~/alexandria/system/.optional documents what each touches, what leaves the machine, and its off switch). Git is the owned history; GitHub is only the default remote host.
  • Source of truth: the private alexandria-inc/alexandria repository, readable in full with an invite at api.alexandria-library.com/source/<invite>/. Auditable line by line.
  • Trust model: consent-symmetric. Your agent may pin setup to one verified Git commit. After that, the shim only runs the payload pinned on your disk, and every factory file is covered by a manifest signed with a Secure Enclave key that cannot leave the maintainer's Mac. Nothing self-updates or checks for updates by default. Signed update notices are a separate opt-in; your installed verifier authenticates any update before it runs. Existing installs resist later server or GitHub-account compromise; a fresh install that needs that protection must confirm the release fingerprint through another trusted channel. Full mechanism below.
  • What our server holds: if you give an email during setup, we keep the address, the route you chose, an unsubscribe token, and a hash of the invite code it came with, so we can send that setup and occasional useful notes until you unsubscribe. That does not create an account or install record. For each invite code we also keep when the source was first read with it and how many of the people it brought have joined. Both are kept per code, with no IP, device, or record of what anyone read. If you later create an account, we also hold your GitHub user ID, hashed API key, a 60-day event log of which endpoints you hit, and any profile fields or files you explicitly publish to the Library.
  • What our server does not hold: your constitution, vault, marginalia, transcripts, or AI-vendor API keys. There is no endpoint that accepts them.
  • Account boundary: connecting stores one exact-format key and one removable people-context permission. It does not publish, sync, create a model or draft a hosted profile unless the Author requested that page. A website-only client needs no private loop. Public other-person material is read only for an approved relevant task and remains untrusted data; no prompt or private record is sent. Publishing remains a separate exact-byte approval.
  • Uninstall: the commands near the end of this document. Reversible.

Threat model

We claim:

  1. The install does what this document says, and only that. Auditable line by line.
  2. Your private cognition (constitution, vault, marginalia, transcripts) never leaves your machine via Alexandria. There is no endpoint that accepts it.
  3. A complete breach of our server yields the data listed above and nothing more — because nothing more is stored.

We do not claim:

  • Zero metadata. The server logs which endpoints your account hits and when (60-day TTL in KV), and Cloudflare logs IPs at the edge.
  • Immunity to the maintainer's Mac being compromised. The signing key cannot be exported from Apple hardware, but code running on that Mac as the maintainer could sign with it; since 2026-09-25 signing needs no fingerprint prompt, by design, so the maintainer's agents can release unattended. Compromise of the repository or GitHub account alone is not sufficient. The rotation procedure is below.
  • Protection from an AI tool you deliberately run without a filesystem sandbox. The protected runtime is outside the writable roots Alexandria grants to supported agents, but every file is still owned by your OS account; a truly unsandboxed process running as you can alter any user-owned file.
  • Zero risk. AI tools execute hooks with your shell privileges. That is true of every editor extension, every dev-server, and every shell hook on your machine — but it is true here too.

Trust root

Two P-256 keys, both generated inside the Secure Enclave of the maintainer's Mac. Either may sign a release.

  • Mac key (signs releases since 2026-09-25): SHA256:p33nHmkn0rm09XTjoBRKezyxSk3qxdA3oYnvLPBhaMI. Signing needs no fingerprint prompt, so the maintainer's agents can release while he is away. It still works only on that one Mac.
  • Touch ID key (signed releases until 2026-09-25, still trusted): SHA256:9DVo6uNuieqKMdNtT0QIi/WoQAAbWl5i/t0Z5MdQ/Jg. Every signature requires a fresh match against the fingerprints enrolled when it was created.
  • Independent witness: GitHub publishes both keys as the maintainer's signing keys at https://api.github.com/users/benmowinckel/ssh_signing_keys. GitHub serves that record, not Alexandria's source route, so a compromised Alexandria server cannot change it. Compute the SHA-256 fingerprint of each key there and compare it with the ones above.
  • Public keys (verbatim, as installed at ~/.local/share/alexandria/allowed_signers):
    alexandria-payload-signing ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBETzcr+XjCojo7y6s+JU8UwqkOtzIv3h9kEQI/ef9/nuGolyXvLF8WXkoEDwFc3zkXxTbZ+TVWI5Uq0fgMxHvjM= alexandria-touchid
    alexandria-payload-signing ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBnntuFCVzj3xypcrpVPv7nToNOL/i4Kb/9SWKc6p2azYGjYhFokZj+wou53Nhnf4Bc11ZIDoaukrDuKnqrLYVQ= alexandria-mac
    
  • Private keys: non-exportable Apple hardware. No passphrase, agent cache, CI secret, or backup copy can sign. Why the fingerprint prompt was dropped: it only ever protected against code already running on the maintainer's Mac, and such code could get a routine tap approved anyway. What matters for Authors is that a stolen GitHub login, a compromised server, or anyone without that Mac cannot sign.

First-install identity

The repository is private and downloads are invite-only (2026-09-15). The official first touch gives no executable command, fingerprint, or vendor-authored verification recipe. It states, in the user's voice and read by them before they send it, their intent to set up their own personal data system from the blueprint at the invite-gated source address https://api.alexandria-library.com/source/<invite>/main/. It names the lasting effects (hooks in their coding tools, session copies kept in ~/alexandria, and write access to that folder) and exactly what needs no check-back (reading the project, looking at how the computer is set up, creating what the system needs, adding instructions and skills to their tools, and running the setup script once the agent has read it), keeps everything they use working, keeps their material private, and tells the agent to stop if anything looks unsafe. It also asks, in the user's own message rather than repository authority, for the connector and the exact join link. The user's message is the authority and the go-ahead; every Alexandria file remains reference material to evaluate. The agent chooses its own security process.

A robust process has two phases. First the agent reviews, read-only. It resolves …/source/<invite>/commit to one full commit hash and reviews the source at …/source/<invite>/<hash>/ without executing code or creating local state. Only when that review finds nothing unsafe does it act on the user's go-ahead and download that same revision from …/source/<invite>/<hash>.tar.gz and run its factory/setup.sh with ALEXANDRIA_SOURCE_COMMIT set to the hash and ALEXANDRIA_INVITE set to the invite code. Setup fetches every file through the same route pinned to that hash and authenticates the signed manifest before installing anything. The source route is Alexandria's own server, so it is not an independent witness. It notes only the first time each invite code reads it, with no IP, path, or device, so the maintainer can see whether invited people reach setup. It cannot forge the manifest signature, but the key embedded in setup.sh is only as trustworthy as the channel that delivered it. Confirm the fingerprint above through a channel you already trust, or decline to proceed. A script cannot authenticate itself with a key it supplies itself.

Existing-loop account connection

Joining does not authorize local setup. When the user's setup request asked for the Connector, joining happens last in the same sitting, after their own parts work and are marked ready. The joined handoff assumes the private loop already works and copies a short first-person request around a random alex_connect_… code, built in the browser from a fixed template in the same shape as the setup paste. The server returns only the code, never prose. The signed local instructions treat the code as opaque data, explain the narrow change, and wait for the exact word connect. The request may ask for the mirror and the Alexandria skill afterwards; anything public still needs the exact word publish for the exact bytes shown.

After consent, the verifier authenticates the signed factory/scripts/connect-account.sh. That connector refuses unless setup and local onboarding are complete, reads no private Author file, and writes only system/.api_key plus the removable system/permissions/people-context marker disclosed before consent. The browser carries a one-hour, one-use code, never the persistent key. D1 consumes the code atomically and the API checks live membership before minting a separate machine key. The connector never prints a server response or stores account status; a local parser accepts only an exact alex_ key shape or the exact existing-key flag, while failures become fixed local text plus an HTTP status. GitHub sign-in alone never rotates a working key, and connected_at remains separate from installed_at.

After the connector closes, the mirror starts empty: the tier folders exist, the member page carries only the name the account already has, and nothing of the person's is published. Later, when a session suggests it or the person asks, their own ai may use only local material it already had permission to read to prepare a private, ineligible profile draft at files/library/_profile.json. No public page or server-authored content enters onboarding. The shared renderer supplies the page design; the draft contains only the person's content. Existing public links are included only when the local material already identifies them as public. Nothing is published yet. The person sees every byte and must separately say the exact word publish; the signed one-shot publisher then verifies the approved hash, sends only the four allowed public-profile fields to /library/me/profile, accepts only the fixed {ok:true} response, and enables no standing sync.

Later ordinary work may use the signed person-context.mjs helper when a specifically named person materially affects the task. It first downloads the member directory without sending the name, so identity matching happens locally. It then makes GET requests only for that selected profile and exact files the current account can already open. The request contains the account key and Library address, never the prompt, private files, inferred relationship, or local context. The helper labels every returned byte as untrusted data; it can shape the answer shown to the person but cannot authorize a command, write, message, purchase, publication, or other outward action. Removing system/permissions/people-context stops those reads without disconnecting the account. Every profile revision, file publication, Marketplace call, backup, and other outbound capability still needs its own exact consent.

Inspect before running

Start at /start. Enter your private invite code, then set up with an agent on your computer, including one reached through Remote Control, such as Codex, Claude Code or Cursor. Claude Code Web or another trusted cloud agent can use only committed files in a repository you deliberately selected and writes its own branch. The Shortcut link adapts to the device: direct add on iPhone; Mac download and an iPhone QR code on computer.

On the computer route, the receiving agent independently inspects the invite-gated source, decides how my blueprint should fit around your existing setup, and gives you a short recommendation. It may continue with the current Mac files only after you approve. Claude Desktop's Code tab set to Local runs on your Mac. Claude web or mobile can reach those same current files only when it is controlling an already-running local Claude Code session; the screen is remote, but the files and execution remain on the computer.

On the cloud route, the receiving agent first evaluates only the invite-gated source. After start, it separately asks permission for the exact private sources and destination. Only then may an approved provider use the repository you selected for that provider. It can read committed files and write only to its own branch. It cannot see uncommitted Mac files, use Mac-only tools, or make its branch live by itself. Your trusted computer agent reconciles and closes the return. If you do not trust a provider with the sovereign repository, give it a bounded Airlock projection instead.

A regular chat can use an approved folder it can really write and read back. After permission for the named personal sources and destination, it stores the reviewed _start guidance beside the private record and runs the available loop explicitly when hooks are absent. It reads writes back, keeps the exact record location for later chats, and labels any unsupported instruction loading or record retrieval as unverified. A failed save is reported as a failure. The private loop does not require joining; give the neutral join link only when the person's originating request asked for it.

If you join, the welcome page has two steps: copy the connector, and invite your people. The connector copy is your own short request around a one-use connection code, built in the browser; the server returns only the code. Your computer agent explains the change simply and waits for connect, then helps build your mirror from both sides (a public summary drafted from your private map, plus the public links you name, on your own website or a page here), shows every word and publishes only on publish, then opens the Alexandria skill in a new chat. A website-only evaluation reads the public Connector module, checks the project you selected and recommends the smallest useful addition before changing anything. GitHub sign-in identifies your account; Stripe handles membership. Payout onboarding is only for authors choosing to sell through a supported hosted payment route, never a prerequisite for an independent public mirror.

The independent minimum is one JSON description pointing to selected public Markdown/PDF files on your existing website. No backend, model, company account, theme or migration is required. A copyable helper writes only that description. Optional live answers and protected material need an owner-controlled backend; the framework-independent handler can attach under an unused route. It reads only selected material and calls the owner's model. Independent public reads and model calls make zero Alexandria requests.

The paid Connector operates shared discovery, verified website addresses, reader identity and current exact access. Registering a static public mirror needs a website, description path and ownership proof; no callback or completed hosted profile. Listing is an explicit choice. DNS TXT is the current ownership proof, so a host without DNS control does not yet have a complete verified registration path. Repeating unchanged verified registration preserves its identity and reader sessions. A callback is added only for shared reader sign-in. Never put the owner's account key in the website.

For website-only users, factory/scripts/setup-connector.sh verifies an independently reviewed signed checkout and prepares only ~/.local/share/alexandria-connector plus ~/.config/alexandria/connector. It installs no loop, hooks, private record, model or website. The AI reads the local .connect instructions before a fresh opaque code and waits for exact connect; the signed connect-account.sh --website exchanges it privately. Existing loop users keep the original healthy-loop route. Both preserve the strict one-use code, current membership check and fixed response parser. Account connection completes without drafting or publishing a page. An Alexandria-hosted profile is optional.

Current membership gates the operated service. Scheduled cancellation keeps service through the paid period; expiry stops shared discovery and protected service requests. Renewal restores the connection and still-valid grants. A reader's exact invitation or purchase is separate from membership, and membership never creates such a grant. Public files, own-model answers and already delivered material remain the owner's or reader's; cancellation cannot recall copied knowledge. A billing outage denies the dependent shared operation without breaking independent public reading.

The setup is one bash script. The hooks payload is one bash script. The shim is one bash script. Everything below describes what they do.

What gets installed on your machine

~/alexandria/ — the Author-writable folder, initialised as a local Git repository (~/alexandria/.git/). Plain markdown and small JSON state files. All readable. The Git repo IS the substrate format — your worldline is a sequence of commits, your own to push to any Git remote (GitHub is the default if you gh auth login; any host works).

~/.local/share/alexandria/ — the small automatic runtime. Supported harnesses do not add this folder to the AI's writable roots. It contains only signed hook programs, their verification state, the scoped uninstaller, and permissions/: the grants and exact Library approvals you recorded with scripts/permission.sh, a step that only works outside the AI's sandbox. No cognition or transcripts.

Each automatic connection needs consent the AI cannot forge (below). bash ~/.local/share/alexandria/scripts/permission.sh status shows what is on.

PathPurpose
.git/Local Git repository. Your cognitive worldline as a commit history.
files/constitution/Your beliefs, personality, working style. You write these.
files/vault/Raw input — transcripts, notes, voice memos. You drop things in. vault/input/ stays local unless you separately enable the iCloud-capture add-on.
files/marginalia/Shared working layer between raw and settled — your developing thoughts + Engine candidates, drains over time.
files/library/{public,authors,paid,invite}/Optional publication outbox. Your source file may stay anywhere in your own structure; the default adapter is a file symlink under the exact permission folder. Add exact cohort folders when needed (invite/friends, paid/course); parent and sibling scopes never inherit. A file leaves only when Library sync is separately granted and your protected approval list names its exact scope, name, and the SHA-256 of its current target bytes.
files/library/filter.mdYour publishing policy — the canon-driven rule the Engine consults before promoting drafts to final.
files/core/Engine working memory: agent.md, machine.md, notepad.md, feedback.md, shelf.md.
files/works/Long-form pieces in progress.
~/.local/share/alexandria/hooks/shim.shBash wrapper outside the AI-writable root. Runs the pinned verified payload; checks upstream for signed updates only if you separately enable that option.
~/.local/share/alexandria/.hooks_payloadThe pinned engine payload. Runs only after passing hardware-signature verification.
~/.local/share/alexandria/.payload_verified_shaThe recorded hash of the verified payload — the pin. If the payload file changes without re-verification, the shim refuses to run it.
~/.local/share/alexandria/.canon_manifestThe signed manifest that backed this cached payload — every canon module is hash-checked against it before being written, so a compromised GitHub repo cannot push poisoned canon either.
~/.local/share/alexandria/.factory_versionHighest signed factory release this machine has accepted. Older valid manifests are rejected instead of being replayed as a downgrade.
~/.local/share/alexandria/.owned_integrationsExact path-and-hash receipts for skills, rules, droids, and Cursor hook files setup created. Re-runs and uninstallers require this receipt instead of trusting a filename or copied product sentence.
~/.local/share/alexandria/allowed_signersThe maintainer's P-256 public keys. Trust root for payload + manifest signature verification.
~/.local/share/alexandria/scripts/verify-fetch.shThe only later update door. It verifies the signed manifest, rejects rollback, verifies the requested file hash, then emits or runs those exact bytes.
~/.local/share/alexandria/scripts/{capture_resolver,capture_state,statusline,uninstall}.py/shSigned automatic helpers and the scoped remover, kept outside the Author-writable folder. capture_state.py is read-only: it gives the statusline a current count and lets /a freeze and prove the exact capture batch that existed when the session began.
system/canon/Signed local references, cached once and never auto-written afterwards. The loop: foundation.md, the complete passive → cue → active local core. Methods: axioms.md, methodology.md, editor.md, mercury.md, publisher.md; moving one into system/canon/disabled/ turns it off, and setup and update notices leave it off. Additions: local capabilities used only when chosen for a concrete job. Connections: Library/filter, marketplace, cloud, outbound messages, and PLM/twin stay dormant until exact approval. MODULES.md is the product map. A file being available here does not activate its feature. Signed updates are notices only; you pull one or ignore it.
system/modules.jsonThe signed machine-readable map of core, removable methods, available additions, and separately approved connections. The private AI reads its version locally; no account or server read is needed. Local files, protected grants, and their switches remain the authority for what is actually on.
system/.api_keyYour API key, mode 0600.
system/.blockOne-time onboarding instructions cached locally.
system/.optionalThe add-ons menu — what each opt-in add-on does, touches, and how to turn it off.

| system/.* (other) | Ephemeral state — session ID markers, sync logs, the error log, and last-maintenance timestamps. All readable. None leave the machine. |

Experimental AI access. Do not hand a tool you are testing your Apple login, Drive account, normal GitHub account, or sovereign repo. To connect one, open the trusted computer AI and type Airlock this new AI: <name or URL>. Airlock uses a separate GitHub account that may access exactly one private <ai>-airlock repo, belong to no organizations, and host one broad-OAuth experimental AI at a time. The repo contains a deliberately selected projection plus inbox/ files and airlock-capture issues for returns: a wholly public Library projection may refresh automatically, while any projection containing private bytes needs approval of its exact selection and stays frozen as a unit until changed bytes are reapproved. The controller verifies the account, credential, remote, visibility, organizations, complete accessible-repo list, manifest, and exported bytes before network actions. Every return becomes a trust: untrusted capture with no automatic authority to change files, run tools, or become canon. Switching broad-OAuth AIs requires importing the final return, revoking the old app, and deleting the old app's repo before creating the next app-named repo. GitHub account creation, sign-in, and third-party authorization remain human steps.

~/.claude/skills/{a,alexandria}/SKILL.md — the /a skill (and its /alexandria alias). ~/.claude/skills/a./SKILL.md — the /a. close skill: ends an /a session by capturing everything to your files, then asking what shifted — you say it, in your words; it files them. Plain markdown, all of them. cat them. (Cursor gets the same three under ~/.cursor/skills/. Grok CLI gets /a, /alexandria, and the close skill under ~/.grok/skills/.) If a or a. already belongs to another tool, setup leaves it untouched. It may install a namespaced fallback, but it reports the loop incomplete and keeps every hook inactive because the visible /a → /a. route would otherwise point at the wrong skill.

The Git substrate and commit signing

~/alexandria/ is initialised as a local Git repository. Your worldline IS a commit history — every Constitution edit, marginalia drain, and vault drop you preserve becomes a commit. The repo is yours; you can push to any Git remote (GitHub is the default if you have gh authenticated; any host works).

Git preserves the history; it does not certify the mind behind it. A valid commit signature proves that a particular key committed particular bytes. It does not prove that a human originated, understood, or freely chose the position. Alexandria uses Git as a flight recorder beneath its before→after review, not as an authorship oracle.

Root stewardship. root is a mark on a thought inside the living Constitution, not a second identity or a claim that an untouched self exists. The separate works/root.md file carries the minimal protected thought verbatim plus a pointer to its full, still-living reasoning; it does not duplicate the whole person. The Author does not maintain the list. At session start, before Constitution writes, at close, and during maintenance, the Engine compares the Constitution, recent material, deltas and Git history. It watches for unprotected positions that repeatedly govern other choices and for several small movements that together form one material drift. When something plausibly deserves exceptional protection, it creates or refreshes one plain-text packet in works/root-packets/ and leaves only a one-line pointer in marginalia. The Engine nominates; only the Author confirms what becomes root.

The packet contains the evidence, cumulative before→after, strongest case for and against, and the proposing model's identity and self-reported influence. It stays local. Alexandria never calls another model or sends the packet merely because that provider was authorised before. Independent review happens when the Author opens a qualifying model themselves, or after the Engine shows the exact packet and destination and the Author gives a fresh yes for that one call. The first qualifying model to encounter the local packet reviews it before discretionary work. Another session, alias, version or reasoning mode of the proposer does not count.

Only after the proposing AI marks the case ready and the independent reviewer marks the contest complete does the Engine ask the Author once for the substantive decision and reason in their own words. Adding a root mark, changing or deleting a root position, and removing the mark all run that same gate. An accepted designation lands the reviewed statement in works/root.md, keeps its Constitution pointer and completed packet, records provenance, and commits the result to Git. A rejected designation is recorded and not reproposed without new evidence. An unfinished case waits without nagging. Until all gates close, the old state remains current.

At session start, close and before a Constitution commit, a conforming Engine also compares the root set and protected statements against Git. An unauthorised addition, rewrite, deletion or unmarking pauses the commit and stays pending; nothing is silently restored. Reasoning around the exact statement can keep evolving normally. This is model-enforced semantic review plus a precise file-and-Git habit gate, not a cryptographic write lock: an Engine that ignores the instructions can bypass it, but the committed history makes the bypass visible and recoverable to the next conforming Engine. The exact-statement check closes accidental edits; the model remains responsible for catching a semantic reversal smuggled through different words.

The provenance stack. The transcript or vault preserves what was actually said; the delta packet preserves the cumulative before→after, arguments, influences, model identities and human correction; Git preserves byte history and key continuity. None proves inner authorship or freedom from persuasion. The nominating AI can steer salience and framing; different providers can share blind spots; human signoff can rationalise prior influence. Together the stack makes the causal record inspectable and partly reversible. It offers resistance, not immunity.

How signing works. setup.sh detects an existing SSH public key under ~/.ssh/*.pub (first one found, any type — Ed25519, RSA, ECDSA). If found, it (a) configures git inside ~/alexandria/ to sign with that key, repo-local — your global git config and other repos are untouched, (b) writes the key + your email to ~/.config/git/allowed_signers so git verify-commit and git log --show-signature work locally, and (c) signs the genesis commit. Every subsequent commit is signed automatically. All of this is local and offline — nothing is uploaded at install. Registering the key with GitHub (for the "Verified" badge) happens only when you enable the backup add-on, which is also the only step that creates the private alexandria-private repo on your own account and pushes to it.

The ~/.config/git/allowed_signers file (used by git verify-commit for your own commits) is not the same file as ~/.local/share/alexandria/allowed_signers (used by the shim to verify the maintainer's payload signature). Same file format, different purposes.

Soft fallback. If you have no SSH key, setup prints signing: skipped (...) with the reason and the genesis commit goes through unsigned. The worldline still works — you just don't get cryptographic key continuity on the ledger. Run ssh-keygen -t ed25519 and re-run setup to enable signing later.

OAuth scope. Alexandria's GitHub OAuth requests admin:ssh_signing_key at signup so the backup add-on can register your signing key without a separate scope-refresh step when you enable it. Existing pre-scope users see a one-time re-authorize prompt at next web login.

What you can verify yourself. git -C ~/alexandria log --show-signature shows the signature on each commit. git -C ~/alexandria verify-commit HEAD returns "Good signature" if signing is configured. On GitHub, the commit history page shows the green "Verified" badge on each commit. The signing key never leaves your machine; only the public key is uploaded to GitHub.

What gets modified in your config

FileChangeInspect
~/.claude/settings.jsonsetup.sh adds 4 hook entries: SessionStart ×2 (the shim, plus the capture resolver that turns links you saved into readable captures — see the network table), SessionEnd, SubagentStart. Same file Claude Desktop's code tab reads, so that surface is covered by the same entries — nothing extra to install.cat ~/.claude/settings.json
~/.cursor/hooks.jsonOnly if Cursor detected. Adds 5 hook entries pointing to the Python wrappers below — session start/end/stop plus per-prompt and per-response transcript capture (written locally to your vault, like the Claude Code transcript archive).cat ~/.cursor/hooks.json
~/.cursor/hooks/alexandria-{session-start,session-end,stop,transcript}.pyOnly if Cursor detected. Four small Python files that shell out to the shim or write the local transcript.cat ~/.cursor/hooks/alexandria-*.py
~/.cursor/rules/alexandria.mdcOnly if Cursor detected. Plain markdown rule.cat ~/.cursor/rules/alexandria.mdc
~/.codex/hooks.jsonOnly if Codex detected. Preserves unknown hooks; adds SessionStart, bounded 3-second SessionEnd, SubagentStart, and capture resolver entries. Codex requires the user to trust each new or changed definition in /hooks before it runs.cat ~/.codex/hooks.json
~/.codex/AGENTS.mdOnly if Codex detected. Preserves existing instructions and merges one small marked Alexandria block. If the full Alexandria agent instructions are already present, writes nothing. Legacy instructions.md is never touched.cat ~/.codex/AGENTS.md
~/.agents/skills/a/ + a./Only if Codex detected. Installs one start skill and the separate close skill. A foreign name is preserved; because the product's visible route is /a → /a., either collision leaves setup visibly incomplete rather than pointing at the foreign skill.find ~/.agents/skills -maxdepth 2 -name SKILL.md
~/.factory/droids/a.mdOnly if Factory droid CLI detected. Plain markdown skill.cat ~/.factory/droids/a.md
~/.grok/skills/{a,alexandria}/SKILL.md + close skillOnly if Grok CLI / Grok Build detected (command -v grok or ~/.grok). Native /a and /alexandria skills plus the close skill. A foreign name is preserved.find ~/.grok/skills -maxdepth 2 -name SKILL.md
~/.grok/hooks/alexandria.jsonOnly if Grok CLI detected. Dedicated owned hook file: SessionStart (shim + capture resolver), SessionEnd, SubagentStart. Does not rewrite ~/.grok/config.toml. Global Grok hooks are always trusted.cat ~/.grok/hooks/alexandria.json

Not modified: shell rc files (.zshrc, .bashrc, .profile), system PATH, sudoers, system services, launchd, cron, or cloud storage. The install does modify the detected harness folders (~/.claude/, ~/.cursor/, ~/.codex/, ~/.factory/, ~/.agents/skills/, ~/.grok/) exactly as listed above, may append the Author's existing public signing key to ~/.config/git/allowed_signers, and uses the Cursor sidecar ~/.alexandria/ for transcript staging and hook logs. The repo-local git config inside ~/alexandria/ is set; your global git config is not. The install schedules nothing and creates no background processes — scheduled jobs exist only inside opt-in add-ons, each installed only on its own explicit yes and each with a one-line off switch listed in ~/alexandria/system/.optional. Grok Bot (Cursor chat assistants) has no verified Mac-side skill directory; setup does not invent one. The supported Grok Bot install is an agent-created workflow from factory/skills/grok-bot.md.

The hooks activate only after setup proves the assembled local loop: passive hooks are present, the exact /a and /a. skills are safe, the cue renders both its start state and its per-session close state, and Codex is either trusted or visibly waiting for its required trust step. Skill and rule filenames are shared user space, so setup replaces one only when an exact content marker proves Alexandria owns it. A foreign collision is preserved and the host is reported incomplete; another healthy host cannot hide that failure. The uninstaller applies the same content test. If setup or an update stops halfway, the partial files remain available to inspect and repair, but every Alexandria hook stays off until a verified rerun succeeds.

How each surface is wired

One verified setup wires every surface — nothing to install per-agent, no plugin, no marketplace:

  • Claude Code: the hook entries in ~/.claude/settings.json fire the shim at session start and end.
  • Claude Desktop's code tab: that tab is Claude Code running on your machine — it reads the same ~/.claude/settings.json, so the same entries cover it automatically. The normal chat tab cannot run these local hooks. It can still use an approved writable record and load its _start guidance explicitly.
  • Cursor: 5 hook entries in ~/.cursor/hooks.json call small Python wrappers — session start/end/stop plus per-prompt and per-response transcript capture — that shell out to the same shim (or write the local staging transcript Cursor never provides natively).
  • Codex: native hooks.json, current AGENTS.md, and one start + one close skill. SessionEnd saves the transcript and a receipt inside Codex's three-second cap; the next SessionStart drains the ordinary feedback/git work. Setup stays visibly pending until trusted hooks have actually run at start and end.
  • Factory: a plain active-session droid in ~/.factory/droids/a.md. Factory has no passive lifecycle path here, so Factory alone is reported as an incomplete loop rather than a successful install.
  • Grok CLI / Grok Build: native skills under ~/.grok/skills/ and ~/.grok/hooks/alexandria.json calling the same signed shim. Grok also reads Claude and Cursor hook files by default; this install still writes Grok-native hooks so a Claude-less Grok user gets the loop, and it does not globally disable [compat.claude] hooks. If Claude or Cursor Alexandria hooks are also present, one Grok CLI session may run the shim twice.
  • Grok Bot: not a Mac install path. Public docs and this repo do not verify a user-level on-disk skill directory that Grok Bot loads. The supported install is saving factory/skills/grok-bot.md (and the close skill) into Grok Bot's own workflow library as /a and /alexandria.

Result: Claude Code, Cursor, Codex, and Grok CLI can close the full passive → cue → active loop over one signed payload and one sovereign folder. Factory can run the active part beside one of those hosts, but does not pretend to supply the passive part. Grok Bot can run the active /a loop when its computer connection can reach ~/alexandria.

Cowork and the Claude app (a file surface, not an install path)

Cowork runs your agent in a sealed environment and can only see a local folder when you attach it. Alexandria installs no Cowork plugin: a plugin duplicated the skill, could not provide a trustworthy hook path, and created a misleading extra install surface. Cowork works through the files themselves:

  1. Capture (automatic). An optional launchd agent (com.alexandria.session-capture, enabled separately) reads the transcripts Cowork writes to your disk and mirrors the dialogue into ~/alexandria/files/vault/sessions/ — no attach needed, riding the one direction the VM shares out.
  2. Awareness (one-time, additive). After the private loop works, setup guides the compact ~/alexandria/system/.account-instructions.md block below the ordinary AI's existing instructions, then offers the same block for other AIs. The block activates the passive loop and active-session nudge; the reviewed manual and personal map live in approved storage, with exact locators kept for new chats. When hooks are absent, _start loads that guidance explicitly. Actual inheritance and access are verified per surface, not assumed from an account or product name.
  3. Read/write (within approved scope). Grant the exact Alexandria folder, then ordinary work uses it and saves clear signal automatically. For deliberate work use the host's verified native Alexandria skill, or start an Alexandria session if none exists. The agent loads Foundation and relevant enabled guidance, executing explicitly when hooks are absent. If local access is unavailable, use an approved connected copy; never mix homes or call an unsaved handoff saved. Consequential ambiguity, protected-belief changes, new access, sharing, publication and destructive actions retain their separate approval gates.

Nothing here routes your files through a server; it's the same sovereign folder, reached the only way a sealed VM allows.

What is signed

A single manifest, factory/manifest.txt, lists a signed, monotonically increasing release version and the SHA-256 of every tracked file under factory/. factory/ship.sh derives that set from Git itself; there is no hand-maintained allowlist that can forget a new script, prompt, template, hook, or setup file. Only the generated manifest and its signature are excluded.

On first install, every fetch is pinned to the reviewed commit through the invite-gated source route. Setup then authenticates the manifest before fetching any factory file and refuses any file missing from the manifest or not matching its signed hash. On every later update, the already-installed verifier authenticates setup.sh before running it. The website and API are never executable update authorities.

<sha256>  factory/hooks/payload.sh
<sha256>  factory/hooks/shim.sh
<sha256>  factory/setup.sh
<sha256>  factory/canon/foundation.md
<sha256>  factory/canon/axioms.md
<sha256>  factory/canon/methodology.md
...
<sha256>  factory/skills/scheduled.md
<sha256>  factory/scripts/install.sh
<sha256>  factory/migrate.sh

The manifest is signed inside the maintainer's Mac Secure Enclave (factory/manifest.txt.sig), in the namespace alexandria with identity alexandria-payload-signing. The result is a standard SSH signature, so Authors verify it with ssh-keygen; the Apple-only signer exists only on the publishing side. Each accepted release version becomes a local floor. An older valid manifest is rejected, so rollback is shipped as a new forward-signed release rather than replaying old bytes.

The pinned-payload update model

This is the most important property to understand. The model is pinned + consent-symmetric: the shim only ever executes the payload pinned on disk, nothing self-updates, and no code runs before verification.

The shim at ~/.local/share/alexandria/hooks/shim.sh is installed by setup.sh outside the AI-writable Author folder and refreshed only by a verified, explicit update. Sessions never refetch the shim. On every session start — Claude Code and Claude Desktop's code tab reach it via the settings-hook entries; Cursor via its Python wrappers; Grok CLI via ~/.grok/hooks/alexandria.json — the shim does this:

  1. Runs only the payload pinned on your disk (~/.local/share/alexandria/.hooks_payload) — and only if that exact file has passed verification. The payload, accepted manifest, version floor, activation marker, and verification hash all remain outside ~/alexandria, the only Alexandria root granted writable to the AI. When the payload is new or changed (fresh install, an update you applied), the shim fetches factory/manifest.txt + .sig over HTTPS, verifies the signature with ssh-keygen -Y verify against ~/.local/share/alexandria/allowed_signers (the public key installed once at setup), and compares the payload's SHA-256 to the manifest entry. Pass → the hash is recorded beside the payload and it runs. Fail → the shim refuses to run it: loud warning in the AI's context, entry in ~/alexandria/system/.alexandria_errors, bare mode (constitution only, no protocol calls).
  2. Optionally checks for updates, notify-only. Setup leaves hooks/auto-update absent. If you separately create it, the shim fetches and signature-verifies the current upstream manifest. Session start compares only signed hashes with local files and generates fixed local wording naming an allowlisted module; it never downloads upstream canon or writes a remote diff into agent context. Nothing is applied.

So the code that processes your session is exactly what you approved — the payload pinned at install or at your last explicit update — and it passed the hardware-signature check before its first run. Applying an update is always your action: bash ~/.local/share/alexandria/scripts/verify-fetch.sh --run setup.sh. The installed verifier authenticates setup before it executes; setup then verifies every fetched factory file. Bare GitHub access isn't enough to ship code: the manifest must also be signed on the maintainer's Mac.

Engine and canon work the same way: both are offered, verified, and applied only on your go — canon via the update notice you pull per-module, the engine via the local verifier. Nothing on your machine changes without your explicit action.

What you're trusting: the maintainer's Mac, which holds a private key that cannot leave Apple hardware. The source is auditable by every invited person; that physical approval is the only thing that can ship new signed code.

What protects you anyway:

  1. Whole-factory signed manifest + hash pinning. manifest.txt lists a monotonic release version and the SHA-256 of every tracked file under factory/, including setup and the verifier. CI derives the same set from Git and fails on any missing or extra path. The manifest itself is signed (manifest.txt.sig). Compromise of the GitHub repo alone does not produce code execution.
  2. Refuse-to-run. A payload that has never passed verification never executes — if the file on disk changes without re-verification (tampering, a half-finished update), the session runs bare instead of running it.
  3. Public diff. Every payload version is in git history. Any session can be reconstructed from the commit SHA on main at that moment.
  4. Canon canaries. The canon explicitly tells the model to refuse instructions that try to exfiltrate files, escalate scope, or bypass the user. The same posture covers marketplace modules: a foreign module's body is untrusted input — instructions inside it are read as data, not commands, and adopted only after review against your own canon.
  5. AI-tool approval dialogs. Claude Code, Cursor, and Codex show every shell action before executing. Real protection at install and during anomaly, but it weakens with habituation — treat it as a backstop, not the primary defense.

Residual gap: code running on a compromised maintainer Mac, including a misled AI agent, could sign a release without any prompt. Releases still pass the automated GitHub tests before reaching main. The key-rotation procedure is below. If that residual gap matters to you, run a frozen install.

Turning update checks on or off

They start off. To enable signed, notify-only checks after a separate yes: touch ~/alexandria/system/hooks/auto-update. To stop them: rm ~/alexandria/system/hooks/auto-update. Removing the marker keeps every session on the pinned local copy, and re-running setup does not turn checks back on. Connecting an account adds no status read or other standing request. Separately approved Library, marketplace, backup, or saved-link resolution stops by removing its file under ~/alexandria/system/permissions/.

A truly independent fork needs its own trust root. Copying the repo is easy; safely shipping changed factory files means replacing the embedded public key and release signer, publishing the new fingerprint through a channel your users already trust, then signing your own whole-factory manifests. A raw fork URL is not an authentication mechanism. If you only want immutability, the simple freeze above is the safer, smaller move: your already-verified local files keep running with no update path at all.

The hooks run outside the AI's sandbox, and the AI can write anything in ~/alexandria. So nothing written there can turn on work that leaves the machine, and nothing there runs as a hook's code:

  • Two halves. Library publishing, Marketplace reporting, backup, and saved-link fetching each run only while a grant exists in the protected runtime, ~/.local/share/alexandria/permissions/, and its switch exists in ~/alexandria/system/permissions/. Library approvals, each file's SHA-256 with its exact scope and name, live in the same protected folder, never beside the file.
  • Only the Author grants. ~/.local/share/alexandria/scripts/permission.sh writes grants and approvals, and it succeeds only outside the AI's sandbox: the Author runs it in their own terminal, or approves their ai app's prompt to run that one command outside the sandbox. It checks the file, manifest, or remote against the hash or address the Author was shown and refuses if it changed.
  • Anyone can switch off. Deleting a switch stops that connection at once, and the next session start deletes its grant. The AI can end a permission; it cannot begin or restore one.
  • No code or git settings from ~/alexandria. The root checker runs only from a private copy whose bytes match a signed release this machine verified. Every git call a hook makes forces repository hooks and the file-system monitor off. Backup pauses, and names the setting, while the repository's own git configuration holds anything that could start a program or redirect data: a hooks path, filter or merge driver, credential helper, signing program, proxy, URL rewrite, or an ssh command other than the one recorded with the grant. It pushes only to origin by name, and only while every fetch and push address of origin equals the approved one.
  • No file becomes an instruction. The optional Cursor self-check sends one fixed sentence, switched on in the protected runtime; a hook never passes file contents to the AI as its next instruction.
  • Existing installs. The first setup run of this release carries forward, once, exactly what the previous hook would already have acted on: present switches, a backup remote that still matches, and Library approvals whose bytes still match. It then records a receipt, and nothing written in ~/alexandria afterwards becomes a grant.

Two switches stay AI-writable on purpose, because turning them on sends nothing private: system/hooks/auto-update (signed release files only) and system/hooks/visible-cue.off (which only silences). The people-context marker governs a helper the AI itself runs during a task, never a hook.

What the hooks capture — locally

The session hooks archive transcripts into ~/alexandria/files/vault/ when the host exposes them; Cursor's prompt/response hooks build a local transcript themselves. A host-supplied transcript_path is copied only when it is a regular, user-owned file under a supported host root (~/.claude/, ~/.codex/, ~/.cursor/, ~/.alexandria/transcripts/, ~/.factory/, ~/.grok/) with no symlink or path traversal. If a host supplies no transcript, the loop must say so rather than claim capture. The vault is the Author's accumulating local record, owned by them, retained until they delete it, and removable at any time. Running the scoped uninstaller disconnects every Alexandria hook while keeping the files by default; it never auto-deletes user data. --delete-files removes ~/alexandria/ only. Cursor's shared ~/.alexandria/ sidecar, iCloud capture folders, private Git remotes, Drive copies, and foreign config stay unless the Author removes them separately. A directory name cannot prove every existing file inside belongs to Alexandria. Every hook requires the post-probe .setup_complete marker. Failed core probes leave hooks off. If optional downloads fail while the core passes, the local loop stays active with the available files; setup reports an incomplete refresh, exits nonzero, and retains the prior completed-install manifest. That marker proves core readiness, not that every optional file is from one release. By default the vault is transmitted nowhere. The hooks make no standing account request; every outbound feature remains separately permissioned. People-context reads happen only in relevant ordinary work while their marker exists, never in a hook. Each connected computer has its own account key, so a later GitHub sign-in or connection on another computer does not invalidate a healthy local connection. If the Author separately enables backup, tracked vault files are pushed only to the exact private Git remote they approved; Alexandria has no access to that repo. Optional signed update checks, Library publishing, Marketplace reporting, or saved-link resolution run only while their separate permission is valid; every one of them except update checks needs the protected grant described above. Saved-link resolution sends only the exact URL or tweet ID found in the capture inbox, and stays off without its grant. While it is on, it fetches any link in that inbox, including one an AI session wrote there. The resolver still refuses private, loopback, link-local, reserved, multicast, and metadata endpoints, re-checks redirects, pins DNS, allows only https, and caps response size. Transcripts appear in none of those requests.

First-install agents classify an existing path with receipts and hashes before reading personal files. A healthy install short-circuits and is never overwritten. Partial and foreign paths fail closed. Optional connected state is disclosed and left as the Author set it. The Apple Shortcut's auditable spec lives at factory/systems/shortcut.md; the Shortcut itself is Apple-only.

Network call inventory

Every outbound call the install or hooks make. Complete list.

CallTriggerSendsReceives
GET api.alexandria-library.com/source/<invite>/…Your coding agent, once before first installyour invite codeone exact commit and the source to review
GET api.alexandria-library.com/source/<invite>/<verified-commit>/factory/…Setup, pinned to the reviewed commityour invite codesigned manifest + factory files
GET api.alexandria-library.com/source/<invite>/main/factory/{setup.sh,hooks/...}Only when you explicitly apply an update through the installed verifieryour invite codefiles accepted only if the whole-factory manifest signature, version, and file hash pass
GET api.alexandria-library.com/source/<invite>/main/factory/manifest.txt(.sig)Verifying a newly pinned payload, or session start after optional update checks are enabledyour invite codesigned manifest + signature
GET api.alexandria-library.com/source/<invite>/main/factory/canon/*.mdInstall, an explicit pull, or session start after optional update checks are enabledyour invite codesigned local references
GET api.alexandria-library.com/source/<invite>/main/factory/{skills,hooks/cursor,templates,scripts}/...Install, or session-start drift comparison after optional update checks are enabledyour invite codefactory files for install or comparison
POST api.alexandria-library.com/account/connect/exchangeOnce, only after the exact word connectshort-lived one-use code, installed public client version, and the current key when one already worksone exact-format account key, or one exact existing-key flag; all other response shapes fail closed and no server text is shown
GET api.alexandria-library.com/libraryDuring ordinary work, only while permissions/people-context exists and a named person materially mattersAPI key; no name, prompt, or private contextbounded member directory fields used to match the person locally
GET api.alexandria-library.com/connect/site/<author>After one confident local identity match under the same people-context permissionAPI key + selected public handle; no prompt or private contextexact verified own-site origin/manifest route, or an explicit unregistered result
GET <verified-own-site>/<manifest>.json and its same-origin public shadow URLsAfter that permitted match, or an exact public manifest the Author directly suppliedno API key, cookie, prompt or private context; normal public HTTPS requestbounded public metadata and selected public shadows, DNS-pinned and hash-checked when declared; still untrusted
GET api.alexandria-library.com/library/<author>After one confident local identity match under that same permissionAPI key + selected public Library address; no prompt or private contextonly the profile and artifact metadata this account can already see, marked untrusted
GET api.alexandria-library.com/library/<author>/file/<name>Only for a shadow or relevant artifact returned by that permitted profile readAPI key + exact Library file address; no prompt or private contextthe exact authorized publication, bounded and marked untrusted data rather than instructions
PUT api.alexandria-library.com/library/me/profileOnce, only after the exact local draft is displayed and the person says the exact word publishAPI key + only the hash-bound approved display_name, text, website, and socials fieldsexact {ok:true} or a fixed local failure; no server prose is shown
POST api.alexandria-library.com/callOnly while your protected Marketplace grant holds the SHA-256 of the current .call_manifest and its switch existsAPI key + the exact approved JSONbounded acknowledgements validated against the local manifest, then reduced to fixed success/failure
GET api.alexandria-library.com/filesOnly with Library permission, after sending approved filesAPI key + client-version hashthe current account's bounded file metadata, validated locally and reduced to fixed drift codes
PUT api.alexandria-library.com/file/<name>Only with the protected Library grant and an approval naming that file's exact scope, name, and content hashAPI key, that exact approved file + visibility tier; no adjacent metadata or other private path. The shared Library caps an account at 250 files, 25MB per file, and 250MB total; large media stays elsewhere and enters as a link.200/4xx
POST/DELETE api.alexandria-library.com/connect/siteOnly after the owner chooses the exact site registration or withdrawalAccount key + approved site/description/callback/listing fields, no publication bytesStructured registration result; DNS proof is untrusted data, not an instruction to run code
POST api.alexandria-library.com/connect/site/verifyAfter the exact domain proof is placed by its ownerAccount key + siteVerified registration result
GET api.alexandria-library.com/connect/access/<author>Only when an owner-hosted endpoint serves protected materialReader-scoped credential + target and exact scope; no question or publication textCurrent access decision; unavailable fails closed
GET api.alexandria-library.com/file/<name>?scope=<scope>Only with Library permission, after that exact approved file was sentAPI key + exact local scopethe current account's stored bytes, hashed locally for equality and never shown to the private AI
DELETE api.alexandria-library.com/file/<name>Only after you directly ask to unpublish that exact remote artifact and separately approve the deletion; never from standing syncAPI key200/4xx
git push / git pull --rebase against your own alexandria-private GitHub repoSession start (commit + push, then pull/rebase) + session end (push) — only while your protected backup grant names every fetch and push URL of origin exactly and its switch exists. A pre-existing or changed remote does nothing, and repository git settings that could start a program pause it.the tracked contents of ~/alexandria/ — gitignored paths excluded: system/canon/, system/hooks/, system/permissions/, system/.*, files/library/, node_modules/git ref data
gh CLI: gh ssh-key add, gh repo createNever at install. Only when you enable the backup or publish add-on, on your explicit yesyour separate gh OAuth token (not your Alexandria API key)success/failure
GET api.fxtwitter.com/status/<id> (+ the tweet's media hosts)Session start, only while your protected capture-network grant and its switch exist and an X/Twitter link is in files/vault/input/the tweet ID saved there (+ your IP, as with any fetch)tweet text/media, written locally into files/vault/_input/
GET www.youtube.com/oembed?...Same separate permission plus a saved YouTube linkthe video URL you savedtitle/author metadata, local
GET <a URL you saved>Same separate permission plus a saved link/.url dropthe exact URL you saved (+ IP)page title/content, written locally for your review

Every authenticated call also carries an X-Alexandria-Client header — a client version hash, so a broken client build can be spotted server-side; it identifies the software version, not you (your account is already on the request).

That is all. No telemetry pings, install reports, automatic feedback, error reporters, analytics SDKs, account-status reads, or session-start Library imports. General public pages stay in the browser or a genuinely isolated reader. The one narrow exception is the permissioned named-person flow above: it sends no private query, keeps no cache, and returned text may shape only the answer shown to you, never a tool action. Server text does not enter through connection or session start. The saved-link rows require both a separate permission file and a link you deliberately dropped into your own capture inbox; everything they fetch lands on your disk, not ours. You can confirm the full surface by grep -E 'curl|wget|http' ~/.local/share/alexandria/.hooks_payload, ~/.local/share/alexandria/scripts/person-context.mjs, and ~/.local/share/alexandria/scripts/capture_resolver.py. Capture extraction itself is local: /a freezes the exact starting batch, opens the foreground immediately, and proves that batch in the background without confusing later arrivals for unfinished work.

What our server holds

Cloudflare Worker, stateless re: your private content. KV + D1 + R2.

StoredWhereWhy
Email + GitHub login + Stripe customer ID, in one encrypted account blob. Between GitHub sign-in and joining it can also hold the hash of the invite code your browser used, removed once the join is countedKV (AES-256-GCM at rest)Account, OAuth, billing
The email you give on /start, the route you chose, an unsubscribe token, and the hash of the invite code it came withD1 (waitlist)Your setup email and occasional notes; counting emails per invite code
Per invite code, as its hash: when the source was first read with it, and how many people it brought have joinedD1 (invite_funnel)Seeing where invited people stop, with nothing about what they read or who read it
API key — SHA-256 hash onlyKVAuth check
Account connection code — SHA-256 hash, account pointer, and expiry (one hour or first use)D1One explicit connection exchange without exposing a persistent key in browser HTML or email
Event log: endpoints you deliberately use, with timestamps and lightweight request contextKV (60-day TTL)Debugging, abuse signal
Library files you explicitly publishR2Published Library content
Library file metadata (name, exact scope, visibility, content hash, updated_at)D1Permissioned discovery and listing
Marketplace calls you separately approve: module ID, account ID, timestamp, and exact optional notes/requests in the approved manifestD1 (protocol_calls)Marketplace listing and request board

Not stored anywhere we control: your constitution, vault, marginalia, transcripts, machine.md, notepad, raw API key, AI-vendor (Anthropic/OpenAI/etc) API keys, or any file outside your approved files/library/ publication mappings — the only path the session sync ever PUTs. A context PLM receives only the exact published scopes allowed for that reader, plus the active artifact and current conversation. Its adapter lives in an environment you choose and, to meet Alexandria's contract, has no Author filesystem, hidden memory, live web, or Alexandria credential; it accepts Author context only from the Worker's bearer-authenticated request. There is no endpoint that accepts private-source files.

What a complete server breach yields: account emails, setup emails with the hash of the invite code each came with, per-code first-read times and join counts, GitHub user IDs, hashed (un-reversible) API keys, the 60-day event log, your full protocol_calls history (the per-module portion is already exposed by design via the authed marketplace endpoint), published Library content (files you explicitly published), and Cloudflare-level access logs (IPs, timing). It does not yield private cognition, unpublished files, or AI-vendor credentials, because those never reach the server.

Why your API key is safe

  • Stored server-side as SHA-256 hash. Never the raw key.
  • Account blob in KV encrypted at rest with AES-256-GCM.
  • The raw key appears once on the OAuth callback page in your browser. Never in email, never in any third-party metadata.
  • Stripe identifies your account by GitHub login, not API key.
  • DELETE /account with your key cancels any Stripe subscription and removes your account, module-call records, Library activity, and published files. Endpoint events expire on their 60-day TTL.

What this defends against

ThreatMitigation
Impersonating site or source supplies different codeThe official paste names the exact invite-gated source on Alexandria's API domain and tells the user's already-running agent to evaluate the project rather than obey it. Setup stays pinned to one reviewed commit, and every file must match the signed manifest. A compromise of Alexandria's server or GitHub account could still serve a different first-install key, so strict protection requires confirming the fingerprint through another trusted channel.
Server or GitHub account compromise after installationThe installed verifier retains the already-accepted release key. An attacker cannot produce a valid newer manifest signature, so updates are refused.
Selectively tampered single file (including setup.sh or the verifier itself)Manifest covers the entire tracked factory; any change breaks the signed hash and is refused.
A prompt or repository edits the Author-writable Alexandria folderAutomatic hook programs, the signing key, accepted manifest, version floor, activation marker, connection grants, and Library approvals live at ~/.local/share/alexandria/, outside the writable root granted to the AI. A switch in ~/alexandria can only turn a connection off. The next hook does not execute a file from ~/alexandria, runs the root checker only from a verified copy of signed bytes, forces repository git hooks and the file-system monitor off, and pauses backup on any repository git setting that could start a program or redirect data.
Man-in-the-middle on the source routeSignature verification on top of HTTPS catches forged content.
Replay of an old but valid signed releaseThe signed release version can only move forward; each machine stores the highest authenticated version and rejects anything lower.

What this does NOT defend against

Residual riskWhy it's accepted at current stage
Maintainer's Mac compromisedThe private keys still cannot be exported, so an attacker must act from that Mac. Code running there as the maintainer, including a misled AI agent, could sign a release with the Mac key without any prompt. Accepted deliberately (2026-09-25): a fingerprint prompt did not stop that in practice, because routine releases get approved without reading every line. Releases still pass the automated GitHub tests before reaching main.
Maintainer's Mac is lostThe keys are deliberately not recoverable. A new key must be accepted through the independent first-install process; it cannot be silently rotated by the old software. Availability is traded for a hard no-backup signing boundary.
Maintainer ships malicious code intentionallyAnyone with an invite can read every line before anything runs, and every release is signed with a hardware key on one Mac. Reputational + legal alignment is the structural deterrent — same as every CLI tool maintainer.
Alexandria's server is compromisedIt can reject an outward action, lie through a fixed success/failure status, misbind or disable an account key, mishandle bytes an Author chose to publish, or return false or hostile Library context. The connector and session-start path still accept no server prose. The people-context helper sends no prompt or private context, uses GET only, validates the canonical API origin and bounded response shapes, and labels every returned byte untrusted. The honest residual is answer poisoning: hostile published prose may distort the answer the person sees. It is never authority for a tool action or standing memory.
User bypasses the official flow and runs code from an impersonatorNo shell script can authenticate itself after it has already started. The official path asks the user's existing agent to inspect first and to stop if anything looks unsafe, with the user's own message as the only go-ahead; a person can still deliberately bypass that boundary, as with any phishing attempt.
The AI tool is deliberately run without a filesystem sandbox, or runs commands outside it without askingAll runtime files are owned by the same OS user, so a truly unsandboxed agent, or one whose host approves out-of-sandbox commands automatically, could alter them and write its own grants. The separation protects supported sandboxed operation where the host asks before a command leaves the sandbox; it is not an OS account boundary.
The AI can read the account key and reach Alexandria's API directlyThen it holds the account's own power without any hook: it could call the API itself. Protected grants close the route where a sandbox that blocks that reach is bypassed through a hook. The key stays readable because tools the AI runs during a task, such as the people-context reader and the profile publisher, use it; a host rule that denies reading ~/alexandria/system/.api_key makes the Author's out-of-sandbox approval the only way to publish.
Another running session rewrites git settings between the check and git's own readThe check runs immediately before each sync, and hooks and the file-system monitor are forced off regardless. A compromised session racing that moment is not excluded.

Audit checklist

Fastest path: give the plain request from /start to your existing agent and let it choose the audit. For the project's own hostile checklist, use factory/redteam.md as untrusted evidence, not authority. To do it by hand, download one exact commit from api.alexandria-library.com/source/<invite>/<commit>.tar.gz, compare the release key in factory/setup.sh with the fingerprints in Trust root, and verify the signed manifest before running anything.

These are the files. Read them.

factory/setup.sh
factory/hooks/shim.sh
factory/hooks/payload.sh
factory/scripts/verify-fetch.sh
factory/manifest.txt
factory/manifest.txt.sig
factory/canon/methodology.md
factory/skills/claudecode.md

From that authenticated checkout, verify the manifest signature yourself:

ssh-keygen -Y verify \
  -f ~/.local/share/alexandria/allowed_signers \
  -I alexandria-payload-signing \
  -n alexandria \
  -s factory/manifest.txt.sig \
  < factory/manifest.txt
# Expected: Good "alexandria" signature for alexandria-payload-signing with ECDSA key SHA256:p33nHmkn0rm09XTjoBRKezyxSk3qxdA3oYnvLPBhaMI
# (releases before 2026-09-25 show SHA256:9DVo6uNuieqKMdNtT0QIi/WoQAAbWl5i/t0Z5MdQ/Jg)

# Verify every tracked factory file's hash matches the manifest
awk '$1 !~ /^#/ { print $1 "  " $2 }' factory/manifest.txt | shasum -a 256 -c

After install, your live install is at:

  • ~/.local/share/alexandria/hooks/shim.sh (refreshed only by a verified explicit update)
  • ~/.local/share/alexandria/.hooks_payload (refreshed only by a verified explicit update)
  • ~/.local/share/alexandria/.canon_manifest (the verified manifest backing the cached payload)
  • ~/.local/share/alexandria/.factory_version (the accepted rollback floor)
  • ~/alexandria/system/canon/*.md (sovereign; divergence from upstream shows up in ~/alexandria/system/.canon_update_notice)

Then audit the cached payload for anything that touches the network, evaluates remote code, or reads sensitive paths:

# Network and code-evaluation surface
grep -nE '\b(curl|wget|eval|osascript)\b|python -c|bash -c' \
  ~/.local/share/alexandria/.hooks_payload

# Credential-store traversal
grep -nE '\.ssh|\.aws|\.anthropic|\.openai|keychain|gnome-keyring' \
  ~/.local/share/alexandria/.hooks_payload

The first should match only the curl calls in the network inventory above. The second should return zero matches. (The same checks against factory/setup.sh will surface a few additional curls and gh calls for the install-time GitHub fork setup, all listed in the install table.)

Uninstall

To hide only the /a cue and leave the loop running:

touch ~/alexandria/system/hooks/visible-cue.off

One scoped remover reverses every hook, instruction block, writable-root entry, skill, and optional background job that Alexandria owns. It checks generic names such as a and a. before removing them, so a pre-existing skill is left alone. By default it disconnects the loop and does not delete user data. Left in place: ~/alexandria/ (files, permission markers, local git), ~/.alexandria/ (Cursor sidecar), any iCloud capture folder, any private Git remote or Drive copy, and every foreign skill or hook. The Apple Shortcut's action list is documented at factory/systems/shortcut.md.

python3 ~/.local/share/alexandria/scripts/uninstall.py

Cursor's shared ~/.alexandria/ sidecar is also preserved. Alexandria uses parts of it for local transcript staging, but the directory name alone cannot prove every file inside belongs to Alexandria, so the uninstaller never removes the whole directory.

To remove the local files too, use the explicit destructive form. It refuses if ~/alexandria is a symlink and never deletes a remote backup:

python3 ~/.local/share/alexandria/scripts/uninstall.py --delete-files

Deleting an Alexandria account is separate because it changes server-side state:


# Revoke server-side (removes the account record, endpoint events, marketplace
# calls, published files, and any Stripe subscription; messages you separately
# chose to send Alexandria are correspondence and are not part of the local loop)
curl -X DELETE -H "Authorization: Bearer $YOUR_KEY" https://api.alexandria-library.com/account

Key rotation

If the Secure Enclave key is invalidated, unavailable, or suspected compromised, the maintainer will:

  1. Generate a new key inside a clean Mac's Secure Enclave.
  2. Replace the public key embedded in factory/setup.sh through the repository's admin path. This is a visible trust-root recovery, not an ordinary release.
  3. Sign the first factory manifest under the new root with the new key.
  4. Announce the rotation independently on the project website and in the repo.
  5. Existing users repeat the independent /start verification flow and explicitly accept the announced new fingerprint. The old local verifier cannot silently grant trust to a replacement key.

This is intentionally manual: a replacement key after a compromise must be accepted independently. Adding a key while the current one is still trusted is different. On 2026-09-25 a release signed by the Touch ID key added the Mac key, so installs that apply that update trust both. Applying it is the Author's own explicit update, as always. Installs that have not applied it keep running their pinned version; to update later they re-run setup once. The earlier rotation, from an Ed25519 key to the Touch ID key, happened in August 2026; installs trusting that Ed25519 fingerprint must also re-run setup once.

How to think about this

The trust here is legible, not zero. It is bounded-trust:

  • The full source is readable with an invite; every payload change is in git history.
  • The signing key is non-exportable Apple hardware. Anyone with the source or GitHub account cannot ship factory code; a release also has to be signed on the maintainer's Mac. That is a real concentration of trust; we are not pretending otherwise. The rotation procedure is above.
  • You can freeze forever on your verified local copy. A modified fork must establish and publish its own signing root rather than inheriting ours.
  • You can re-audit at any time. diff your cached payload against the same file in the invite source, and verify the manifest signature with ssh-keygen -Y verify — both shown above.

What we are claiming is not "no trust required." We are claiming you can read every line of the trust you are extending, change the relationship anytime, and walk away cleanly with all your files intact.

Reporting issues

Suspected key compromise, signature anomalies, or trust-model questions: email benmowinckel@gmail.com.

your own system, in one sitting.

Paste one message into the superintelligence you use on your computer. It keeps what already works for you and builds what’s missing, in files you own, for free.

let me try