Как я настраивал OpenClaw на NixOS

от автора

Введение

Каждый новый диалог с ассистентом — чистый лист. Он не помнит, о чём мы общались в предыдущих сессиях. Меня это не устраивало. Я начал искать решение и остановился на 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/