Введение
Каждый новый диалог с ассистентом — чистый лист. Он не помнит, о чём мы общались в предыдущих сессиях. Меня это не устраивало. Я начал искать решение и остановился на OpenClaw: декларативная конфигурация, долгосрочная память через QMD, Telegram-бот, GLM-4.7-flash — и всё это воспроизводится на любой машине одной командой.
Архитектура

Есть OpenClaw Gateway. К нему привязаны Telegram (канал связи), Workspace (файлы, определяющие личность ассистента), LLM (модель, генерирующая ответы) и QMD (долгосрочная память на векторном поиске). Всё это описывается в Nix.
До NixOS я сидел на Arch. Там обновления регулярно ломали систему: версии пакетов разъезжались, зависимости не сходились. А ещё приходилось вручную разбираться с откатами. На NixOS можно настроить и забыть. Если что-то пошло не так, откатился к коммиту или запустил предыдущее поколение.
Разбор flake.nix
{ description = "NixOS configuration with Hyprland"; inputs = { nixpkgs.url = "nixpkgs"; home-manager.url = "github:nix-community/home-manager"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; agenix.url = "github:ryantm/agenix"; agenix.inputs.nixpkgs.follows = "nixpkgs"; nix-openclaw.url = "github:openclaw/nix-openclaw"; openclaw-workspace = { url = "path:/home/vokrob/.config/openclaw"; flake = false; }; }; outputs = { self, nixpkgs, home-manager, agenix, nix-openclaw, openclaw-workspace, ... }@inputs: { nixosConfigurations.vokrob = nixpkgs.lib.nixosSystem { specialArgs = { inherit nix-openclaw openclaw-workspace; }; system = "x86_64-linux"; modules = [ home-manager.nixosModules.home-manager agenix.nixosModules.default ./hosts/nixos ]; }; };}
-
nix-openclaw: flake из
github:openclaw/nix-openclaw. Тащит модули Home Manager, overlay для пакетов и бинарный кэш наcache.garnix.io. Garnix полезен тем, что сборка OpenClaw не пересобирает зависимости с нуля; -
openclaw-workspace: просто путь, не flake. Там директория с файлами, которые определяют, как ассистент себя ведёт;
-
specialArgs: штука, которая протаскивает внешние инпуты в модульную систему Nix. Без неё модули не увидят
openclaw-workspace.
Хост у меня один, но если бы я добавлял сервер или ноутбук, конфигурация осталась бы той же.
Модульная архитектура
Конфигурация разбита на два уровня.
Системные модули
Лежат в modules/nixos/default.nix. Там base.nix (загрузчик, ядро), networking.nix (NetworkManager), services.nix (у меня Hyprland и AmneziaWG), security.nix (выключил пароль на отключение питания через Polkit) и users.nix (vokrob, agenix, zsh).
В base.nix я подключаю overlay:
nixpkgs.overlays = [ nix-openclaw.overlays.default (import ../../overlays)];
Overlay добавляет пакеты OpenClaw в pkgs, в том числе openclaw-gateway.
Пользовательские модули
Подключаются через modules/home/default.nix. Главное: features/openclaw.nix.
Плюс в hosts/nixos/default.nix я добавил:
home-manager.sharedModules = [nix-openclaw.homeManagerModules.openclaw];
sharedModules делает модуль OpenClaw доступным во всех конфигурациях Home Manager. Если появится второй хост, модуль уже будет там.
Разбор openclaw.nix
Основная конфигурация описана в modules/home/features/openclaw.nix.
Workspace
programs.openclaw.workspace.bootstrapFiles = { agents = "${openclaw-workspace}/AGENTS.md"; soul = "${openclaw-workspace}/SOUL.md"; tools = "${openclaw-workspace}/TOOLS.md"; identity = "${openclaw-workspace}/IDENTITY.md"; user = "${openclaw-workspace}/USER.md";};
Эти пять файлов формируют личность ассистента: AGENTS.md задаёт роли агентов и маршрутизацию, SOUL.md — базовую инструкцию, TOOLS.md описывает инструменты, IDENTITY.md — стиль общения, USER.md — мои данные.
Файлы находятся в ~/.config/openclaw/, и менять их можно без пересборки системы. Достаточно поправить SOUL.md, и ассистент начнёт вести себя иначе.
Секреты
programs.openclaw.environment = { ZHIPU_API_KEY = "/run/agenix/openclaw-zhipu-key"; OPENCLAW_GATEWAY_TOKEN = "/run/agenix/openclaw-gateway-token";};
Значения — это не сами ключи, а пути к файлам. OpenClaw читает секреты из файлов. Nix подставляет пути на этапе сборки, а agenix расшифровывает секреты при активации конфигурации и кладёт их в /run/agenix/. В /nix/store/ они никогда не попадают.
Токен для Telegram передаётся отдельно:
channels.telegram.tokenFile = "/run/agenix/openclaw-telegram-token";
Интеграции
config = { gateway.mode = "local"; channels.telegram = { tokenFile = "/run/agenix/openclaw-telegram-token"; allowFrom = [5748618304]; };};
Режим local означает, что gateway работает без привязки к OpenClaw Cloud. Всё на моей машине. Gateway слушает локальный порт и авторизует запросы через токен из /run/agenix/openclaw-gateway-token. К Telegram-боту доступ есть только у меня (список allowFrom).
GLM-4.7-flash
models.providers.openai = { baseUrl = "https://open.bigmodel.cn/api/paas/v4"; apiKey = { source = "env"; provider = "default"; id = "ZHIPU_API_KEY"; }; models = [{ name = "glm-4.7-flash"; id = "glm-4.7-flash"; api = "openai-completions"; contextWindow = 200000; }];};
Провайдер называется openai, но baseUrl ведёт на Z.ai. Z.ai даёт OpenAI-совместимый эндпоинт. Через api = "openai-completions" OpenClaw использует стандартный OpenAI SDK. Модель glm-4.7-flash бесплатная, с контекстным окном 200K токенов.
QMD — долгосрочная память
memory.backend = "qmd";
QMD — сайдкар на базе Qdrant, не требующий отдельного сервера.
Каждое сообщение и ответ векторизуются, эмбеддинги попадают в QMD с метаданными. Когда я пишу что-то новое, семантический поиск цепляет фрагменты из прошлого и подмешивает их в промпт. Ассистент помнит, о чём мы общались в предыдущих сессиях.
Проверил — запоминает:

Команды “запомни” и “забудь” работают через MEMORY.md. QMD просто добавляет сверху семантический поиск по всей истории.
Повышенные привилегии
tools.elevated = { enabled = true; allowFrom = { telegram = [5748618304]; };};
Эта секция даёт доступ к опасным инструментам через Telegram-бота: выполнение команд на хосте, установка пакетов, управление процессами.
Дополнительные опции
agents.defaults = { model.primary = "openai/glm-4.7-flash"; thinkingDefault = "low"; compaction.reserveTokensFloor = 20000;};reloadScript.enable = true;bundledPlugins = { summarize.enable = true;};
-
thinkingDefault: глубина рассуждений. Поставилlow, бытовым командам размышления ни к чему; -
compaction.reserveTokensFloor: резервирует 20K токенов под память и системный промпт. Когда не резервировал, контекст съедался, и ассистент начинал тупить; -
reloadScript: генерирует скрипт перезагрузки конфигурации без перезапуска gateway; -
bundledPlugins.summarize: сам суммаризирует URL и PDF, которые отправляешь в чат.
Gateway работает как systemd user service: стартует, когда я захожу в систему, и перезапускается, если падает. Логи смотрю через journalctl --user -u openclaw-gateway -f. Если что-то пошло не так, выполняю systemctl --user restart openclaw-gateway.

Секреты
В secrets/ три зашифрованных файла:
-
openclaw-telegram-token.age; -
openclaw-zhipu-key.age; -
openclaw-gateway-token.age.
В конфиге это выглядит так:
age.secrets = { "openclaw-telegram-token" = { file = ../../secrets/openclaw-telegram-token.age; owner = "vokrob"; group = "users"; mode = "0400"; };};
Agenix шифрует файлы с помощью age. Ключ лежит локально в ~/.config/agenix/age-key.txt. Расшифровка происходит только при активации системы. В /nix/store/ секреты никогда не попадают, их нельзя случайно закоммитить или засветить в бинарном кэше. Даже если кто-то получит доступ к store, API-ключи он не увидит.
Жизненный цикл сообщения
Я пишу сообщение Telegram-боту. Telegram-бот отправляет его на gateway. Gateway сначала проверяет allowFrom, если я в списке — идём дальше. Потом gateway лезет в QMD за контекстом из прошлых разговоров. Формирует промпт: системные инструкции + контекст из памяти + моё сообщение. Отправляет это в GLM-4.7-flash. Ответ модели gateway сохраняет как новый фрагмент памяти и шлёт обратно в Telegram.
Цепочка занимает от пары секунд до нескольких минут из-за очереди к бесплатной модели.
Проблемы
Сервис не стартует
Первое, с чем я столкнулся: не запускался gateway. Причина: agenix не применил скрипт активации. Решается через sudo nixos-rebuild switch, после чего проверяем /run/agenix/:
ls -la /run/agenix/
Если файлов нет, значит ошибка в определениях age.secrets. У меня было: я забыл указать owner и mode, и agenix не создал файлы.
Telegram-бот не отвечает
Тут два варианта: либо allowFrom не тот, либо токен невалидный. Telegram ID можно узнать через @userinfobot. Я ошибся: вбил ID чата вместо ID пользователя.
Проверить токен:
journalctl --user -u openclaw-gateway | grep -i telegram
QMD не возвращает контекст
Сразу после установки QMD пустой, и ассистент отвечает как будто без памяти. Это нормально. Эмбеддинги накапливаются по мере общения. Надо просто продолжать разговаривать.
Токен gateway не совпадает
Бывает, если пересоздать токен, а gateway об этом не знает:
agenix -e secrets/openclaw-gateway-token.agesystemctl --user restart openclaw-gateway
Что в итоге
Ушёл вечер, но оно того стоило. Теперь у меня воспроизводимый AI-ассистент, который помнит, о чём мы общались, и разворачивается одной командой. Конфигурация идентична на любой машине: склонировал репозиторий, запустил nixos-rebuild и готово.
Код на GitHub. Замените секреты на свои и собирайте.
ссылка на оригинал статьи https://habr.com/ru/articles/1062434/