MCPcopy Index your code
hub / github.com/atemerev/lethe

github.com/atemerev/lethe @v0.23.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.23.5 ↗ · + Follow
2,291 symbols 6,533 edges 110 files 274 documented · 12%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Lethe

Release License Rust Swiss Made Software

Lethe is a long-running personal AI assistant with a brain-inspired cognitive architecture: cortex, hippocampus, brainstem, and a default-mode network running as cooperating actors. She has continuous memory across sessions, notices things on her own, delegates to focused subagents, and can read her own source — propose changes to it, restart herself with new logic. Lives on your machine as an isolated, rootless container (or, with --yolo, natively as a systemd/launchd service). Persists across reboots, models, hardware upgrades.

Written in Rust as a single ~50 MB static binary. Routes LLM traffic through genai. Intentionally has no web console.

Quickstart

# Download the latest release and run the setup wizard
curl -fsSL https://lethe.gg/install | bash

The installer drops a prebuilt binary at ~/.lethe/bin/lethe and hands off to lethe init, which walks you through provider, model, API key, and identity — then deploys Lethe as an isolated, rootless container (the default: Podman on Linux, Apple Container on macOS, installed for you if missing). Pass --yolo to skip the container and run natively on the host instead.

Prefer to build from source?

Linux linker note: check .cargo/config.toml first. If it points at mold, install it before building (sudo dnf install mold or sudo apt-get install mold) or adjust the linker setting for your system.

git clone https://github.com/atemerev/lethe.git
cd lethe
cargo build --release
install -m 755 target/release/lethe ~/.local/bin/lethe
lethe init            # add --yolo for a native (uncontained) setup

lethe init writes ~/.lethe/config/.env, seeds the workspace and core memory blocks, and runs a smoke test against the LLM and embedding pipeline before declaring success. It runs non-interactively when stdin isn't a terminal (Docker/CI): pass --provider/--model/--aux-model and supply the key via the provider's env var (e.g. OPENROUTER_API_KEY). If you'd rather configure by hand, copy .env.example and edit. The first turn that uses recall/notes triggers a one-time ~150MB download of the embedding runtime and model (progress is shown).

Then check on her:

lethe                 # status: version + current config (no live probes)
lethe check           # live health check (LLM + embeddings)
lethe chat -m "hello" # one-off message straight to the model

To sign in (or re-auth) a single provider without re-running the full wizard, use lethe login:

lethe login openai       # asks: ChatGPT Plus/Pro subscription (default) or API key
lethe login anthropic    # asks: Claude Pro/Max subscription (default) or API key
lethe login openrouter   # API key only
lethe login opencode-go  # API key only

Each command writes credentials to ~/.lethe/credentials/ (subscription) or sets the API key in ~/.lethe/config/.env, flips LLM_PROVIDER, and prompts for LLM_MODEL / LLM_MODEL_AUX (defaults from the curated catalog — accept with Enter, or type any other model id).

Sanity-check an existing setup any time with lethe check — it pings the model and exercises the embedding pipeline rather than just printing config.

Architecture

                 Telegram / HTTP API
                        |
                        v
              Cortex: user-facing agent
        memory, tools, delegation, final replies
                        |
       +----------------+----------------+
       |                |                |
       v                v                v
 Hippocampus       Actor System     Notification Pipeline
 recall over       subagents,       scoring, gating,
 notes/archive/    registry,        and proactive
 conversations     event bus        transport output
       |                |
       v                +----------------+
 Memory Stack                            |
 markdown blocks,                       v
 notes, SQLite-vec index,     DMN + heartbeat
 message history              background thought
                        |
                        v
                    Tool Registry
       files, shell/PTY, browser, web, Telegram/API transport

Core runtime pieces:

Area Rust modules Responsibility
Agent/cortex src/agent.rs Prompt assembly, LLM calls, tool loop, and actor turn execution.
LLM routing src/llm/ genai client, OAuth (ChatGPT Plus/Pro, Claude Pro/Max) and API-key auth, OpenRouter prompt-cache forwarding via vendored genai patch, model metadata.
Memory src/memory/ Markdown memory blocks, SQLite-vec recall tables (memory, message_history, plus their *_vec virtual siblings), SQLite todos.
Recall src/hippocampus.rs Hybrid lexical/vector recall over notes, archival memories, and conversation history.
Actors src/actor.rs, src/actor/ Resident Kameo actors, supervisor-owned state, mailbox/event routing, autonomous subagent wakeups, persistent DMN, SQLite-backed actor snapshots that survive restarts.
Notifications src/notification.rs, src/heartbeat.rs, src/runtime.rs Background candidate gating and proactive output limits.
Transports src/telegram.rs, src/api.rs, src/conversation.rs Telegram polling, HTTP/SSE API, debounce/cancel handling.
Tools src/tools/ Filesystem, shell, PTY terminal, browser, image, web, memory, notes, todos, actors, transport tools.

