• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
Prada

Prada

Locals-AI

Public
Like
Locals-AI
Home
Code
14
.claude
1
api
1
components
3
hooks
2
lib
2
screens
5
.vtignore
AGENTS.md
App.tsx
README.md
deno.json
H
main.ts
tailwind.config.js
types.ts
Branches
5
Pull requests
Remixes
History
Environment variables
1
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
Code
/
Search
README.md

Locals AI πŸ€–

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.

Features

  • πŸ”’ Client-side encryption - All chats encrypted with AES-256-GCM before storage
  • πŸ”‘ Password-protected - Each chat requires a password to unlock
  • πŸ’Ύ Self-hosted on Val Town - Your data stays in your own Val Town SQLite database
  • 🚫 No tracking - No analytics, no third parties
  • 🧠 Local AI - Uses WebLLM to run AI models directly in your browser
  • 🍴 Fork-friendly - Easy to remix and run your own instance

How It Works

  1. Create a chat with a password
  2. Your messages are encrypted in the browser using your password
  3. Encrypted data is stored in your Val Town SQLite database
  4. Only you can decrypt your chats with the correct password

Your password is never sent to the server. Encryption happens entirely in your browser.

Quick Start: Remix This Val

Step 1: Fork the Val

  1. Click the "Remix" button on Val Town (or fork this repository)
  2. This creates your own private copy of the app

Step 2: Set Up Security

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.

To set the environment variable:

  1. Go to your Val Town settings
  2. Navigate to Environment Variables
  3. Add a new variable:
    • Name: STORAGE_API_KEY
    • Value: (paste the key from console logs)
  4. Save and restart your val

Step 3: Update the Storage URL

In 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.

Step 4: Use Your App

Visit your main val's URL and start chatting! Create your first encrypted chat with a strong password.

Security Features

What's Protected

βœ… 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

Encryption Details

  • Algorithm: AES-GCM (256-bit)
  • Key Derivation: PBKDF2 with 100,000 iterations
  • Random Salt & IV: Generated for each encryption
  • Password: Never leaves your device

What's Stored in the Database

Your Val Town SQLite database stores:

  • Chat ID (random UUID)
  • Chat name (plain text)
  • Encrypted chat data (ciphertext + salt + IV)
  • Timestamps

Without your password, the encrypted data is unreadable.

Environment Variables

VariableRequiredDescription
STORAGE_API_KEYYesProtects your storage API from unauthorized access
FRONTEND_URLNoOptional CORS restriction (e.g., https://yourapp.val.run)

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Browser       β”‚
β”‚  (React App)    β”‚
β”‚                 β”‚
β”‚  β€’ WebLLM AI    β”‚
β”‚  β€’ Encryption   β”‚
β”‚  β€’ UI           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”‚ HTTPS + API Key
         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Val Town      β”‚
β”‚  Storage API    β”‚
β”‚                 β”‚
β”‚  β€’ SQLite DB    β”‚
β”‚  β€’ Auth Check   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File Structure

β”œβ”€β”€ 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

Usage Tips

Strong Passwords

Use strong, unique passwords for each chat. Since encryption happens client-side, your password is the only thing protecting your data.

Password Recovery

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.

Backup

Since this is self-hosted, you're responsible for backups. Val Town SQLite data persists, but you may want to:

  1. Export your encrypted data periodically
  2. Save your passwords securely (use a password manager)
  3. Consider backing up your Val Town val

Troubleshooting

"Unauthorized" Error

Problem: API calls return 401 Unauthorized

Solution:

  1. Check that STORAGE_API_KEY is set in environment variables
  2. Make sure the key matches in both your main val and storage val
  3. Restart both vals after setting the variable

"Wrong Password" Error

Problem: Can't unlock a chat

Solution:

  • Double-check your password (passwords are case-sensitive)
  • There is no password recovery - if you forgot it, the chat is inaccessible

Chat List Empty

Problem: No chats appear on home screen

Solution:

  1. Check browser console for errors
  2. Verify STORAGE_URL in lib/api.ts points to your storage val
  3. Ensure storage val is running and accessible

AI Model Not Loading

Problem: WebLLM status shows error

Solution:

  • WebLLM downloads models to browser (can be 1-2 GB)
  • Check your internet connection
  • Try refreshing the page
  • Check browser console for specific errors

Advanced Configuration

Change PBKDF2 Iterations

For stronger encryption, increase iterations in lib/crypto.ts (line 25):

iterations: 600000, // Increased from 100,000

Trade-off: Higher security, slower encryption/decryption.

Restrict CORS

To only allow requests from your frontend:

  1. Set FRONTEND_URL environment variable
  2. Value: https://your-main-val.val.run
  3. Restart storage val

This prevents other websites from calling your API (browser-level protection).

Use a Different AI Model

Edit hooks/useWebLLM.ts to use a different WebLLM-supported model. See WebLLM documentation for available models.

Privacy & Data

What Data is Collected

None. This app doesn't collect, track, or transmit any data beyond what's necessary for functionality:

  • Your chats are encrypted and stored in your Val Town SQLite database
  • Your password never leaves your browser
  • No analytics, no tracking, no third parties

Who Can Access Your Data

Only you. When you fork this val:

  • You own the Val Town vals
  • You control the database
  • You set the API key
  • You hold the encryption passwords

No one else (including the original author) can access your chats.

Contributing

Found a bug or want to improve the code? Feel free to:

  1. Fork this val
  2. Make your improvements
  3. Share your enhanced version!

This is open source - make it your own.

Security Considerations

While this app implements strong encryption and security practices, please note:

  • ⚠️ This is a personal project, not audited by security professionals
  • ⚠️ API keys are visible in browser DevTools (use strong, unique keys)
  • ⚠️ Val Town is a public platform - keep your vals private if needed
  • ⚠️ No rate limiting implemented (could be added if needed)

For maximum security:

  • Use strong, unique passwords
  • Set a strong STORAGE_API_KEY
  • Keep your Val Town account secure
  • Consider enabling 2FA on your Val Town account

Credits

Built with:

  • Val Town - Hosting & SQLite
  • React - UI framework
  • WebLLM - Browser-based AI
  • Web Crypto API - Encryption
  • Tailwind CSS - Styling

License

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.

Code
.claudeapicomponentshookslibscreens.vtignoreAGENTS.mdApp.tsxREADME.mddeno.json
H
main.ts
tailwind.config.jstypes.ts
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
Β© 2025 Val Town, Inc.