Around me, a bunch of non-technical colleagues have been vibecoding dashboards. Small static HTML apps — a bit of JavaScript, some charts, maybe a table pulling from a CSV. They know exactly how they want their data to look, and AI agents are surprisingly good at building exactly that.
But they all hit the same wall: how do you share it?
The options aren’t great. Email the HTML file? Fragile, can’t update it. Push to GitHub Pages? Requires a GitHub account and some git literacy. Spin up a container or a VPS? Massively overkill for a 200-line HTML file. Upload to Netlify? Yet another account, yet another dashboard to manage.
I wanted something simpler. Give it to the agent, get a URL back, share that URL with your colleagues. That’s it.
So I built lwid (https://lookwhatidid.xyz).

What it is
Think plik but for static sites instead of files. You push a directory, you get a URL. Anyone with the URL can view it. You can update it. It expires in 7 days by default.
The twist: everything is encrypted client-side before it ever leaves your machine.
Why encryption matters here
Vibecoded dashboards often contain sensitive data. Sales numbers, internal metrics, customer lists — the kind of stuff you wouldn’t want sitting in plaintext on a random server.
Most hosting services store your files in the clear. That’s fine for a public portfolio, but not great for internal tooling. With lwid, the server is just a dumb blob store. It never sees your content.
Here’s how it works:
- Your files are encrypted with AES-256-GCM in the browser (or CLI) before upload
- The server stores opaque, content-addressed blobs — it has no idea what it’s hosting
- The decryption key lives in the URL fragment (
#key), which browsers never send to the server - Write access is gated by an Ed25519 signature, so the server can verify authorship without knowing the content
The URL looks like this:
https://lookwhatidid.xyz/p/{project-id}#{read-key}:{write-key}
On first load, the write key is automatically saved to localStorage and stripped from the URL — so you can’t accidentally leak write access by sharing your address bar. The share button defaults to a read-only URL, but can optionally include the write key if you want to collaborate.
Agentic first
The whole thing is designed to be driven by an AI agent. There’s a SKILL.md — a plain-text file that tells the agent exactly what lwid is, how to install it, and how to use it. Give the skill to your agent and it handles the rest: encrypt, upload, return a URL.
# The agent does this: lwid push --server https://lookwhatidid.xyz # → https://lookwhatidid.xyz/p/abc123#readkey:writekey
No account creation, no OAuth flow, no config files to explain.
Stateful webapps
Static doesn’t have to mean stateless. lwid ships a JS library that exposes a key-value store and a blob store backed by encrypted S3 objects. Your vibecoded app can persist data across sessions — still zero-knowledge, still no plaintext on the server.
import { kv } from "https://lookwhatidid.xyz/sdk.js";
await kv.set("last_run", new Date().toISOString());
const last = await kv.get("last_run");
Under the hood
The backend is a small Rust server (Axum) fronting S3-compatible storage. The shell SPA is vanilla JS — no framework. A Service Worker intercepts navigation and decrypts content on the fly inside a sandboxed iframe, which means the decryption key never touches the server even during rendering.
The CLI is also Rust, distributed as a single static binary.
lwid-common/ Crypto primitives (AES-256-GCM, Ed25519), CID utilities
lwid-server/ Axum HTTP server, blob storage, shell SPA
lwid-cli/ CLI binary — push, pull, clone, kv, blob
Try it
- Live: lookwhatidid.xyz
- Skill: lookwhatidid.xyz/SKILL.md
- Source: github.com/Marlinski/lwid
Install the CLI:
curl -fsSL https://raw.githubusercontent.com/Marlinski/lwid/main/install.sh | sh
Or just hand the skill URL to your agent and let it figure out the rest.