Expose a NixOS module from the flake #48

Closed
opened 2026-07-06 20:00:36 +08:00 by weiwen · 0 comments
Owner

Problem

The flake currently exposes packages.default (the evie binary), packages.sandcastleImage, apps, and dev shells — but no nixosModules. Deploying evie on a NixOS host today means hand-rolling a systemd service, threading the config TOML in manually, and wiring secrets (telegram.bot_token, http.api_key) by hand. There's no declarative, reusable deployment surface.

Proposal

Add nixosModules.default (and re-export via a top-level nixosModules output, since eachDefaultSystem only covers per-system outputs) providing a services.evie module that:

  • installs the evie package and runs it as a systemd service with a dedicated system user;
  • exposes the config surface (src/config.rs) as typed NixOS options — telegram (enabled, bot_token, allowedChatIds), http (enabled, host, port, apiKey), pi (binaryPath, provider, model, systemPrompt, responseIdleTimeoutSecs, sessionDir, extensions, skills), notes.directory, session.idleTimeoutSecs, debug.exposeErrors, silverbullet.baseUrl, and schedule (list of { cron, prompt });
  • generates the TOML config from the options (or accepts a configFile path passthrough) and points evie's --config at it;
  • supports secret handling that keeps bot_token/api_key out of the Nix store (e.g. *File options / LoadCredential / EnvironmentFile), rather than inlining them into world-readable store paths;
  • applies sensible systemd hardening (DynamicUser or a dedicated user, StateDirectory for session_dir, restricted filesystem access).

Open questions

  • Full typed options vs. a thin settings attrset (freeform, serialized to TOML)? A settings-style freeform option tracks the Rust config with less churn.
  • Secret injection mechanism: LoadCredential vs. EnvironmentFile vs. agenix/sops — evie currently reads secrets straight from the TOML, so runtime substitution may need a small change in config.rs.
  • Whether pi and its runtime deps (claude-code, etc.) should be wired into the service PATH the way postInstall wraps the binary today.

Note the pi binary is already wrapped onto the package's PATH via postInstall, so a service using packages.default inherits that.

## Problem The flake currently exposes `packages.default` (the `evie` binary), `packages.sandcastleImage`, `apps`, and dev shells — but no `nixosModules`. Deploying evie on a NixOS host today means hand-rolling a systemd service, threading the config TOML in manually, and wiring secrets (`telegram.bot_token`, `http.api_key`) by hand. There's no declarative, reusable deployment surface. ## Proposal Add `nixosModules.default` (and re-export via a top-level `nixosModules` output, since `eachDefaultSystem` only covers per-system outputs) providing a `services.evie` module that: - installs the `evie` package and runs it as a systemd service with a dedicated system user; - exposes the config surface (`src/config.rs`) as typed NixOS options — `telegram` (`enabled`, `bot_token`, `allowedChatIds`), `http` (`enabled`, `host`, `port`, `apiKey`), `pi` (`binaryPath`, `provider`, `model`, `systemPrompt`, `responseIdleTimeoutSecs`, `sessionDir`, `extensions`, `skills`), `notes.directory`, `session.idleTimeoutSecs`, `debug.exposeErrors`, `silverbullet.baseUrl`, and `schedule` (list of `{ cron, prompt }`); - generates the TOML config from the options (or accepts a `configFile` path passthrough) and points evie's `--config` at it; - supports secret handling that keeps `bot_token`/`api_key` out of the Nix store (e.g. `*File` options / `LoadCredential` / `EnvironmentFile`), rather than inlining them into world-readable store paths; - applies sensible systemd hardening (`DynamicUser` or a dedicated user, `StateDirectory` for `session_dir`, restricted filesystem access). ## Open questions - Full typed options vs. a thin `settings` attrset (freeform, serialized to TOML)? A `settings`-style freeform option tracks the Rust config with less churn. - Secret injection mechanism: `LoadCredential` vs. `EnvironmentFile` vs. agenix/sops — evie currently reads secrets straight from the TOML, so runtime substitution may need a small change in `config.rs`. - Whether `pi` and its runtime deps (claude-code, etc.) should be wired into the service `PATH` the way `postInstall` wraps the binary today. Note the `pi` binary is already wrapped onto the package's PATH via `postInstall`, so a service using `packages.default` inherits that.
weiwen 2026-07-06 21:34:30 +08:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie#48
No description provided.