A private, encrypted AI chat application running entirely on Val Town. Your conversations are encrypted client-side before being stored, and your password never leaves your device.
Your password is never sent to the server. Encryption happens entirely in your browser.
When you first run your forked val, check the console logs. You'll see a message like:
ā ļø STORAGE_API_KEY not set! Auto-generated key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
ā ļø Save this key to your STORAGE_API_KEY environment variable!
Important: Save this API key! It protects your storage endpoint.
STORAGE_API_KEYIn lib/api.ts, update line 3 with your storage val URL:
const STORAGE_URL = "https://your-username--your-storage-val-id.web.val.run";
You can find this URL from your forked storage val.
Visit your main val's URL and start chatting! Create your first encrypted chat with a strong password.
ā SQL Injection Prevention - All database queries use parameterized statements ā API Authentication - Storage endpoint requires API key ā Client-side Encryption - AES-256-GCM with PBKDF2 key derivation ā Password Protection - Each chat requires password to unlock
Your Val Town SQLite database stores:
Without your password, the encrypted data is unreadable.
| Variable | Required | Description |
|---|---|---|
STORAGE_API_KEY | Yes | Protects your storage API from unauthorized access |
FRONTEND_URL | No | Optional CORS restriction (e.g., https://yourapp.val.run) |
āāāāāāāāāāāāāāāāāāā
ā Browser ā
ā (React App) ā
ā ā
ā ⢠WebLLM AI ā
ā ⢠Encryption ā
ā ⢠UI ā
āāāāāāāāāā¬āāāāāāāāā
ā
ā HTTPS + API Key
ā
āāāāāāāāāā¼āāāāāāāāā
ā Val Town ā
ā Storage API ā
ā ā
ā ⢠SQLite DB ā
ā ⢠Auth Check ā
āāāāāāāāāāāāāāāāāāā
āāā main.ts # Entry point, serves HTML
āāā App.tsx # Main React component
āāā api/
ā āāā storage.ts # Storage API with authentication
āāā lib/
ā āāā api.ts # Client-side API calls
ā āāā crypto.ts # Encryption/decryption logic
āāā hooks/
ā āāā useEncryption.ts # Encryption state management
ā āāā useWebLLM.ts # AI model integration
āāā screens/
ā āāā HomeScreen.tsx # Chat list
ā āāā UnlockScreen.tsx # Password entry
ā āāā NewChatScreen.tsx # Create new chat
ā āāā ChatScreen.tsx # Chat interface
āāā components/
āāā MessageBubble.tsx # Message display
āāā StatusBadge.tsx # AI status indicator
āāā EmptyState.tsx # Empty state UI
Use strong, unique passwords for each chat. Since encryption happens client-side, your password is the only thing protecting your data.
There is no password recovery. If you forget your password, your chat data is permanently inaccessible. This is by design - we don't have access to your passwords.
Since this is self-hosted, you're responsible for backups. Val Town SQLite data persists, but you may want to:
Problem: API calls return 401 Unauthorized
Solution:
STORAGE_API_KEY is set in environment variablesProblem: Can't unlock a chat
Solution:
Problem: No chats appear on home screen
Solution:
STORAGE_URL in lib/api.ts points to your storage valProblem: WebLLM status shows error
Solution:
For stronger encryption, increase iterations in lib/crypto.ts (line 25):
iterations: 600000, // Increased from 100,000
Trade-off: Higher security, slower encryption/decryption.
To only allow requests from your frontend:
FRONTEND_URL environment variablehttps://your-main-val.val.runThis prevents other websites from calling your API (browser-level protection).
Edit hooks/useWebLLM.ts to use a different WebLLM-supported model. See WebLLM documentation for available models.
None. This app doesn't collect, track, or transmit any data beyond what's necessary for functionality:
Only you. When you fork this val:
No one else (including the original author) can access your chats.
Found a bug or want to improve the code? Feel free to:
This is open source - make it your own.
While this app implements strong encryption and security practices, please note:
For maximum security:
STORAGE_API_KEYBuilt with:
MIT License - Feel free to fork, remix, and make it your own!
Remember: Your password is your key. Keep it safe, keep it secret, keep it strong.