{ config, lib, pkgs, ... }: # Pi, a terminal coding agent, for the primary user, configured through # home-manager, which ships the package and manages global settings. # The login credential is left unmanaged, so it survives rebuilds. let user = config.user.name; # NOLINT(let_order) piDir = "${config.users.users.${user}.home}/.pi/agent"; in { options.modules.shell.pi = { enable = lib.mkEnableOption "Pi, a terminal coding agent, configured through home-manager"; }; config = lib.mkIf config.modules.shell.pi.enable { home-manager.users.${user} = { programs.pi-coding-agent = { enable = true; package = pkgs.buildNpmPackage { pname = "pi-coding-agent"; version = "0.85.1"; src = ../../../../../third_party/pi; npmDepsHash = "sha256-jzlsZIQzfl1FCZZ5//dHFWwMfBZQ4nRD6KB4HHifPqE="; npmWorkspace = "packages/coding-agent"; npmRebuildFlags = [ "--ignore-scripts" ]; dontNpmPrune = true; preConfigure = '' mkdir -p packages/ai/src/providers/data tar --extract --gzip \ --file=${ pkgs.fetchurl { url = "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.85.1.tgz"; hash = "sha256-r30RmGF5RFzm/oizfVfeIvgjwP/TplyuMcVVt/XpklM="; } } \ --directory=packages/ai/src/providers/data \ --strip-components=4 \ package/dist/providers/data ''; buildPhase = '' runHook preBuild npm run build:offline runHook postBuild ''; preInstall = '' npm prune --omit=dev --no-save ''; postInstall = '' local nm="$out/lib/node_modules/pi-monorepo/node_modules" for ws in @earendil-works/chord:packages/chord \ @earendil-works/pi-ai:packages/ai \ @earendil-works/pi-agent-core:packages/agent \ @earendil-works/pi-client:packages/client \ @earendil-works/pi-protocol:packages/protocol \ @earendil-works/pi-telemetry:packages/telemetry \ @earendil-works/pi-tui:packages/tui; do IFS=: read -r pkg src <<< "$ws" rm "$nm/$pkg" cp -r "$src" "$nm/$pkg" done find "$nm" -type l -lname '*/packages/*' -delete find "$nm/.bin" -xtype l -delete ''; nativeBuildInputs = [ pkgs.makeBinaryWrapper ]; postFixup = '' wrapProgram "$out/bin/pi" --prefix PATH : ${ lib.makeBinPath [ pkgs.ripgrep pkgs.fd ] } \ --set-default PI_SKIP_VERSION_CHECK 1 \ --set-default PI_TELEMETRY 0 ''; doInstallCheck = true; nativeInstallCheckInputs = [ pkgs.writableTmpDirAsHomeHook pkgs.versionCheckHook ]; versionCheckKeepEnvironment = [ "HOME" ]; versionCheckProgram = "${placeholder "out"}/bin/pi"; versionCheckProgramArg = "--version"; }; settings = { defaultProvider = "openai-codex"; defaultModel = "gpt-5.6-terra"; defaultThinkingLevel = "medium"; theme = "dark"; enableInstallTelemetry = false; enableAnalytics = false; terminal.clearOnShrink = true; }; }; home.file = { # The first declarative rollout replaces the interactive settings file. # Login state stays in auth.json, which this module does not manage. "${piDir}/settings.json".force = true; }; }; }; }