Build

git clone https://github.com/atemerev/lethe.git
cd lethe
cp .env.example .env
cargo build --release
target/release/lethe check

Native installer:

curl -fsSL https://lethe.gg/install | bash
~/.lethe/bin/lethe check

The installer downloads the latest GitHub binary release for the current platform when available. If no release asset matches, it falls back to a local Cargo build. Force source builds with LETHE_INSTALL_FROM_SOURCE=1.

Run tests:

cargo test
cargo build --release

The built-in browser_* tools shell out to the external agent-browser CLI (npm install -g agent-browser). When the agent-id integration's vault-sealed browser is active it takes over instead (and the built-in browser_* tools are hidden, so there's only ever one browser) — see Alien agent-id.

Running

Lethe's default home is an isolated, rootless container managed as a background service — lethe init sets that up for you. The CLI drives and inspects the whole deployment.

Deploy & manage

lethe run                      # run in the foreground here (Ctrl-C to stop); --yolo for native
lethe service install --now    # install + start the background service (systemd user unit / launchd agent)
lethe service status           # platform, unit path, live status
lethe container up             # build image (if needed), create the container, install + start the service
lethe container status         # engine, container state, shared mounts
lethe container logs -f        # follow the container logs
lethe container shell          # root shell inside the running container
lethe container up --rebuild   # rebuild the image and recreate the container
lethe container down           # stop the container
lethe uninstall                # remove the service/container (add --purge to also delete ~/.lethe)

Share extra host directories with the container via lethe container up --mount host[:container] (repeatable; persisted).

Reach her

lethe transport list                       # API + Telegram channels and their status
lethe transport api --port 1373 --token    # configure the local HTTP API (powers the TUI); --token mints a fresh one
lethe transport telegram --enable          # configure + enable the Telegram bot

Under the hood a single lethe api process hosts the HTTP/SSE transport and the Telegram poller (when TELEGRAM_BOT_TOKEN is set) in the same address space, sharing one Agent, one actor registry, and one Brainstem (the sole source of heartbeats / proactive emissions — transports just subscribe and forward). API mode binds to LETHE_API_HOST (127.0.0.1 by default) on LETHE_API_PORT (1373); use a reverse proxy for remote access.

Configure on the fly

lethe status                   # version + current config, secrets censored (this is also the bare `lethe`)
lethe identity set --name "…"  # change who she is (name + persona); `lethe identity edit` opens $EDITOR
lethe model                    # show current model + catalog; `lethe model <id>` or `--pick` to change
lethe login anthropic          # (re-)auth a single provider
lethe completions fish         # print a shell completion script

Add --config <PATH> to any command to point at a different .env. Low-level/debug subcommands (memory, fs, sh, todo, agent, …) are hidden but still work — lethe help <command>.

Terminal UI

lethe tui                                       # local API
lethe tui --url http://host:1373 --token $LETHE_API_TOKEN

Inline tool cards, an actors/todos sidebar, streaming assistant text (Anthropic + OpenAI OAuth providers), @-prefix workspace path autocomplete, and slash commands (/help, /clear, /cancel, /todos, /actors, /model, /quit).

LLM Providers

Lethe routes chat through genai. The runtime supports both API-key and subscription-OAuth auth, plus OpenAI-compatible local servers:

Provider Auth Example LLM_MODEL
Anthropic (API key) ANTHROPIC_API_KEY claude-opus-4-7
Anthropic (Claude Pro/Max) lethe login anthropic → token file claude-opus-4-7
OpenAI (API key) OPENAI_API_KEY gpt-5.5
OpenAI (ChatGPT Plus/Pro) lethe login openai → token file gpt-5.5
OpenRouter OPENROUTER_API_KEY openrouter/moonshotai/kimi-k2.6
OpenCode Go OPENCODE_GO_API_KEY opencode-go/kimi-k2.6
Local OpenAI-compatible LLM_API_BASE + OPENAI_API_KEY=local openai/gemma-4-31B-it-Q8_0.gguf

OpenCode Go is a budget-friendly gateway ($5–$10/month) to a curated set of open models. Unlike the other providers it speaks different wire protocols per model — some models expect the OpenAI API, others the Anthropic Messages API — so each catalog entry declares its protocol and the router selects the matching adapter automatically. No subscription/OAuth path; API key only.

