Storage
AI Supreme Council stores all data locally in your browser. Nothing is uploaded to any server. The storage system uses two tiers -- localStorage for small, synchronous reads needed at boot, and IndexedDB for large, asynchronous data like bot profiles and chat histories.
Two-Tier Storage Architecture
| Tier | API | Capacity | Use Case |
|---|---|---|---|
| localStorage | Synchronous | ~5-10 MB | Theme, API keys, settings -- data needed instantly at page load |
| IndexedDB | Asynchronous | ~100 MB - 1 GB+ | Bot profiles, chat histories, addon manifests -- large data |
The split exists because localStorage is fast but limited in size, while IndexedDB is virtually unlimited but requires async access. Critical boot-time values (theme, API keys, login state) live in localStorage so the app can render immediately without waiting for async reads.
localStorage Keys
All localStorage keys use the ais- prefix:
| Key | Type | Description |
|---|---|---|
ais-theme | string | Current theme (light, dark, or system) |
ais-apikey-anthropic | string | Anthropic API key |
ais-apikey-openai | string | OpenAI API key |
ais-apikey-xai | string | xAI API key |
ais-apikey-gemini | string | Google Gemini API key |
ais-apikey-openrouter | string | OpenRouter API key |
ais-apikey-deepseek | string | DeepSeek API key |
ais-apikey-groq | string | Groq API key |
ais-apikey-mistral | string | Mistral API key |
ais-user | JSON | Logged-in user info (name, email, picture, provider) |
ais-idb-migrated | string | Flag indicating localStorage-to-IndexedDB migration complete |
ais-ollama-endpoint | string | Custom Ollama endpoint URL (default: http://localhost:11434) |
ais-custom-providers | JSON | Array of user-defined custom provider configurations |
aiscouncil-settings | JSON | Global settings (theme, font size, capabilities, etc.) |
aiscouncil-usage | JSON | Usage tracking data (tokens, costs per provider) |
API keys in localStorage are accessible to any JavaScript running on the same origin. This is standard for browser apps, but means you should not install untrusted browser extensions. Keys are never included in URL exports or data backups.
IndexedDB Keys
IndexedDB stores data in a key-value object store within a database named ais-db (or a per-user database when logged in):
| Key Pattern | Type | Description |
|---|---|---|
ais-bots | array | All bot session metadata (ID, name, config, creation date) |
ais-profiles | array | All saved profiles (individual and council) |
ais-chat-{botId} | array | Chat message history for a specific bot session |
ais-addon-manifests | array | Installed addon/plugin manifests |
ais-miniprogram-* | varies | Installed mini-program data |
Each bot session has its own chat key (ais-chat-abc123), so chat histories are isolated and can be loaded independently.
Auto-Migration
On first boot, AIS.Storage.init() checks whether data exists in localStorage from an older version and automatically migrates it to IndexedDB. The ais-idb-migrated flag prevents re-migration on subsequent loads.
If IndexedDB is unavailable (some privacy browsers block it), the storage layer falls back to localStorage transparently. The app continues to work, but with the ~5-10 MB storage limit.
Optional SQLite WASM Layer
For advanced use cases involving large binary data (images, attachments), the storage system can load an optional SQLite WASM module. SQLite runs concurrently with IndexedDB and stores data in the browser's Origin Private File System (OPFS).
SQLite is loaded on demand -- it is never loaded unless explicitly requested or needed for blob storage. To enable it, go to Settings > General > Storage Backend and select SQLite.
| Feature | IndexedDB | SQLite WASM |
|---|---|---|
| Key-value storage | Yes | Yes |
| Binary blob storage | Limited | Optimized |
| SQL queries | No | Yes |
| Persistence | Browser-managed | OPFS (file-based) |
| Loading | Immediate | Lazy (on first use) |
AIS.Storage API
The AIS.Storage module provides a unified API that works regardless of the active backend:
Core Operations
// Initialize storage (called once at boot)
await AIS.Storage.init();
// Get a value
const bots = await AIS.Storage.get('ais-bots');
// Set a value
await AIS.Storage.set('ais-bots', updatedBots);
// Delete a key
await AIS.Storage.delete('ais-chat-abc123');
// List all keys
const allKeys = await AIS.Storage.keys();
// Get all key-value pairs
const everything = await AIS.Storage.getAll();
// Clear all data
await AIS.Storage.clear();
Blob Storage (SQLite)
// Store a binary blob
await AIS.Storage.putBlob('image-001', arrayBuffer, 'image/png');
// Retrieve a blob
const blob = await AIS.Storage.getBlob('image-001');
// { data: Uint8Array, mime: 'image/png', size: 12345 }
Utility Functions
// Synchronous localStorage helpers (for boot-time reads)
const theme = AIS.Storage.loadJSON('ais-theme');
AIS.Storage.saveJSON('ais-theme', 'dark');
// TTL cache factory (for registry caching)
const cache = AIS.Storage.cache('ais-models-cache', 'ais-models-ts', 86400000); // 24h TTL
const data = cache.load(); // Read cached data
cache.save(newData); // Update cache
const stale = cache.isStale(); // Check if cache expired
Status Properties
AIS.Storage.isIDB; // true if IndexedDB is active
AIS.Storage.hasSQLite; // true if SQLite WASM is loaded
Export and Import
Exporting Data
Go to Settings > Privacy > Export All Data or use the API:
const backup = await AIS.Storage.exportData();
// Returns: { bcz_version: "1.0.0", exported: "2026-02-19T...", data: {...} }
The export includes all bot profiles, chat histories, settings, and addon manifests. It explicitly excludes:
- API keys (never exported)
- Per-member API keys in profiles (stripped to just provider/model)
The export is saved as ais-backup-YYYY-MM-DD.json.
If you have SQLite blob storage active, the export also generates a separate ais-blobs-YYYY-MM-DD.db file containing the SQLite database.
Importing Data
Go to Settings > Privacy > Import Data or use the API:
const count = await AIS.Storage.importData(jsonBackup);
// Returns: number of items imported
Import accepts:
.jsonfiles (standard backup format).dbfiles (SQLite database)
API keys are never imported even if present in the file.
Storage Quotas
Browser storage quotas vary by platform:
| Browser | IndexedDB Quota | With Persistent Storage |
|---|---|---|
| Chrome/Edge | ~60% of disk space | Same, but not evicted |
| Firefox | ~50% of disk space | Prompts user for permission |
| Safari | ~1 GB initial, user can grant more | Same |
AI Supreme Council requests persistent storage on init via navigator.storage.persist(). When granted, the browser will not automatically evict your data when storage is low.
Open your browser's DevTools, go to Application > Storage, and look for the origin aiscouncil.com to see current storage usage and quota.
Privacy
All data stays on your device:
- No server uploads -- bot configs, chat histories, and settings are never sent to any server
- No analytics -- no usage data is transmitted anywhere
- No cookies -- the app uses
localStorageand IndexedDB, not tracking cookies (theais-authcookie is used only for cross-subdomain auth detection) - No third-party storage -- data is stored only under the
aiscouncil.comorigin
Clearing Data
To clear all stored data:
- Settings > Privacy > Clear All Data -- removes all IndexedDB data, profiles, and chat histories
- Browser DevTools > Application > Clear Storage -- nuclear option, removes everything including localStorage
- Individual chat deletion -- right-click a bot in the sidebar and select Delete
Clearing all data is irreversible. Export your data first if you want a backup. API keys stored in localStorage are also removed when clearing via browser DevTools.
Per-Bot Storage for Mini-Programs
Each installed mini-program gets its own isolated storage namespace. Mini-programs access storage through the ais.storage SDK API, which maps to per-app prefixed keys in IndexedDB. One mini-program cannot access another's data.
// Inside a mini-program
await ais.storage.set('my-key', 'my-value');
const val = await ais.storage.get('my-key');
const keys = await ais.storage.keys();
await ais.storage.remove('my-key');
Storage for a mini-program is deleted when the mini-program is uninstalled.