lwid / docs
Home GitHub

How lwid works

An encrypted, zero-knowledge platform for sharing small web apps.

All your data is encrypted and decrypted directly in your browser before anything leaves your machine. The server never sees your files, your keys, or your filenames — only encrypted gibberish blobs.

Security model

End-to-end encryption

Every file is encrypted with AES-256-GCM in your browser before it leaves your machine. The server only ever receives and stores opaque ciphertext blobs.

Zero-knowledge server

The server never sees your content, your keys, or your filenames. It stores content-addressed blobs identified by their IPFS CIDv1 hash — nothing more.

Keys live in the URL fragment

The decryption key is encoded in the #fragment part of the URL. Browsers never send the fragment to the server — it stays entirely client-side.

Quotas

Limits per account tier. Sign in to unlock higher limits.

Limit Anonymous
Loading…

Usage

Web UI

  1. Go to lookwhatidid.xyz.
  2. Drop your project folder (must contain an index.html).
  3. Click Create & Share.
  4. You'll be redirected to your project's URL with both keys in the fragment.
  5. Share the view-only link (read key only) or the edit link (both keys).

CLI

Install the lwid CLI:

macOS / Linux:

Windows (PowerShell):

First push (new project)

This generates keys, creates the project, encrypts and uploads all files, and prints the shareable URL. A .lwid.json config file is saved in the directory.

Important: Add .lwid.json to your .gitignore immediately — it contains your encryption and signing keys.

Update an existing project

lwid push

Reads config from .lwid.json in the current directory.

Pull a project

lwid pull --dir .

Project info

lwid info

Prints project ID, server URL, edit URL, and view-only URL.

AI agent integration

Any coding agent that supports skill files can publish to lwid automatically. Point your agent at the skill URL:

https://lookwhatidid.xyz/SKILL.md

The skill instructs the agent to install the CLI, run lwid push, and return the shareable URL. No manual steps required.

Architecture

  You (browser / CLI)                           Server
  ┌──────────────────────┐                ┌──────────────────┐
  │                      │                │                  │
  │  1. Generate keys    │                │  Stores only:    │
  │     - AES-256-GCM    │   encrypted    │  - CID → blob    │
  │     - Ed25519 seed   │──── blobs ────▶│  - project → CID │
  │                      │                │                  │
  │  2. Encrypt files    │                │  Never sees:     │
  │  3. Compute CID      │                │  - plaintext     │
  │  4. Upload blobs     │                │  - keys          │
  │  5. Build manifest   │                │  - filenames     │
  │  6. Sign & upload    │                │                  │
  │                      │                └──────────────────┘
  └──────────────────────┘

  URL: /p/{project-id-OA4cCJ3}#{read-key}:{write-key}
       └─── sent to server ──┘└───── never sent ────┘
Encryption & keys

When you create a project, two keys are generated client-side:

  • Read key (32 bytes) — AES-256-GCM symmetric key used to encrypt and decrypt all file content.
  • Write key (32 bytes) — Ed25519 seed used to derive a signing keypair. The server stores only the public key and verifies signatures on manifest updates.

Both keys are encoded as base64url (no padding) and placed in the URL fragment: #readkey:writekey. A view-only URL omits the write key: #readkey.

Content-addressed storage

Each encrypted blob is hashed with SHA2-256 and stored under its IPFS CIDv1 (multicodec raw, multibase base32lower). This means:

  • Identical content is stored once (deduplication).
  • Integrity is verifiable by recomputing the hash.
  • The server cannot tamper with content without detection.
Manifests & versioning

A manifest is a JSON document listing all files in a version: path, CID, and size for each entry. The manifest itself is encrypted, uploaded as a blob, and its CID becomes the project's root.

Each manifest points to its predecessor via a parent CID, forming a linked version chain. Updating the root requires a valid Ed25519 signature from the write key.

Service Worker sandbox

In the browser, files are decrypted in the main thread and passed to a Service Worker via postMessage. The SW intercepts fetch requests under /sandbox/ and serves the decrypted files from memory, so the project renders in a sandboxed <iframe> without any plaintext hitting the network.

URL scheme

TypeFormatWho can…
View /p/{project-id}#{read-key} Decrypt and view the project
Edit /p/{project-id}#{read-key}:{write-key} View + push new versions

Keys are base64url-encoded (no padding). The fragment (#...) is never sent to the server by the browser.

Source code

lwid is open source. The Rust workspace has three crates:

CratePurpose
lwid-commonShared types, AES-256-GCM crypto, Ed25519 auth, CID utilities, blob/project stores
lwid-serverAxum HTTP server, API endpoints, static file serving
lwid-cliCLI binary — push, pull, info commands

View on GitHub