Aleph
Concepts

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/; no XDG_CONFIG_HOME distinction; test / multi-instance scenarios are fully isolated via ALEPH_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 into memory/*.db + sqlite-vec; evolution.db (legacy skill evolution DB) → consolidated into dream_* tables; providers.toml (legacy credentials file) → folded into config.toml under [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 FormatExampleDescription
agent:main:mainShared sessionCross-channel default session
agent:main:telegram:dm:user123Per-user DMIsolated Telegram conversation
agent:main:discord:group:guild-idGroup chatDiscord guild conversation
agent:main:cron:daily-summaryCron taskScheduled task session
agent:main:loop:<loop_id>Loop sessionGoalLoop context
agent:main:goal:<goal_id>Goal sessionGoalStore context
agent:main:heartbeat:<task_id>HeartbeatPeriodic 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*.dbnotes, 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 GraphRecomputeStage into notes_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):

  1. ~/.aleph/agents/<id>/skills/active agent's private skills (highest priority)
  2. ~/.aleph/skills/ — user-level
  3. <project>/.aleph/skills/ — project-level (native)
  4. <project>/.claude/skills/ — project-level Claude Code compatible (outranked by the project .aleph/ on clash)
  5. ~/.aleph/plugins/<plugin>/skills/ — plugin-bundled (authoritatively owned by extension_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.md

Plugins

~/.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.wasm

A 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.archive
  • channels.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-DDtracing structured 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 event

Newly 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).

On this page