Architecture

Tauri v2 desktop app. All crypto runs in Rust — no secrets touch JavaScript.

System Overview

Cargo.toml (workspace)
├── crates/core/     ← shared Rust library
│   ├── crypto       AES-256-GCM + Argon2id
│   ├── scanner      3-layer Surgical Butler
│   ├── vault        zip + SHA-256 hashing
│   ├── recovery     BIP39 mnemonic
│   ├── meta         project + config management
│   ├── supabase     HTTP push/pull
│   ├── file_sync    .envbutler file export/import + folder sync
│   ├── team         invite token generation/parsing
│   └── ci_token     CI/CD service tokens
├── crates/cli/      ← terminal binary (clap)
└── src-tauri/       ← desktop app (Tauri → core)

┌─────────────────┐  ┌──────────────┐
│   Desktop GUI   │  │  CLI Binary  │
│  React + Tauri  │  │    clap      │
└────────┬────────┘  └──────┬───────┘
         │ invoke()         │ direct call
         └────────┬─────────┘
          ┌───────▼───────┐
          │  env-butler   │
          │    -core      │
          └───┬───┬───┬───┘
              │   │   │
     ┌────────┘   │   └────────┐
     ▼            ▼            ▼
 Supabase    Cloud Folder   .envbutler
 (HTTPS)   (Drive/iCloud)    (file)

Rust Modules

crypto

AES-256-GCM encryption + Argon2id key derivation. All encryption/decryption happens here.

scanner

3-layer Surgical Butler — allowlist, content fingerprint, and push preview.

vault

Zips .env files into an archive, computes SHA-256 hash for conflict detection.

recovery

BIP39 mnemonic generation and Master Key derivation from 24-word phrase.

meta

Project and config management — projects.json and config.json in ~/.env-butler/.

supabase

HTTP client (reqwest + TLS) for uploading/downloading encrypted blobs.

file_sync

Export/import .envbutler files + folder-based sync (Google Drive, iCloud, Dropbox).

team

Invite token generation and parsing for team vault sharing.

ci_token

Service tokens for non-interactive CI/CD pulls via ENVBUTLER_TOKEN env var.

Push Flow

  1. Scan — Scanner finds .env* files using allowlist, blocks SSH keys / certificates / binaries / files > 50KB
  2. Preview — Non-skippable modal shows every file, variable count, and sensitive key warnings
  3. Package — Vault zips all allowed files and computes SHA-256 hash
  4. Encrypt — Crypto module derives a key from your Master Key via Argon2id, encrypts the zip with AES-256-GCM
  5. Upload — Supabase module upserts the encrypted blob + hash to your vault table

Pull Flow

  1. Fetch — Downloads encrypted blob + remote hash from Supabase
  2. Compare — Computes local hash and compares with remote to detect conflicts
  3. Resolve — Four states: InSync, SafePull, PushReminder, Conflict
  4. Diff — On conflict: decrypts remote, parses both sides, shows variable-level masked diff
  5. Write — User approves → files written to project directory

Tech Stack

LayerTechnology
Desktop appTauri v2 + Rust
CLIRust + Clap
FrontendReact + TypeScript + Tailwind CSS
EncryptionAES-256-GCM + Argon2id
RecoveryBIP39 (tiny-bip39)
StorageSupabase / Google Drive / iCloud / Dropbox
CI/CDGitHub Actions + service tokens

Supabase Schema

vault (
  id             UUID PRIMARY KEY
  project_slug   TEXT UNIQUE NOT NULL
  encrypted_blob TEXT NOT NULL       -- base64-encoded encrypted zip
  plaintext_hash TEXT NOT NULL       -- SHA-256 of unencrypted zip
  metadata       JSONB               -- reserved for future use
  created_at     TIMESTAMPTZ
  updated_at     TIMESTAMPTZ         -- auto-updated via trigger
)

Row Level Security is enabled. The anon role is denied all access — only requests authenticated with the Service Role Key can read/write vault data. Safe for self-hosted single-user deployments.