LLM_PROVIDER is optional but useful when a model id does not carry a provider prefix — for example LLM_PROVIDER=openrouter with LLM_MODEL=moonshotai/kimi-k2.6. Subscription auth also requires LLM_PROVIDER=openai or LLM_PROVIDER=anthropic so the router picks the OAuth path instead of looking for an API key (the lethe login commands set this for you).

LLM_MODEL_AUX defaults to the main model and is used for lightweight/background calls.

Subscription OAuth

lethe login openai runs a device-code flow against auth.openai.com; tokens land in ~/.lethe/credentials/openai_oauth_tokens.json. Calls then go to the Codex Responses API at chatgpt.com/backend-api/codex/responses using your ChatGPT Plus/Pro session — no OPENAI_API_KEY needed. Override the token file with LETHE_OPENAI_OAUTH_TOKENS or supply a raw token via OPENAI_AUTH_TOKEN.

lethe login anthropic runs a PKCE browser flow against claude.ai/oauth/authorize; tokens land in ~/.lethe/credentials/anthropic_oauth_tokens.json. Override with LETHE_ANTHROPIC_OAUTH_TOKENS or ANTHROPIC_AUTH_TOKEN.

Prompt caching

Lethe stamps cache breakpoints on the system prompt (1h-TTL persistent prefix + 5min-TTL ephemeral tail) and forwards them through to:

  • Anthropic direct and Anthropic OAuth — cache_control is emitted on system blocks.
  • OpenRouter — cache_control is emitted on system content parts, which OpenRouter forwards to upstream providers that support explicit caching (Anthropic, Qwen, Gemini explicit). Providers with automatic prefix caching (OpenAI, Grok, Moonshot/Kimi, Groq, DeepSeek, Gemini implicit) ignore the field but benefit from the stable structured shape.

Both genai's native OpenAI adapter and our vendored fork now carry the patch — see vendor/genai/LETHE_FORK.md for the patch surface.

Configuration

Configuration is read from process environment, a local .env, and $LETHE_HOME/config/.env.

Variable Description Default
LETHE_MODE cli, telegram, or api cli
LETHE_HOME Runtime root ~/.lethe
LETHE_AGENT_NAME Assistant name (see lethe identity) lethe
LETHE_CONFIG_FILE Config .env path (also --config) $LETHE_HOME/config/.env
WORKSPACE_DIR Workspace directory $LETHE_HOME/workspace
MEMORY_DIR Memory data directory $LETHE_HOME/data/memory
DB_PATH SQLite todo database path $LETHE_HOME/data/lethe.db
LOGS_DIR Runtime log directory $LETHE_HOME/logs
TELEGRAM_BOT_TOKEN Bot token from BotFather required for Telegram
TELEGRAM_ALLOWED_USER_IDS Comma-separated allowlist all users
TELEGRAM_TRANSCRIPTION_ENABLED Transcribe Telegram audio/voice true
LETHE_API_TOKEN Bearer or x-lethe-token auth for API mode required for API
LETHE_API_HOST API bind address 127.0.0.1
LETHE_API_PORT API port 1373
`LLM_

Extension points exported contracts — how you extend this code

TurnObserver (Interface)
Transport-side hook called around each tool execution. Lets a transport (e.g. Telegram) keep its "typing" indicator aliv [2 …
src/tools/registry/observer.rs
PromptDialect (Interface)
Behaviour knobs the system-prompt assembler queries per turn. Currently the only differentiator we need across families [2 …
src/llm/dialect.rs
TextEmbedder (Interface)
(no doc) [2 implementers]
src/memory/semantic.rs
MessageEgress (Interface)
Abstraction over the transports that can ship a message back to the user during a tool turn. Both `TelegramToolContext` [2 …
src/tools/registry/egress.rs

Core symbols most depended-on inside this repo

is_empty
called by 481
src/scheduler/proactive.rs
get
called by 290
src/memory/db.rs
insert
called by 137
src/memory/db.rs
len
called by 130
src/actor.rs
get
called by 81
src/actor/registry.rs
string_arg
called by 58
src/tools/registry/args.rs
count
called by 58
src/memory/db.rs
execute
called by 56
src/tools/registry/dispatch.rs

Shape

Function 1,275
Method 662
Class 262
Enum 88
Interface 4

Languages

Rust100%

Modules by API surface

src/interfaces/telegram.rs165 symbols
src/llm/client.rs113 symbols
src/agent.rs91 symbols
src/interfaces/api.rs70 symbols
src/llm/openai_oauth.rs62 symbols
src/cli/container.rs51 symbols
src/todos.rs50 symbols
src/actor/runtime.rs50 symbols
src/tools/shell.rs49 symbols
src/actor/registry.rs45 symbols
src/cli/telegram_loop.rs44 symbols
src/agent/tool_loop.rs42 symbols

For agents

$ claude mcp add lethe \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact