UnENVerse architecture
One encrypted vault, one Rust engine, three front ends. This page names the parts, shows how a request moves through them, and explains where Rust ends and TypeScript begins.
The shape of it
The Rust workspace
Five crates make up the product. The workspace denies warnings for its own crates, and clippy's defect groups run in CI.
| Crate | Role |
|---|---|
vault-core | Storage on SQLCipher, key derivation with Argon2id, cryptography, permissions and roles, the hash-chained audit log, config history, node protocol, importers, the update check. |
unv-app | The application layer. Every operation (resolve a reference, render a config, rotate, restore) is written once here and reached by all three front ends. It holds the single write point, Access::save, which also enforces --dry-run. |
unv-cli | The unv command line and the node agent. A thin layer over unv-app that adds argument parsing, JSON output and stable exit codes. |
unv-server | The optional server: HTTP and TLS API for teams, sessions and tokens, and the hub that nodes poll. |
src-tauri (package unenverse) | The desktop shell: Tauri 2 commands that expose unv-app to the interface over IPC. |
Where Rust ends and TypeScript begins
- Rust owns every rule. Encryption, permission checks, reference resolution, rendering and persistence are Rust. A secret value is decrypted in Rust and reaches the interface only when a command asks for it.
- TypeScript owns the screen. The interface in
src/tsis plain TypeScript with no framework:render.tsdraws the cards and the sidebar,modals.tsthe forms,vault.tsthe start-up and event wiring,state.tsthe in-memory state and settings, andtools.tswith its siblings the tool panes. - Markup is escaped by construction. HTML reaches the page only through an escaping template tag, because vault data is untrusted input.
- Parity is tested. Where logic has to exist on both sides (the environment-variable name template, for example) one golden fixture is asserted from Rust and from TypeScript, so the two cannot drift.
- The CLI can do what the app does. Capability parity is a rule, with the few exemptions written down in
capabilities.json.
How a request flows
- A front end (the desktop window, the CLI or a server route) receives an action.
unv-appresolves${refs}, checks permissions and takes the single write point.vault-corereads and writes the SQLCipher database. The key comes from the master password through Argon2id and lives only in memory while the vault is unlocked.- Output goes through a resolver chosen for the purpose: redacting for display, and materialising only for
exec,render,--revealand--out.
The data model, drawn from the source
This diagram is generated from src/ts/types.ts with TsUML2, a TypeScript to UML tool that runs offline. Regenerate it with node scripts/gen-uml.mjs. Open the diagram on its own to zoom in.
Who acts on the vault
| Actor | What it can do |
|---|---|
| Owner | Everything: read, write, manage users, back up and restore. |
| Named user | Only what its class and permission rules allow, on unv-server. Failed logins are rate limited. |
| API token | A credential for scripts and AI agents with the same scoped permissions as its user. Output is redacted unless a materialising command is used. |
| Node agent | Watches a config file, reports drift and writes only what its own configuration allows. Requests are signed. |
| Recovery destination | Receives encrypted recovery packages (a folder, a NAS or SFTP with a pinned host key). |
| Release pipeline | Builds, signs with Sigstore, attests and publishes release files from a tagged commit. |
How it is verified
- Rust unit, integration and end-to-end tests, with nightly coverage reported to Codecov.
- Vitest for the interface and Playwright for layout in a real browser.
- Fuzz targets for the importers and migrators.
- CodeQL,
cargo-denyand OSV for dependencies and code, and an OpenSSF Scorecard.
Read further
- The documentation book, including the architecture decision records that give the reasons for each choice.
- The generated Rust and TypeScript API references.
- Why Rust, SQLCipher and Argon2id.
- The threat model.