Workspaces
How Aleph organizes per-agent state through `~/.aleph/` — configuration, sessions, memory, skills, plugins, Hub, projects, and logs.
Aleph converges all runtime state into a unified home directory tree — ~/.aleph/ (overridable via ALEPH_HOME). This page describes the current layout; legacy ~/.config/aleph/, facts.lance/, evolution.db, providers.toml conventions have all been retired.
Single-source convention: all platforms use
~/.aleph/; noXDG_CONFIG_HOMEdistinction; test / multi-instance scenarios are fully isolated viaALEPH_HOME=/path/to/root.
Directory Structure
~/.aleph/
├── config.toml # main config (see [Configuration](/docs/en/getting-started/configuration))
├── config.toml.bak # automatic pre-migration backup
├── cache/ # generic cache (safe to drop on restart)
├── memory/
│ ├── note/ # knowledge notes (Markdown + SQLite index + sqlite-vec vectors)
│ ├── raw/ # raw sources (input for note distillation)
│ └── *.db # facts tables, graph cache, insights, etc.
├── skills/ # user-level skills (Markdown skill)
├── agents/<id>/skills/ # active agent's private skills (highest priority)
├── plugins/<plugin>/skills/ # plugin-bundled skills
├── runtimes/ # capability ledger — probe, bootstrap, persist external tool state
├── hub_catalog.db # Aleph Hub cache (hub::primer cold-start population)
├── projects.json # project storage (see projects.* RPC)
├── projects.lock # project storage file lock
├── data/ # runtime databases (see below)
│ ├── aleph.lock # instance lock (flock at the entry of `aleph-server start`; OS auto-releases)
│ ├── sessions.db # session event log (SessionEvent SSOT)
│ ├── security.db # device trust, certificate fingerprints, TOFU store + encrypted secret vault
│ ├── pairing.db # pairing & invite codes
│ ├── devices.db # device ledger
│ ├── heartbeat.db # heartbeat tasks / probe history
│ └── scratchpad_bindings.json # session → active-plan pointers (preserved across daemon restart)
├── logs/ # gateway and runtime logs (tracing; daily rotation + 7-day retention)
│ ├── aleph-server.log.YYYY-MM-DD
│ └── ...
└── soul.md # global identity/personality definition (overridden by .soul/identity.md)Historical migration:
facts.lance/(legacy LanceDB vector store) → consolidated intomemory/*.db+sqlite-vec;evolution.db(legacy skill evolution DB) → consolidated intodream_*tables;providers.toml(legacy credentials file) → folded intoconfig.tomlunder[providers.*];~/.config/aleph/→ unified to~/.aleph/.
Configuration Files
config.toml
The primary configuration file controls all runtime behavior. All fields support ${VAR_NAME} environment-variable interpolation. Selected sections:
# Agent defaults (agents_def.rs)
[agents.defaults]
model = "anthropic/claude-sonnet-4"
thinking = "medium"
session_mode = "work" # chat / work / code (third axis)
exec_tier = "ask" # ask / auto / full
# Gateway (with TLS)
[gateway]
port = 18790
bind = "127.0.0.1"
require_auth = false
[gateway.tls]
# When cert/key are empty, the core auto-generates a self-signed cert;
# SANs auto-cover the host's non-loopback IPs; remote clients must use wss.
cert = "/path/to/cert.pem"
# Channels
[channels.telegram]
enabled = false
token = "${TELEGRAM_BOT_TOKEN}"
allow_from = ["+1234567890"]
[channels.discord]
enabled = false
token = "${DISCORD_BOT_TOKEN}"
# Behavior / input mode
[behavior]
input_mode = "halo" # cut / copy / halo
hotkey = "double_shift"
# Voice
[voice]
provider = "deepgram"
vocabulary_bias = ["Aleph", "sqlite-vec", ...]
[voice.streaming]
pcm_input = false # WhisperLiveKit must set true to skip FFmpeg decode
# Heartbeat
[heartbeat]
enabled = true
# See [Heartbeat Automation](/docs/en/automation/heartbeat)Credential Storage
API keys and secrets are held by the OS keychain and persisted as AES-256-GCM ciphertext in data/security.db. They are never written in plaintext to config.toml. MCP servers receive credentials through Aleph's WASM secret-injection boundary per-server at startup so a child process never inherits the daemon's raw env.
Session Storage (data/sessions.db)
The session event log is the single source of truth (session_events table); MessageProjector materialises events into the messages table, and ProjectionReconciler back-fills projections on startup. Schemas are defined in src/session/events.rs and src/session/projector.rs.
Session keys use a hierarchical format encoding agent, channel, and scope:
| Key Format | Example | Description |
|---|---|---|
agent:main:main | Shared session | Cross-channel default session |
agent:main:telegram:dm:user123 | Per-user DM | Isolated Telegram conversation |
agent:main:discord:group:guild-id | Group chat | Discord guild conversation |
agent:main:cron:daily-summary | Cron task | Scheduled task session |
agent:main:loop:<loop_id> | Loop session | GoalLoop context |
agent:main:goal:<goal_id> | Goal session | GoalStore context |
agent:main:heartbeat:<task_id> | Heartbeat | Periodic daemon session |
Memory Storage (memory/)
The memory subsystem uses a single storage backend: SQLite + sqlite-vec, plus a notes layer (memory/note/ Markdown files + SQLite index).
- Facts tables:
memory/facts*.db—notes,notes_sources,notes_provenance,notes_graph_cache,notes_graph_insights(4-signal community-aware recall + Louvain refinement) - Raw sources:
memory/raw/— distillation input; the notes layer back-fills[[wikilink]]edges from these - Graph cache / insights: written by
GraphRecomputeStageintonotes_graph_cache/notes_graph_insights(spawn_blocking, zero LLM)
LanceDB and the legacy single-file graph.db have been folded in.
Skill / Plugin Directories
Skills
Roots scanned in priority order (see Discovery):
~/.aleph/agents/<id>/skills/— active agent's private skills (highest priority)~/.aleph/skills/— user-level<project>/.aleph/skills/— project-level (native)<project>/.claude/skills/— project-level Claude Code compatible (outranked by the project.aleph/on clash)~/.aleph/plugins/<plugin>/skills/— plugin-bundled (authoritatively owned byextension_manager)
Each skill sits in its own subdirectory with a SKILL.md marker (OpenCode-compatible discovery):
~/.aleph/skills/
├── code-review/
│ └── SKILL.md
└── git-commit/
└── SKILL.mdPlugins
~/.aleph/plugins/
├── my-plugin/
│ ├── aleph.plugin.toml # V2 preferred manifest
│ ├── package.json # (Node.js plugins)
│ ├── dist/
│ │ └── index.js
│ └── src/
│ └── index.ts
└── wasm-tool/
├── aleph.plugin.toml
└── plugin.wasmA file watcher (notify-debouncer-full) triggers extension-system hot-reload ~600 ms after a change. reload is serialised under the load guard (the prior concurrent-reload race is fixed).
Hub Cache (hub/)
src/hub/primer.rs projects official MCP presets, official plugins, and the official skill collection into hub_catalog.db on startup. Each entry is merged and tagged with via {source}; a background hub_catalog_sync task pulls incremental updates from Aleph Hub. See Extensions Store.
Project Storage
projects.json + projects.lock holds project metadata; RPC entry points are projects.list / projects.add / projects.create_blank / projects.remove / projects.touch / projects.get. The lock prevents concurrent corruption.
Workspace Storage
Workspaces are the user-facing "multiple workspaces side-by-side" abstraction — switching workspace swaps default channel / persona / agent bindings. RPC entry points:
workspace.create/workspace.list/workspace.get/workspace.update/workspace.archivechannels.set_agent— bind a channel to a specific agent (now requires the agent to exist; the prior version that accepted non-existent agents was fixed)agents.bindings— query current agent ↔ channel bindings
Backed by the SQLite AgentEnvStore (not by ~/.aleph/projects.json); defined in src/gateway/agent_env.rs.
Identity and Soul Files
Aleph uses a layered identity system where soul definitions can be specified at multiple levels:
Priority (highest to lowest):
┌─────────────┐
│ Session │ ← Runtime override via RPC
├─────────────┤
│ Project │ ← .soul/identity.md in the project directory
├─────────────┤
│ Global │ ← ~/.aleph/soul.md
├─────────────┤
│ Default │ ← Built-in empty manifest
└─────────────┘The global soul.md defines the default personality; delegated-role chains and signer ownership are anchored by device/key records in data/security.db.
Log Files
Runtime logs live in logs/:
aleph-server.log.YYYY-MM-DD—tracingstructured logs, rotated daily with 7-day retention
Aleph uses the tracing crate with structured logging. Log levels can be configured via the RUST_LOG environment variable. The ALEPH-BOOT marker is emitted on the raw stdout/stderr stream (not on the structured log stream) to delimit each boot for operators (see Daemon).
Hot Reload
Configuration changes are detected automatically via file watching (500 ms debounce):
~/.aleph/config.toml modified
│
▼
Debounce (500ms) → parse new config → schema validation
│
▼
Apply changes:
• Restart affected interfaces
• Update routing rules (routing_rules.*)
• Hot-update [execution] max_runs_global / max_runs_per_agent
• Emit config.changed eventNewly hot-reloadable fields include project storage, Hub sync TTL, and the [voice] vocabulary bias list (selected sections only).
Multi-Agent / Cluster Workspaces
In cluster federation (see Cluster), the center owns the full ~/.aleph/; nodes carry only controlled subsets (per [cluster.node].sync_paths). Node keys are Unicode-normalized, so CJK node names work correctly (the prior byte-slicing behaviour broke them).
Related Pages
- Configuration —
config.tomlfull field reference - Agent Runtime — How the agent uses workspace state
- Messages — Session storage and message persistence
- Extensions — Plugin layout and discovery
- Discovery — Scan strategy and on-demand MCP / tool discovery
- Daemon — Log rotation and the
ALEPH-BOOTmarker - Architecture Overview — System-level view of the storage layer
- Gateway RPC
workspace.*— Full RPC - Gateway RPC
projects.*— Project store - Cluster — Node-key normalization