Storage
Where CoreLayer keeps state, and how to switch between SQLite, Supabase, and PostgreSQL.
CoreLayer stores state locally by default and can run against Supabase or a self-hosted PostgreSQL instead. Storage mode is chosen at startup, not per request.
Storage modes
| Mode | Value | Description |
|---|---|---|
| SQLite | local (default) | Zero-config local file database |
| Supabase | cloud | Cloud PostgreSQL with your own project |
| PostgreSQL | postgres | Self-hosted PostgreSQL |
The mode lives in its own file, config.json's sibling storage.json in the config zone:
{
"storageMode": "local",
"dbConfig": {
"supabaseUrl": "https://your-project.supabase.co",
"supabaseServiceKey": "…",
"postgresUrl": "postgresql://user:pass@host:5432/corelayer"
}
}dbConfig is only required for the cloud and postgres modes. DATABASE_URL in the environment is also honored for PostgreSQL.
Switching is done from Settings → Storage, which writes this file. A daemon restart picks up the new mode; this is not a live hot-swap.
Disk layout
Local state is split into six zones under the CoreLayer home directory (JARVIS_HOME overrides it; the desktop default is ~/.jarvis):
~/.jarvis/
├── config/ config.json · routing.json (no secrets)
├── security/ credentials.json (0600 on POSIX)
├── memory/ USER.md · MEMORY.md · journal/ · dreams/
├── storage/ jarvis.db
├── worktrees/ active/ · snapshots/
└── cache/ symbol-graph/ · mcp-schemas/ · delegation-pipes/Credentials are read from security/credentials.json; a legacy config/credentials.json is still honored when the new location does not exist.
In sidecar mode the shell can override the root through JARVIS_APP_DATA_DIR, JARVIS_LOG_DIR, and SQLITE_DB_PATH.
Known exceptions
Two files still resolve from legacy locations rather than the six-zone layout:
mcp-servers.jsonis read from~/.jarvis/config/mcp-servers.json- the SQLite database path follows the app-paths resolution (
data/jarvis.dbunlessSQLITE_DB_PATHis set)
Both are documented here as exceptions rather than silently described as part of the new layout.
Schema
The database is managed with Drizzle migrations.
| Group | Tables |
|---|---|
| Work structure | workspaces, workspace_agents, projects, agent_profiles, tasks, artifacts, goals, plans |
| Execution | agent_runs, agent_run_events, executor_runs, execution_logs, environment_sessions, environment_events |
| Governance | approval_requests, permission_memories, capability_grants, pending_actions, tool_call_logs, audit_log, event_log |
| Conversation | conversations, messages |
| Knowledge | memories, articles, reviews |
| Configuration | app_connections, model_profiles, scheduled_tasks |
| Channels | channel_accounts, channel_conversations, channel_messages |
Choosing a backend
- SQLite — one machine, offline, fastest queries. Default.
- Supabase — several devices, and you want managed backups; you own the project and its policies.
- PostgreSQL — you already operate a database and do not want a third-party control plane.
There is no background replication between backends: switching modes means the daemon reads and writes the backend you selected.
Next Steps
- Security Model — what is sensitive and where
- Config File — the configuration reference
- Permissions — policy configuration